From 3c1647f72f2905421af3e914fca58e8c4d8b674a Mon Sep 17 00:00:00 2001 From: Ludvig Strigeus Date: Sun, 21 Oct 2018 16:00:15 +0200 Subject: [PATCH] Split out ipaddr stuff into a separate file --- TunSafe.vcxproj | 2 + TunSafe.vcxproj.filters | 6 + netapi.h | 14 +- network_win32.h | 1 + tunsafe_amalgam.cpp | 1 + tunsafe_dnsresolve.h | 41 +++++ tunsafe_ipaddr.cpp | 380 ++++++++++++++++++++++++++++++++++++++++ tunsafe_ipaddr.h | 40 +++++ wireguard_config.cpp | 324 +--------------------------------- wireguard_config.h | 45 +---- 10 files changed, 476 insertions(+), 378 deletions(-) create mode 100644 tunsafe_dnsresolve.h create mode 100644 tunsafe_ipaddr.cpp create mode 100644 tunsafe_ipaddr.h diff --git a/TunSafe.vcxproj b/TunSafe.vcxproj index 48c8261..94651a4 100644 --- a/TunSafe.vcxproj +++ b/TunSafe.vcxproj @@ -202,6 +202,7 @@ + @@ -221,6 +222,7 @@ + diff --git a/TunSafe.vcxproj.filters b/TunSafe.vcxproj.filters index 71677f1..a035bde 100644 --- a/TunSafe.vcxproj.filters +++ b/TunSafe.vcxproj.filters @@ -120,6 +120,9 @@ crypto\chacha20poly1305 + + Source Files + @@ -185,6 +188,9 @@ crypto\chacha20poly1305 + + Source Files + diff --git a/netapi.h b/netapi.h index 9a33cdf..ca187ce 100644 --- a/netapi.h +++ b/netapi.h @@ -3,9 +3,8 @@ #ifndef TINYVPN_NETAPI_H_ #define TINYVPN_NETAPI_H_ -#include "stdafx.h" #include "tunsafe_types.h" - +#include "tunsafe_ipaddr.h" #include #include @@ -18,17 +17,6 @@ #pragma warning (disable: 4200) -union IpAddr { - sockaddr_in sin; - sockaddr_in6 sin6; -}; - -struct WgCidrAddr { - uint8 addr[16]; - uint8 size; - uint8 cidr; -}; - struct Packet { union { Packet *next; diff --git a/network_win32.h b/network_win32.h index bcd8adf..10532a4 100644 --- a/network_win32.h +++ b/network_win32.h @@ -9,6 +9,7 @@ #include "network_win32_dnsblock.h" #include "wireguard_config.h" #include "tunsafe_threading.h" +#include "tunsafe_dnsresolve.h" #include enum { diff --git a/tunsafe_amalgam.cpp b/tunsafe_amalgam.cpp index 19108eb..664e79a 100644 --- a/tunsafe_amalgam.cpp +++ b/tunsafe_amalgam.cpp @@ -13,6 +13,7 @@ #include "tunsafe_threading.cpp" #include "tunsafe_cpu.cpp" #include "ip_to_peer_map.cpp" +#include "tunsafe_ipaddr.cpp" #include "crypto/curve25519/curve25519-donna.cpp" #include "crypto/chacha20poly1305.cpp" #include "crypto/blake2s/blake2s.cpp" diff --git a/tunsafe_dnsresolve.h b/tunsafe_dnsresolve.h new file mode 100644 index 0000000..f3a1ff4 --- /dev/null +++ b/tunsafe_dnsresolve.h @@ -0,0 +1,41 @@ +#ifndef TUNSAFE_DNSRESOLVE_H_ +#define TUNSAFE_DNSRESOLVE_H_ + +#include "tunsafe_threading.h" +#include "tunsafe_ipaddr.h" + +class DnsBlocker; + +class DnsResolverCanceller { +public: + DnsResolverCanceller() : cancel_(false) {} + void Cancel(); + void Reset() { cancel_ = false; } + bool is_cancelled() { return cancel_; } +public: + bool cancel_; + ConditionVariable condvar_; +}; + +class DnsResolver { +public: + explicit DnsResolver(DnsBlocker *dns_blocker); + ~DnsResolver(); + + bool Resolve(const char *hostname, IpAddr *result); + void ClearCache(); + + void Cancel() { token_.Cancel(); } + void ResetCancel() { token_.Reset(); } +private: + struct Entry { + std::string name; + IpAddr ip; + Entry(const std::string &name, const IpAddr &ip) : name(name), ip(ip) {} + }; + std::vector cache_; + DnsBlocker *dns_blocker_; + DnsResolverCanceller token_; +}; + +#endif // TUNSAFE_DNSRESOLVE_H_ \ No newline at end of file diff --git a/tunsafe_ipaddr.cpp b/tunsafe_ipaddr.cpp new file mode 100644 index 0000000..aed2abf --- /dev/null +++ b/tunsafe_ipaddr.cpp @@ -0,0 +1,380 @@ +#include "stdafx.h" +#include "tunsafe_ipaddr.h" +#include "tunsafe_dnsresolve.h" + +#if defined(OS_WIN) +#include "network_win32_dnsblock.h" +#include +#endif + +#if defined(OS_POSIX) +#include +#include +#include +#endif // defined(OS_POSIX) + +#include +#include "util.h" + +const char *print_ip_prefix(char buf[kSizeOfAddress], int family, const void *ip, int prefixlen) { + // cast to void* to work on VS2015 + if (!inet_ntop(family, (void*)ip, buf, kSizeOfAddress - 8)) { + memcpy(buf, "unknown", 8); + } + if (prefixlen >= 0) + snprintf(buf + strlen(buf), 8, "/%d", prefixlen); + return buf; +} + +char *PrintIpAddr(const IpAddr &addr, char buf[kSizeOfAddress]) { + if (addr.sin.sin_family == AF_INET) { + print_ip_prefix(buf, addr.sin.sin_family, &addr.sin.sin_addr, -1); + } else if (addr.sin.sin_family == AF_INET6) { + print_ip_prefix(buf, addr.sin.sin_family, &addr.sin6.sin6_addr, -1); + } else { + buf[0] = 0; + } + return buf; +} + + +char *PrintWgCidrAddr(const WgCidrAddr &addr, char buf[kSizeOfAddress]) { + if (addr.size == 32) { + print_ip_prefix(buf, AF_INET, addr.addr, addr.cidr); + } else if (addr.size == 128) { + print_ip_prefix(buf, AF_INET6, addr.addr, addr.cidr); + } else { + buf[0] = 0; + } + return buf; +} + +struct Addr { + byte addr[4]; + uint8 cidr; +}; + +bool ParseCidrAddr(const char *s, WgCidrAddr *out) { + const char *slash = strchr(s, '/'); + if (!slash) + return false; + + size_t len = slash - s; + char *tmp = (char*)alloca(len + 1); + tmp[len] = 0; + memcpy(tmp, s, len); + + int e = atoi(slash + 1); + if (e < 0) return false; + + if (inet_pton(AF_INET, tmp, out->addr) == 1) { + if (e > 32) return false; + out->cidr = e; + out->size = 32; + return true; + } + if (inet_pton(AF_INET6, tmp, out->addr) == 1) { + if (e > 128) return false; + out->cidr = e; + out->size = 128; + return true; + } + return false; +} + +static Mutex g_dns_mutex; + +// This starts a background thread for running DNS resolving. +class DnsResolverThread : private Thread::Runner { +public: + DnsResolverThread(); + ~DnsResolverThread(); + + // Resolve the hostname and store the result in |result|. + // The function will block until it's resolved. If the cancellation + // token or becomes signalled, the call will fail. + bool Resolve(const char *hostname, IpAddr *result, DnsResolverCanceller *token); + +private: + virtual void ThreadMain(); + void StartThread(); + + struct Entry { + enum { + // Set when it's been posted to the job queue + POSTED = 0, + // Set when the thread has finished and original thread should delete + COMPLETE = 1, + // Set when the original thread has cancelled and worker thread should delete + CANCELLED = 2, + }; + + Entry() : hostname(NULL) {} + ~Entry() { free(hostname); } + + char *hostname; + IpAddr *result; + Entry *next; + uint32 state; + ConditionVariable *condvar; + }; + Entry *entry_; + Thread thread_; + bool thread_active_; +}; + +DnsResolverThread::DnsResolverThread() { + thread_active_ = false; + entry_ = NULL; +} + +DnsResolverThread::~DnsResolverThread() { + assert(entry_ == NULL); + thread_.StopThread(); +} + +void DnsResolverCanceller::Cancel() { + g_dns_mutex.Acquire(); + cancel_ = true; + condvar_.Wake(); + g_dns_mutex.Release(); +} + +bool DnsResolverThread::Resolve(const char *hostname, IpAddr *result, DnsResolverCanceller *token) { + if (token->cancel_) + return false; + + Entry *e = new Entry; + e->hostname = _strdup(hostname); + e->result = result; + e->next = NULL; + e->state = Entry::POSTED; + e->condvar = &token->condvar_; + result->sin.sin_family = 0; + + // Push it to the queue and start thread + g_dns_mutex.Acquire(); + Entry **p = &entry_; + while (*p) p = &(*p)->next; + *p = e; + if (!thread_active_) + StartThread(); + // Wait for something to happen with it. + while (!token->cancel_ && e->state == Entry::POSTED) + token->condvar_.Wait(&g_dns_mutex); + if (e->state == Entry::COMPLETE) { + delete e; + } else { + e->state = Entry::CANCELLED; + } + g_dns_mutex.Release(); + return result->sin.sin_family != 0; +} + +void DnsResolverThread::StartThread() { + thread_.StopThread(); + thread_active_ = true; + thread_.StartThread(this); +} + +void DnsResolverThread::ThreadMain() { + Entry *e; + struct addrinfo *ai; + g_dns_mutex.Acquire(); + while ((e = entry_) != NULL) { + entry_ = e->next; + g_dns_mutex.Release(); + + struct addrinfo hints = {0}; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_DEFAULT; + ai = NULL; + if (getaddrinfo(e->hostname, NULL, &hints, &ai) != 0) + ai = NULL; + // he = gethostbyname(e->hostname); + g_dns_mutex.Acquire(); + if (e->state == Entry::CANCELLED) { + delete e; + } else { + if (ai) { + e->result->sin.sin_family = ai->ai_family; + e->result->sin.sin_port = 0; + if (ai->ai_family == AF_INET) + memcpy(&e->result->sin.sin_addr, &((sockaddr_in*)ai->ai_addr)->sin_addr, 4); + else + memcpy(&e->result->sin6.sin6_addr, &((sockaddr_in6*)ai->ai_addr)->sin6_addr, 16); + } +/* if (he) { + e->result->sin.sin_family = AF_INET; + e->result->sin.sin_port = 0; + memcpy(&e->result->sin.sin_addr, he->h_addr_list[0], 4); + }*/ + + e->state = Entry::COMPLETE; + e->condvar->Wake(); + } + + if (ai) + freeaddrinfo(ai); + } + thread_active_ = false; + g_dns_mutex.Release(); +} + +static DnsResolverThread g_dnsresolver_thread; + +static bool InterruptibleSleep(int delay, DnsResolverCanceller *token) { + g_dns_mutex.Acquire(); + uint32 time_at_start = (uint32)OsGetMilliseconds(); + while (delay > 0 && !token->cancel_) { + token->condvar_.WaitTimed(&g_dns_mutex, delay); + uint32 now = (uint32)OsGetMilliseconds(); + delay -= (now - time_at_start); + time_at_start = now; + } + g_dns_mutex.Release(); + return (delay <= 0); +} + +DnsResolver::DnsResolver(DnsBlocker *dns_blocker) { + dns_blocker_ = dns_blocker; +} + +DnsResolver::~DnsResolver() { +} + +void DnsResolver::ClearCache() { + cache_.clear(); +} + +bool DnsResolver::Resolve(const char *hostname, IpAddr *result) { + int attempt = 0; + static const uint8 retry_delays[] = {1, 2, 3, 5, 10}; + char buf[kSizeOfAddress]; + + memset(result, 0, sizeof(IpAddr)); + + // First check cache + for (auto it = cache_.begin(); it != cache_.end(); ++it) { + if (it->name == hostname) { + + *result = it->ip; + RINFO("Resolved %s to %s%s", hostname, PrintIpAddr(*result, buf), " (cached)"); + return true; + } + } + +#if defined(OS_WIN) + // Then disable dns blocker (otherwise the windows dns client service can't resolve) + if (dns_blocker_ && dns_blocker_->IsActive()) { + RINFO("Disabling DNS blocker to resolve %s", hostname); + dns_blocker_->RestoreDns(); + } +#endif // defined(OS_WIN) + + for (;;) { + if (g_dnsresolver_thread.Resolve(hostname, result, &token_)) { + // add to cache + cache_.emplace_back(hostname, *result); + RINFO("Resolved %s to %s%s", hostname, PrintIpAddr(*result, buf), ""); + return true; + } + if (token_.is_cancelled()) + return false; + + RINFO("Unable to resolve %s. Trying again in %d second(s)", hostname, retry_delays[attempt]); + if (!InterruptibleSleep(retry_delays[attempt] * 1000, &token_)) + return false; + + if (attempt != ARRAY_SIZE(retry_delays) - 1) + attempt++; + } +} + +// Parse an IPV4 address into sin, doing NAT64 translation if applicable (on IOS) +static bool ParseIpv4WithNAT64Translation(const char *s, IpAddr *sin, int flags) { + // First verify it's actually a valid ipv4 address to prevent getaddrinfo from doing a slow resolve + if (inet_pton(AF_INET, s, &sin->sin.sin_addr) != 1) + return false; + sin->sin.sin_family = AF_INET; + +#if defined(OS_IOS) + if (!(flags & kParseSockaddrDontDoNAT64)) { + struct addrinfo hints = {0}; + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_flags = AI_DEFAULT; + struct addrinfo* ai = NULL; + // When NAT64 is enabled, I don't get an IPv4 address back. + if (getaddrinfo(s, NULL, &hints, &ai) == 0) { + // check so we have an AF_INET6 and no AF_INET + struct sockaddr_in6 *found = NULL; + for(struct addrinfo *t = ai; t; t = t->ai_next) { + if (t->ai_family == AF_INET) { found = NULL; break; } + if (t->ai_family == AF_INET6) found = (sockaddr_in6*)t->ai_addr; + } + if (found) { + memset(&sin->sin.sin_addr, 0, 4); // clear out ipv4 address already written + memcpy(&sin->sin6.sin6_addr, &found->sin6_addr, 16); + sin->sin.sin_family = AF_INET6; + } + freeaddrinfo(ai); + } + } +#endif // defined(OS_IOS) + return true; +} + +bool ParseSockaddrInWithPort(const char *si, IpAddr *sin, DnsResolver *resolver, int flags) { + size_t len = strlen(si) + 1; + char *s = (char*)alloca(len); + memcpy(s, si, len); + + memset(sin, 0, sizeof(IpAddr)); + if (*s == '[') { + char *end = strchr(s, ']'); + if (end == NULL) + return false; + *end = 0; + if (inet_pton(AF_INET6, s + 1, &sin->sin6.sin6_addr) != 1) + return false; + char *x = strchr(end + 1, ':'); + if (!x) + return false; + sin->sin6.sin6_family = AF_INET6; + sin->sin6.sin6_port = htons(atoi(x + 1)); + return true; + } + char *x = strchr(s, ':'); + if (!x) return false; + *x = 0; + + if (!ParseIpv4WithNAT64Translation(s, sin, flags)) { + if (!resolver) { + return false; + } else if (!resolver->Resolve(s, sin)) { + RERROR("Unable to resolve %s", s); + return false; + } + } + sin->sin.sin_port = htons(atoi(x + 1)); + return true; +} + +bool ParseSockaddrInWithoutPort(char *s, IpAddr *sin, DnsResolver *resolver, int flags) { + memset(sin, 0, sizeof(IpAddr)); + + if (inet_pton(AF_INET6, s, &sin->sin6.sin6_addr) == 1) { + sin->sin.sin_family = AF_INET6; + return true; + } else if (ParseIpv4WithNAT64Translation(s, sin, flags)) { + return true; + } else if (!resolver) { + return false; + } else if (!resolver->Resolve(s, sin)) { + RERROR("Unable to resolve %s", s); + return false; + } + return true; +} diff --git a/tunsafe_ipaddr.h b/tunsafe_ipaddr.h new file mode 100644 index 0000000..8b398a2 --- /dev/null +++ b/tunsafe_ipaddr.h @@ -0,0 +1,40 @@ +#ifndef TUNSAFE_IPADDR_H_ +#define TUNSAFE_IPADDR_H_ + +#include "tunsafe_types.h" + +#if !defined(OS_WIN) +#include +#include +#include +#include +#endif + +union IpAddr { + sockaddr_in sin; + sockaddr_in6 sin6; +}; + +struct WgCidrAddr { + uint8 addr[16]; + uint8 size; + uint8 cidr; +}; + +class DnsResolver; + +#define kSizeOfAddress 64 +const char *print_ip_prefix(char buf[kSizeOfAddress], int family, const void *ip, int prefixlen); +char *PrintIpAddr(const IpAddr &addr, char buf[kSizeOfAddress]); +char *PrintWgCidrAddr(const WgCidrAddr &addr, char buf[kSizeOfAddress]); + +bool ParseCidrAddr(const char *s, WgCidrAddr *out); + +enum { + kParseSockaddrDontDoNAT64 = 1, +}; +bool ParseSockaddrInWithPort(const char *s, IpAddr *sin, DnsResolver *resolver, int flags = 0); +bool ParseSockaddrInWithoutPort(char *s, IpAddr *sin, DnsResolver *resolver, int flags = 0); + + +#endif // TUNSAFE_IPADDR_H_ diff --git a/wireguard_config.cpp b/wireguard_config.cpp index c0abc51..9004fad 100644 --- a/wireguard_config.cpp +++ b/wireguard_config.cpp @@ -2,333 +2,13 @@ // Copyright (C) 2018 Ludvig Strigeus . All Rights Reserved. #include "stdafx.h" #include "wireguard_config.h" -#include "netapi.h" -#include "tunsafe_endian.h" #include "wireguard.h" #include "util.h" #include -#include #include #include #include - -#if defined(OS_POSIX) -#include -#include -#include -#include -#include -#endif - -#if defined(OS_WIN) -#include "network_win32_dnsblock.h" -#endif - -const char *print_ip_prefix(char buf[kSizeOfAddress], int family, const void *ip, int prefixlen) { - // cast to void* to work on VS2015 - if (!inet_ntop(family, (void*)ip, buf, kSizeOfAddress - 8)) { - memcpy(buf, "unknown", 8); - } - if (prefixlen >= 0) - snprintf(buf + strlen(buf), 8, "/%d", prefixlen); - return buf; -} - -char *PrintIpAddr(const IpAddr &addr, char buf[kSizeOfAddress]) { - if (addr.sin.sin_family == AF_INET) { - print_ip_prefix(buf, addr.sin.sin_family, &addr.sin.sin_addr, -1); - } else if (addr.sin.sin_family == AF_INET) { - print_ip_prefix(buf, addr.sin.sin_family, &addr.sin6.sin6_addr, -1); - } else { - buf[0] = 0; - } - return buf; -} - - -char *PrintWgCidrAddr(const WgCidrAddr &addr, char buf[kSizeOfAddress]) { - if (addr.size == 32) { - print_ip_prefix(buf, AF_INET, addr.addr, addr.cidr); - } else if (addr.size == 128) { - print_ip_prefix(buf, AF_INET6, addr.addr, addr.cidr); - } else { - buf[0] = 0; - } - return buf; -} - -struct Addr { - byte addr[4]; - uint8 cidr; -}; - -bool ParseCidrAddr(char *s, WgCidrAddr *out) { - char *slash = strchr(s, '/'); - if (!slash) - return false; - - *slash = 0; - int e = atoi(slash + 1); - if (e < 0) return false; - - if (inet_pton(AF_INET, s, out->addr) == 1) { - if (e > 32) return false; - out->cidr = e; - out->size = 32; - return true; - } - if (inet_pton(AF_INET6, s, out->addr) == 1) { - if (e > 128) return false; - out->cidr = e; - out->size = 128; - return true; - } - return false; -} - -static Mutex g_dns_mutex; - -// This starts a background thread for running DNS resolving. -class DnsResolverThread : private Thread::Runner { -public: - DnsResolverThread(); - ~DnsResolverThread(); - - // Resolve the hostname and store the result in |result|. - // The function will block until it's resolved. If the cancellation - // token or becomes signalled, the call will fail. - bool Resolve(const char *hostname, IpAddr *result, DnsResolverCanceller *token); - -private: - virtual void ThreadMain(); - void StartThread(); - - struct Entry { - enum { - // Set when it's been posted to the job queue - POSTED = 0, - // Set when the thread has finished and original thread should delete - COMPLETE = 1, - // Set when the original thread has cancelled and worker thread should delete - CANCELLED = 2, - }; - - Entry() : hostname(NULL) {} - ~Entry() { free(hostname); } - - char *hostname; - IpAddr *result; - Entry *next; - uint32 state; - ConditionVariable *condvar; - }; - Entry *entry_; - Thread thread_; - bool thread_active_; -}; - -DnsResolverThread::DnsResolverThread() { - thread_active_ = false; - entry_ = NULL; -} - -DnsResolverThread::~DnsResolverThread() { - assert(entry_ == NULL); - thread_.StopThread(); -} - -void DnsResolverCanceller::Cancel() { - g_dns_mutex.Acquire(); - cancel_ = true; - condvar_.Wake(); - g_dns_mutex.Release(); -} - -bool DnsResolverThread::Resolve(const char *hostname, IpAddr *result, DnsResolverCanceller *token) { - if (token->cancel_) - return false; - - Entry *e = new Entry; - e->hostname = _strdup(hostname); - e->result = result; - e->next = NULL; - e->state = Entry::POSTED; - e->condvar = &token->condvar_; - result->sin.sin_family = 0; - - // Push it to the queue and start thread - g_dns_mutex.Acquire(); - Entry **p = &entry_; - while (*p) p = &(*p)->next; - *p = e; - if (!thread_active_) - StartThread(); - // Wait for something to happen with it. - while (!token->cancel_ && e->state == Entry::POSTED) - token->condvar_.Wait(&g_dns_mutex); - if (e->state == Entry::COMPLETE) { - delete e; - } else { - e->state = Entry::CANCELLED; - } - g_dns_mutex.Release(); - return result->sin.sin_family != 0; -} - -void DnsResolverThread::StartThread() { - thread_.StopThread(); - thread_active_ = true; - thread_.StartThread(this); -} - -void DnsResolverThread::ThreadMain() { - Entry *e = NULL; - struct hostent *he = NULL; - for (;;) { - g_dns_mutex.Acquire(); - if (e) { - if (e->state == Entry::CANCELLED) { - delete e; - } else { - if (he) { - e->result->sin.sin_family = AF_INET; - e->result->sin.sin_port = 0; - memcpy(&e->result->sin.sin_addr, he->h_addr_list[0], 4); - } - e->state = Entry::COMPLETE; - e->condvar->Wake(); - } - } - if (!(e = entry_)) { - thread_active_ = false; - break; - } - entry_ = e->next; - g_dns_mutex.Release(); - he = gethostbyname(e->hostname); - } - g_dns_mutex.Release(); -} - -static DnsResolverThread g_dnsresolver_thread; - -bool InterruptibleSleep(int delay, DnsResolverCanceller *token) { - g_dns_mutex.Acquire(); - uint32 time_at_start = (uint32)OsGetMilliseconds(); - while (delay > 0 && !token->cancel_) { - token->condvar_.WaitTimed(&g_dns_mutex, delay); - uint32 now = (uint32)OsGetMilliseconds(); - delay -= (now - time_at_start); - time_at_start = now; - } - g_dns_mutex.Release(); - return (delay <= 0); -} - -DnsResolver::DnsResolver(DnsBlocker *dns_blocker) { - dns_blocker_ = dns_blocker; -} - -DnsResolver::~DnsResolver() { -} - -void DnsResolver::ClearCache() { - cache_.clear(); -} - -bool DnsResolver::Resolve(const char *hostname, IpAddr *result) { - int attempt = 0; - static const uint8 retry_delays[] = {1, 2, 3, 5, 10}; - char buf[kSizeOfAddress]; - - memset(result, 0, sizeof(IpAddr)); - - // First check cache - for (auto it = cache_.begin(); it != cache_.end(); ++it) { - if (it->name == hostname) { - - *result = it->ip; - RINFO("Resolved %s to %s%s", hostname, PrintIpAddr(*result, buf), " (cached)"); - return true; - } - } - -#if defined(OS_WIN) - // Then disable dns blocker (otherwise the windows dns client service can't resolve) - if (dns_blocker_ && dns_blocker_->IsActive()) { - RINFO("Disabling DNS blocker to resolve %s", hostname); - dns_blocker_->RestoreDns(); - } -#endif // defined(OS_WIN) - - for (;;) { - if (g_dnsresolver_thread.Resolve(hostname, result, &token_)) { - // add to cache - cache_.emplace_back(hostname, *result); - RINFO("Resolved %s to %s%s", hostname, PrintIpAddr(*result, buf), ""); - return true; - } - if (token_.is_cancelled()) - return false; - - RINFO("Unable to resolve %s. Trying again in %d second(s)", hostname, retry_delays[attempt]); - if (!InterruptibleSleep(retry_delays[attempt] * 1000, &token_)) - return false; - - if (attempt != ARRAY_SIZE(retry_delays) - 1) - attempt++; - } -} - -bool ParseSockaddrInWithPort(const char *si, IpAddr *sin, DnsResolver *resolver) { - size_t len = strlen(si) + 1; - char *s = (char*)alloca(len); - memcpy(s, si, len); - - memset(sin, 0, sizeof(IpAddr)); - if (*s == '[') { - char *end = strchr(s, ']'); - if (end == NULL) - return false; - *end = 0; - if (inet_pton(AF_INET6, s + 1, &sin->sin6.sin6_addr) != 1) - return false; - char *x = strchr(end + 1, ':'); - if (!x) - return false; - sin->sin.sin_family = AF_INET6; - sin->sin.sin_port = htons(atoi(x + 1)); - return true; - } - char *x = strchr(s, ':'); - if (!x) return false; - *x = 0; - - if (inet_pton(AF_INET, s, &sin->sin.sin_addr) == 1) { - sin->sin.sin_family = AF_INET; - } else if (!resolver) { - return false; - } else if (!resolver->Resolve(s, sin)) { - RERROR("Unable to resolve %s", s); - return false; - } - sin->sin.sin_port = htons(atoi(x + 1)); - return true; -} - -static bool ParseSockaddrInWithoutPort(char *s, IpAddr *sin, DnsResolver *resolver) { - if (inet_pton(AF_INET6, s, &sin->sin6.sin6_addr) == 1) { - sin->sin.sin_family = AF_INET6; - return true; - } else if (inet_pton(AF_INET, s, &sin->sin.sin_addr) == 1) { - sin->sin.sin_family = AF_INET; - return true; - } else if (!resolver->Resolve(s, sin)) { - RERROR("Unable to resolve %s", s); - return false; - } - return true; -} +#include class WgFileParser { public: @@ -449,7 +129,7 @@ bool WgFileParser::ParseFlag(const char *group, const char *key, char *value) { } else if (strcmp(key, "DNS") == 0) { SplitString(value, ',', &ss); for (size_t i = 0; i < ss.size(); i++) { - if (!ParseSockaddrInWithoutPort(ss[i], &sin, dns_resolver_)) + if (!ParseSockaddrInWithoutPort(ss[i], &sin, dns_resolver_, kParseSockaddrDontDoNAT64)) return false; wg_->AddDnsServer(sin); } diff --git a/wireguard_config.h b/wireguard_config.h index 632f7df..7ba57ca 100644 --- a/wireguard_config.h +++ b/wireguard_config.h @@ -3,44 +3,10 @@ #ifndef TINYVPN_TINYVPN_H_ #define TINYVPN_TINYVPN_H_ -#include "netapi.h" -#include "tunsafe_threading.h" +#include +class DnsResolver; class WireguardProcessor; -class DnsBlocker; - -class DnsResolverCanceller { -public: - DnsResolverCanceller() : cancel_(false) {} - void Cancel(); - void Reset() { cancel_ = false; } - bool is_cancelled() { return cancel_; } -public: - bool cancel_; - ConditionVariable condvar_; -}; - -class DnsResolver { -public: - explicit DnsResolver(DnsBlocker *dns_blocker); - ~DnsResolver(); - - bool Resolve(const char *hostname, IpAddr *result); - void ClearCache(); - - void Cancel() { token_.Cancel(); } - void ResetCancel() { token_.Reset(); } -private: - struct Entry { - std::string name; - IpAddr ip; - Entry(const std::string &name, const IpAddr &ip) : name(name), ip(ip) {} - }; - std::vector cache_; - DnsBlocker *dns_blocker_; - DnsResolverCanceller token_; -}; - class WgConfig { public: @@ -52,12 +18,5 @@ private: bool ParseWireGuardConfigString(WireguardProcessor *wg, char *buf, size_t buf_size, DnsResolver *dns_resolver); bool ParseWireGuardConfigFile(WireguardProcessor *wg, const char *filename, DnsResolver *dns_resolver); -#define kSizeOfAddress 64 -const char *print_ip_prefix(char buf[kSizeOfAddress], int family, const void *ip, int prefixlen); -char *PrintIpAddr(const IpAddr &addr, char buf[kSizeOfAddress]); -char *PrintWgCidrAddr(const WgCidrAddr &addr, char buf[kSizeOfAddress]); - -bool ParseCidrAddr(char *s, WgCidrAddr *out); -bool ParseSockaddrInWithPort(const char *s, IpAddr *sin, DnsResolver *resolver); #endif // TINYVPN_TINYVPN_H_