From a7776ab7c4563259253bc1b58349dc475e6c6959 Mon Sep 17 00:00:00 2001 From: Ludvig Strigeus Date: Tue, 23 Oct 2018 00:48:20 +0200 Subject: [PATCH] Simplify tun configuration --- ip_to_peer_map.cpp | 12 -- ip_to_peer_map.h | 3 - netapi.h | 31 +--- network_bsd_common.cpp | 156 +++++++++--------- network_bsd_common.h | 1 + network_win32.cpp | 350 ++++++++++++++++++++++++----------------- network_win32.h | 2 +- wireguard.cpp | 136 +++++++--------- wireguard.h | 9 +- wireguard_config.cpp | 6 +- 10 files changed, 359 insertions(+), 347 deletions(-) diff --git a/ip_to_peer_map.cpp b/ip_to_peer_map.cpp index 48539bb..77e2f49 100644 --- a/ip_to_peer_map.cpp +++ b/ip_to_peer_map.cpp @@ -37,18 +37,6 @@ void *IpToPeerMap::LookupV4(uint32 ip) { return ipv4_.Lookup(ip); } -void *IpToPeerMap::LookupV4DefaultPeer() { - return ipv4_.LookupExact(0, 0); -} - -void *IpToPeerMap::LookupV6DefaultPeer() { - for (auto it = ipv6_.begin(); it != ipv6_.end(); ++it) { - if (it->cidr_len == 0) - return it->peer; - } - return NULL; -} - void IpToPeerMap::RemoveV4(uint32 ip, int cidr) { ipv4_.Delete(ip, cidr); } diff --git a/ip_to_peer_map.h b/ip_to_peer_map.h index 2db5d5e..b85b4d4 100644 --- a/ip_to_peer_map.h +++ b/ip_to_peer_map.h @@ -50,9 +50,6 @@ public: void *LookupV4(uint32 ip); void *LookupV6(const void *addr); - void *LookupV4DefaultPeer(); - void *LookupV6DefaultPeer(); - void RemoveV4(uint32 ip, int cidr); void RemoveV6(const void *addr, int cidr); private: diff --git a/netapi.h b/netapi.h index ca187ce..c4a1903 100644 --- a/netapi.h +++ b/netapi.h @@ -63,43 +63,26 @@ public: }; struct TunConfig { - // IP address and netmask of the tun device - in_addr_t ip; - uint8 cidr; - - bool block_dns_on_adapters; - // no, yes(firewall), yes(route), yes(both), 255(default) uint8 internet_blocking; - // Set this to configure a default route for ipv4 - bool use_ipv4_default_route; + bool block_dns_on_adapters; - // Set this to configure a default route for ipv6 - bool use_ipv6_default_route; - // This holds the address of the vpn endpoint, so those get routed to the old iface. - uint32 default_route_endpoint_v4; - // Set mtu int mtu; - // Set ipv6 address? - uint8 ipv6_address[16]; - uint8 ipv6_cidr; + // The ipv6 and ipv4 addresses + std::vector addresses; - // Set this to configure DNS server for ipv4,ipv6 - std::vector ipv4_dns; - std::vector ipv6_dns; - - // This holds the address of the vpn endpoint, so those get routed to the old iface. - uint8 default_route_endpoint_v6[16]; + // Set this to configure DNS server + std::vector dns; // This holds all cidr addresses to add as additional routing entries - std::vector extra_routes; + std::vector included_routes; // This holds all the ips to exclude - std::vector excluded_ips; + std::vector excluded_routes; // This holds the pre/post commands PrePostCommands pre_post_commands; diff --git a/network_bsd_common.cpp b/network_bsd_common.cpp index dae7b66..d6a4921 100644 --- a/network_bsd_common.cpp +++ b/network_bsd_common.cpp @@ -372,29 +372,6 @@ static uint32 CidrToNetmaskV4(int cidr) { return cidr == 32 ? 0xffffffff : 0xffffffff << (32 - cidr); } -static uint32 ComputeIpv4DefaultRoute(uint32 ip, uint32 netmask) { - uint32 default_route_v4 = (ip & netmask) | 1; - if (default_route_v4 == ip) - default_route_v4++; - return default_route_v4; -} - -static void ComputeIpv6DefaultRoute(const uint8 *ipv6_address, uint8 ipv6_cidr, uint8 *default_route_v6) { - memcpy(default_route_v6, ipv6_address, 16); - // clear the last bits of the ipv6 address to match the cidr. - size_t n = (ipv6_cidr + 7) >> 3; - memset(&default_route_v6[n], 0, 16 - n); - if (n == 0) - return; - // adjust the final byte - default_route_v6[n - 1] &= ~(0xff >> (ipv6_cidr & 7)); - // set the very last byte to something - default_route_v6[15] |= 1; - // ensure it doesn't collide - if (memcmp(default_route_v6, ipv6_address, 16) == 0) - default_route_v6[15] ^= 3; -} - void TunsafeBackendBsd::AddRoute(uint32 ip, uint32 cidr, uint32 gw, const char *dev) { uint32 ip_be, gw_be; WriteBE32(&ip_be, ip); @@ -411,7 +388,7 @@ static void AddOrRemoveRoute(const RouteInfo &cd, bool remove) { #if defined(OS_LINUX) const char *cmd = remove ? "del" : "add"; const char *proto = (cd.family == AF_INET) ? NULL : "-6"; - if (cd.dev.empty()) { + if (cd.dev.empty()) { RunCommand("/sbin/ip %s route %s %s via %s", proto, cmd, buf1, buf2); } else { RunCommand("/sbin/ip %s route %s %s dev %s", proto, cmd, buf1, cd.dev.c_str()); @@ -451,6 +428,7 @@ static bool IsIpv6AddressSet(const void *p) { // Called to initialize tun bool TunsafeBackendBsd::Configure(const TunConfig &&config, TunConfigOut *out) override { char buf[kSizeOfAddress]; + char buf2[kSizeOfAddress]; if (!RunPrePostCommand(config.pre_post_commands.pre_up)) { RERROR("Pre command failed!"); @@ -461,72 +439,74 @@ bool TunsafeBackendBsd::Configure(const TunConfig &&config, TunConfigOut *out) o if (!InitializeTun(devname_)) return false; - - uint32 netmask = CidrToNetmaskV4(config.cidr); - uint32 default_route_v4 = ComputeIpv4DefaultRoute(config.ip, netmask); + const WgCidrAddr *ipv4_addr = NULL; + const WgCidrAddr *ipv6_addr = NULL; + for (auto it = config.addresses.begin(); it != config.addresses.end(); ++it) { + if (it->size == 32 && ipv4_addr == NULL) + ipv4_addr = &*it; + else if (it->size == 128 && ipv6_addr == NULL) + ipv6_addr = &*it; + } + if (ipv4_addr == NULL) { + RERROR("The TUN adapter requires an IPv4 address"); + return false; + } + uint32 ipv4_netmask = CidrToNetmaskV4(ipv4_addr->cidr); + uint32 ipv4_ip = ReadBE32(ipv4_addr->addr); + + addresses_to_remove_ = config.addresses; #if defined(OS_LINUX) - if (config.ip) { - char ip[4]; - WriteBE32(ip, config.ip); - RunCommand("/sbin/ip address add dev %s %s", devname_, print_ip_prefix(buf, AF_INET, ip, config.cidr)); - } - if (config.ipv6_cidr) { - RunCommand("/sbin/ip address add dev %s %s", devname_, print_ip_prefix(buf, AF_INET6, config.ipv6_address, config.ipv6_cidr)); - } + RunCommand("/sbin/ip address flush dev %s scope global", devname_); + for(const WgCidrAddr &a : config.addresses) + RunCommand("/sbin/ip address add dev %s %s", devname_, print_ip_prefix(buf, a.size == 32 ? AF_INET : AF_INET6, a.addr, a.cidr)); RunCommand("/sbin/ip link set dev %s mtu %d up", devname_, config.mtu); -#else // !defined(OS_LINUX) - if (config.ip) { - RunCommand("/sbin/ifconfig %s %A mtu %d %A netmask %A up", devname_, config.ip, config.mtu, config.ip, netmask); +#else + for(const WgCidrAddr &a : config.addresses) { + if (a.size == 32) { + RunCommand("/sbin/ifconfig %s inet %s %s add", devname_, print_ip_prefix(buf, AF_INET, a.addr, a.cidr), print_ip_prefix(buf2, AF_INET, a.addr, -1)); + } else { + RunCommand("/sbin/ifconfig %s inet6 %s add", devname_, print_ip_prefix(buf, AF_INET6, a.addr, a.cidr)); + } } - if (config.ipv6_cidr) { - RunCommand("/sbin/ifconfig %s inet6 add %s", devname_, print_ip_prefix(buf, AF_INET6, config.ipv6_address, config.ipv6_cidr)); - } -#endif // !defined(OS_LINUX) + RunCommand("/sbin/ifconfig %s mtu %d up", devname_, config.mtu); +#endif - if (config.ip) { - AddRoute(config.ip & netmask, config.cidr, config.ip, devname_); - } - if (config.use_ipv4_default_route) { - if (config.default_route_endpoint_v4) { - uint32 ipv4_default_gw; - char default_iface[16]; - if (!GetDefaultRoute(default_iface, sizeof(default_iface), &ipv4_default_gw)) { + char default_iface[16]; + uint32 ipv4_default_gw; + bool found_ipv4_route = GetDefaultRoute(default_iface, sizeof(default_iface), &ipv4_default_gw); + for (auto it = config.excluded_routes.begin(); it != config.excluded_routes.end(); ++it) { + if (it->size == 32) { + if (!found_ipv4_route) { RERROR("Unable to determine default interface."); return false; } - AddRoute(config.default_route_endpoint_v4, 32, ipv4_default_gw, NULL); - for (auto it = config.excluded_ips.begin(); it != config.excluded_ips.end(); ++it) { - if (it->size == 32) - AddRoute(ReadBE32(it->addr), it->cidr, ipv4_default_gw, default_iface); - } - } - AddRoute(0x00000000, 1, default_route_v4, devname_); - AddRoute(0x80000000, 1, default_route_v4, devname_); - } - - uint8 default_route_v6[16]; - - if (config.ipv6_cidr) { - static const uint8 matchall_1_route[17] = {0x80, 0, 0, 0}; - ComputeIpv6DefaultRoute(config.ipv6_address, config.ipv6_cidr, default_route_v6); - if (config.use_ipv6_default_route) { - if (IsIpv6AddressSet(config.default_route_endpoint_v6)) { - RERROR("default_route_endpoint_v6 not supported"); - } - AddRoute(AF_INET6, matchall_1_route + 1, 1, default_route_v6, devname_); - AddRoute(AF_INET6, matchall_1_route + 0, 1, default_route_v6, devname_); + AddRoute(ReadBE32(it->addr), it->cidr, ipv4_default_gw, NULL); + } else if (it->size == 128) { + RERROR("default_route_endpoint_v6 not supported"); + return false; } } // Add all the extra routes - for (auto it = config.extra_routes.begin(); it != config.extra_routes.end(); ++it) { + for (auto it = config.included_routes.begin(); it != config.included_routes.end(); ++it) { + if (it->cidr == 0) { + if (it->size == 32) { + AddRoute(0x00000000, 1, ipv4_ip, devname_); + AddRoute(0x80000000, 1, ipv4_ip, devname_); + } else if (it->size == 128 && ipv6_addr) { + static const uint8 matchall_1_route[17] = {0x80, 0, 0, 0}; + AddRoute(AF_INET6, matchall_1_route + 1, 1, ipv6_addr->addr, devname_); + AddRoute(AF_INET6, matchall_1_route + 0, 1, ipv6_addr->addr, devname_); + } + continue; + } if (it->size == 32) { - AddRoute(ReadBE32(it->addr), it->cidr, default_route_v4, devname_); - } else if (it->size == 128 && config.ipv6_cidr) { - AddRoute(AF_INET6, it->addr, it->cidr, default_route_v6, devname_); + AddRoute(ReadBE32(it->addr), it->cidr, ipv4_ip, devname_); + } else if (it->size == 128 && ipv6_addr) { + AddRoute(AF_INET6, it->addr, it->cidr, ipv6_addr->addr, devname_); } } @@ -539,13 +519,30 @@ bool TunsafeBackendBsd::Configure(const TunConfig &&config, TunConfigOut *out) o } void TunsafeBackendBsd::CleanupRoutes() { + char buf[kSizeOfAddress]; + RunPrePostCommand(pre_down_); for(auto it = cleanup_commands_.begin(); it != cleanup_commands_.end(); ++it) { if (!tun_interface_gone_ || strcmp(it->dev.c_str(), devname_) != 0) DelRoute(*it); } + +#if defined(OS_LINUX) + for(const WgCidrAddr &a : addresses_to_remove_) + RunCommand("/sbin/ip address del dev %s %s", devname_, print_ip_prefix(buf, a.size == 32 ? AF_INET : AF_INET6, a.addr, a.cidr)); +#else + for(const WgCidrAddr &a : addresses_to_remove_) { + if (a.size == 32) { + RunCommand("/sbin/ifconfig %s inet %s -alias", devname_, print_ip_prefix(buf, AF_INET, a.addr, -1)); + } else { + RunCommand("/sbin/ifconfig %s inet6 %s -alias", devname_, print_ip_prefix(buf, AF_INET6, a.addr, -1)); + } + } +#endif + cleanup_commands_.clear(); + addresses_to_remove_.clear(); RunPrePostCommand(post_down_); @@ -767,9 +764,13 @@ public: virtual void OnConnected() override { if (!is_connected_) { - uint32 ipv4_ip = ReadBE32(wg_processor_->tun_addr().addr); + const WgCidrAddr *ipv4_addr = NULL; + for (const WgCidrAddr &x : wg_processor_->addr()) { + if (x.size == 32) { ipv4_addr = &x; break; } + } + uint32 ipv4_ip = ipv4_addr ? ReadBE32(ipv4_addr->addr) : 0; char buf[kSizeOfAddress]; - RINFO("Connection established. IP %s", print_ip(buf, ipv4_ip)); + RINFO("Connection established. IP %s", ipv4_ip ? print_ip(buf, ipv4_ip) : "(none)"); is_connected_ = true; } } @@ -831,3 +832,4 @@ int main(int argc, char **argv) { return 0; } + diff --git a/network_bsd_common.h b/network_bsd_common.h index 36d566c..c4ef5ad 100644 --- a/network_bsd_common.h +++ b/network_bsd_common.h @@ -80,6 +80,7 @@ protected: WireguardProcessor *processor_; std::vector cleanup_commands_; std::vector pre_down_, post_down_; + std::vector addresses_to_remove_; sigset_t orig_signal_mask_; char devname_[16]; bool tun_interface_gone_; diff --git a/network_win32.cpp b/network_win32.cpp index 5482523..7d701e3 100644 --- a/network_win32.cpp +++ b/network_win32.cpp @@ -310,7 +310,7 @@ struct RouteInfo { uint8 found_null_routes; }; -static inline bool IsRouteOriginatingFromNullRoute(MIB_IPFORWARD_ROW2 *row) { +static bool IsRouteOriginatingFromNullRoute(MIB_IPFORWARD_ROW2 *row) { if (!(row->InterfaceLuid.Info.IfType == 24 && row->Protocol == MIB_IPPROTO_NETMGMT && row->DestinationPrefix.PrefixLength == 1)) return false; if (row->NextHop.si_family == AF_INET) { @@ -322,14 +322,25 @@ static inline bool IsRouteOriginatingFromNullRoute(MIB_IPFORWARD_ROW2 *row) { return false; } -static inline bool IsRouteTheAddressOfTheServer(int family, MIB_IPFORWARD_ROW2 *row, uint8 *old_endpoint_to_delete) { - if (!(row->Protocol == MIB_IPPROTO_NETMGMT && row->DestinationPrefix.Prefix.si_family == family)) +static bool IsDestinationRouteEqualTo(MIB_IPFORWARD_ROW2 *row, const WgCidrAddr *addr) { + if (addr->size == 32) { + return row->DestinationPrefix.Prefix.si_family == AF_INET && + row->DestinationPrefix.PrefixLength == addr->cidr && + memcmp(&row->DestinationPrefix.Prefix.Ipv4.sin_addr, addr->addr, 4) == 0; + + } else if (addr->size == 128) { + return row->DestinationPrefix.Prefix.si_family == AF_INET6 && + row->DestinationPrefix.PrefixLength == addr->cidr && + memcmp(&row->DestinationPrefix.Prefix.Ipv6.sin6_addr, addr->addr, 16) == 0; + } else { return false; - if (family == AF_INET) { - return (row->DestinationPrefix.PrefixLength == 32 && memcmp(&row->DestinationPrefix.Prefix.Ipv4.sin_addr, old_endpoint_to_delete, 4) == 0); - } else if (family == AF_INET6) { - return (row->DestinationPrefix.PrefixLength == 128 && memcmp(&row->DestinationPrefix.Prefix.Ipv6.sin6_addr, old_endpoint_to_delete, 16) == 0); } +} + +static bool IsDestinationRouteEqualToAny(MIB_IPFORWARD_ROW2 *row, const std::vector &addr) { + for (const WgCidrAddr &x : addr) + if (IsDestinationRouteEqualTo(row, &x)) + return true; return false; } @@ -343,17 +354,18 @@ static void DeleteRouteOrPrintErr(MIB_IPFORWARD_ROW2 *row) { (void*)&row->DestinationPrefix.Prefix.Ipv6.sin6_addr, row->DestinationPrefix.PrefixLength)); } -static bool GetDefaultRouteAndDeleteOldRoutes(int family, const NET_LUID *InterfaceLuid, bool keep_null_routes, uint8 *old_endpoint_to_delete, RouteInfo *ri) { +static bool GetDefaultRouteAndDeleteOldRoutes(int family, const NET_LUID *InterfaceLuid, bool keep_null_routes, const std::vector *old_endpoint_to_delete, RouteInfo *ri) { MIB_IPFORWARD_TABLE2 *table = NULL; assert(family == AF_INET || family == AF_INET6); + ri->found_default_adapter = false; + ri->found_null_routes = 0; + if (GetIpForwardTable2(family, &table)) return false; DWORD rv = 0; DWORD gw_metric = 0xffffffff; - ri->found_default_adapter = false; - ri->found_null_routes = 0; for (unsigned i = 0; i < table->NumEntries; i++) { MIB_IPFORWARD_ROW2 *row = &table->Table[i]; if (InterfaceLuid && memcmp(&row->InterfaceLuid, InterfaceLuid, sizeof(NET_LUID)) == 0) { @@ -378,8 +390,8 @@ static bool GetDefaultRouteAndDeleteOldRoutes(int family, const NET_LUID *Interf if (old_endpoint_to_delete && ri->found_default_adapter) { for (unsigned i = 0; i < table->NumEntries; i++) { MIB_IPFORWARD_ROW2 *row = &table->Table[i]; - if (memcmp(&row->InterfaceLuid, &ri->default_adapter, sizeof(NET_LUID)) == 0) { - if (IsRouteTheAddressOfTheServer(family, row, old_endpoint_to_delete)) + if (row->Protocol == MIB_IPPROTO_NETMGMT && memcmp(&row->InterfaceLuid, &ri->default_adapter, sizeof(NET_LUID)) == 0) { + if (IsDestinationRouteEqualToAny(row, *old_endpoint_to_delete)) DeleteRouteOrPrintErr(row); } } @@ -1008,31 +1020,45 @@ static void AssignIpv6Address(const void *new_address, int new_cidr, WgCidrAddr memcpy(target->addr, new_address, 16); } +static int IsIpv6AddressInList(const std::vector &addresses, const void *ipv6_addr, int cidr) { + int i = 0; + for (auto it = addresses.begin(); it != addresses.end(); ++it, i++) { + if (it->size == 128 && it->cidr == cidr && memcmp(it->addr, ipv6_addr, 16) == 0) + return i; + } + return -1; +} + // Set new_cidr to 0 to clear it. -static bool SetIPV6AddressOnInterface(NET_LUID *InterfaceLuid, const uint8 new_address[16], int new_cidr, WgCidrAddr *old_address) { +static bool SetIPV6AddressOnInterface(NET_LUID *InterfaceLuid, const std::vector &addresses, std::vector *old_address) { NETIO_STATUS Status; PMIB_UNICASTIPADDRESS_TABLE table = NULL; if (old_address) - memset(old_address, 0, sizeof(WgCidrAddr)); + old_address->clear(); Status = GetUnicastIpAddressTable(AF_INET6, &table); if (Status != 0) { RERROR("GetUnicastAddressTable Failed. Error %d\n", Status); return false; } - - bool found_row = false; + uint64 matching_addr = 0; for (int i = 0; i < (int)table->NumEntries; i++) { MIB_UNICASTIPADDRESS_ROW *row = &table->Table[i]; if (!memcmp(&row->InterfaceLuid, InterfaceLuid, sizeof(NET_LUID))) { if (row->PrefixOrigin == 1 && row->SuffixOrigin == 1) { - if (row->OnLinkPrefixLength == new_cidr && !memcmp(&row->Address.Ipv6.sin6_addr, new_address, 16)) { - found_row = true; + if (old_address) { + WgCidrAddr tmp; + AssignIpv6Address(&row->Address.Ipv6.sin6_addr, row->OnLinkPrefixLength, &tmp); + old_address->push_back(tmp); + } + + int idx = IsIpv6AddressInList(addresses, &row->Address.Ipv6.sin6_addr, row->OnLinkPrefixLength); + if (idx >= 0 && idx < 64) { + matching_addr |= (uint64)1 << idx; + RINFO("Using IPv6 address: %s/%d", PrintIPV6((uint8*)&row->Address.Ipv6.sin6_addr), row->OnLinkPrefixLength); continue; } - if (old_address != NULL) - AssignIpv6Address(&row->Address.Ipv6.sin6_addr, row->OnLinkPrefixLength, old_address); Status = DeleteUnicastIpAddressEntry(row); if (Status) RERROR("Error %d deleting IPv6 address: %s/%d", Status, PrintIPV6((uint8*)&row->Address.Ipv6.sin6_addr), row->OnLinkPrefixLength); @@ -1043,43 +1069,50 @@ static bool SetIPV6AddressOnInterface(NET_LUID *InterfaceLuid, const uint8 new_a } FreeMibTable(table); - if (found_row) { - RINFO("Using IPv6 address: %s/%d", PrintIPV6(new_address), new_cidr); - return true; + // Add all ipv6 addresses that were not already set. + bool success = true; + int i = 0; + for (auto it = addresses.begin(); it != addresses.end(); ++it, i++) { + // skip it because of wrong type or already set? + if (it->size != 128 || i < 64 && (matching_addr & ((uint64)1 << i))) + continue; + + MIB_UNICASTIPADDRESS_ROW Row; + InitializeUnicastIpAddressEntry(&Row); + Row.OnLinkPrefixLength = it->cidr; + Row.Address.si_family = AF_INET6; + memcpy(&Row.Address.Ipv6.sin6_addr, it->addr, 16); + Row.InterfaceLuid = *InterfaceLuid; + Status = CreateUnicastIpAddressEntry(&Row); + if (Status != 0) { + RERROR("Error %d setting IPv6 address: %s/%d", Status, PrintIPV6(it->addr), it->cidr); + success = false; + } else { + RINFO("Added IPV6 Address: %s/%d", PrintIPV6(it->addr), it->cidr); + } } - - if (!IsIpv6AddressSet(new_address)) - return true; - - if (old_address != NULL) - old_address->size = 128; - - MIB_UNICASTIPADDRESS_ROW Row; - InitializeUnicastIpAddressEntry(&Row); - Row.OnLinkPrefixLength = new_cidr; - Row.Address.si_family = AF_INET6; - memcpy(&Row.Address.Ipv6.sin6_addr, new_address, 16); - Row.InterfaceLuid = *InterfaceLuid; - Status = CreateUnicastIpAddressEntry(&Row); - if (Status != 0) { - RERROR("Error %d setting IPv6 address: %s/%d", Status, PrintIPV6(new_address), new_cidr); - return false; - } - RINFO("Set IPV6 Address to: %s/%d", PrintIPV6(new_address), new_cidr); - return true; + return success; } static bool SetIPV6DnsOnInterface(NET_LUID *InterfaceLuid, const IpAddr *new_address, size_t new_address_size) { char buf[128]; char ipv6[128]; + bool isfirst = true; NET_IFINDEX InterfaceIndex; if (ConvertInterfaceLuidToIndex(InterfaceLuid, &InterfaceIndex)) return false; if (new_address_size) { for (size_t i = 0; i < new_address_size; i++) { + if (new_address[i].sin.sin_family != AF_INET6) + continue; if (!inet_ntop(AF_INET6, (void*)&new_address[i].sin6.sin6_addr, ipv6, sizeof(ipv6))) return false; - snprintf(buf, sizeof(buf), "netsh interface ipv6 %s dns name=%d static %s validate=no", (i == 0) ? "set" : "add", InterfaceIndex, ipv6); + if (isfirst) { + isfirst = false; + snprintf(buf, sizeof(buf), "netsh interface ipv6 set dnsservers name=%d static %s validate=no", InterfaceIndex, ipv6); + } else { + snprintf(buf, sizeof(buf), "netsh interface ipv6 add dnsservers name=%d %s validate=no", InterfaceIndex, ipv6); + } if (!RunNetsh(buf)) return false; } @@ -1127,7 +1160,6 @@ static bool AddMultipleCatchallRoutes(int inet, int bits, const uint8 *target, c TunWin32Adapter::TunWin32Adapter(DnsBlocker *dns_blocker, const char guid[ADAPTER_GUID_SIZE]) { handle_ = NULL; dns_blocker_ = dns_blocker; - old_ipv6_address_.size = 0; old_ipv6_metric_ = kMetricNone; old_ipv4_metric_ = kMetricNone; has_dns6_setting_ = false; @@ -1162,6 +1194,22 @@ bool TunWin32Adapter::OpenAdapter(TunsafeBackendWin32 *backend, DWORD open_flags return (handle_ != NULL); } +static inline bool CheckFirstNbitsEquals(const byte *a, const byte *b, size_t n) { + return memcmp(a, b, n >> 3) == 0 && ((n & 7) == 0 || !((a[n >> 3] ^ b[n >> 3]) & (0xff << (8 - (n & 7))))); +} + +static bool IsWgCidrAddrSubsetOf(const WgCidrAddr &inner, const WgCidrAddr &outer) { + return inner.size == outer.size && inner.cidr >= outer.cidr && + CheckFirstNbitsEquals(inner.addr, outer.addr, outer.cidr); +} + +static bool IsWgCidrAddrSubsetOfAny(const WgCidrAddr &inner, const std::vector &addr) { + for (auto &a : addr) + if (IsWgCidrAddrSubsetOf(inner, a)) + return true; + return false; +} + bool TunWin32Adapter::ConfigureAdapter(const TunInterface::TunConfig &&config, TunInterface::TunConfigOut *out) { DWORD len, err; @@ -1175,14 +1223,28 @@ bool TunWin32Adapter::ConfigureAdapter(const TunInterface::TunConfig &&config, T pre_down_ = std::move(config.pre_post_commands.pre_down); post_down_ = std::move(config.pre_post_commands.post_down); - uint32 netmask = CidrToNetmaskV4(config.cidr); + const WgCidrAddr *ipv4_addr = NULL; + const WgCidrAddr *ipv6_addr = NULL; + for (auto it = config.addresses.begin(); it != config.addresses.end(); ++it) { + if (it->size == 32 && ipv4_addr == NULL) + ipv4_addr = &*it; + else if (it->size == 128 && ipv6_addr == NULL) + ipv6_addr = &*it; + } + if (ipv4_addr == NULL) { + RERROR("The TUN adapter on Windows requires an IPv4 address"); + return false; + } + + uint32 ipv4_netmask = CidrToNetmaskV4(ipv4_addr->cidr); + uint32 ipv4_ip = ReadBE32(ipv4_addr->addr); // Set TAP-Windows TUN subnet mode if (1) { uint32 v[3]; - v[0] = htonl(config.ip); - v[1] = htonl(config.ip & netmask); - v[2] = htonl(netmask); + v[0] = htonl(ipv4_ip); + v[1] = htonl(ipv4_ip & ipv4_netmask); + v[2] = htonl(ipv4_netmask); if (!DeviceIoControl(handle_, TAP_IOCTL_CONFIG_TUN, v, sizeof(v), v, sizeof(v), &len, NULL)) { RERROR("DeviceIoControl(TAP_IOCTL_CONFIG_TUN) failed"); return false; @@ -1192,9 +1254,9 @@ bool TunWin32Adapter::ConfigureAdapter(const TunInterface::TunConfig &&config, T // Set DHCP IP/netmask { uint32 v[4]; - v[0] = htonl(config.ip); - v[1] = htonl(netmask); - v[2] = htonl((config.ip | ~netmask) - 1); // x.x.x.254 + v[0] = htonl(ipv4_ip); + v[1] = htonl(ipv4_netmask); + v[2] = htonl((ipv4_ip | ~ipv4_netmask) - 1); // x.x.x.254 v[3] = 31536000; // One year if (!DeviceIoControl(handle_, TAP_IOCTL_CONFIG_DHCP_MASQ, v, sizeof(v), v, sizeof(v), &len, NULL)) { RERROR("DeviceIoControl(TAP_IOCTL_CONFIG_DHCP_MASQ) failed"); @@ -1202,21 +1264,28 @@ bool TunWin32Adapter::ConfigureAdapter(const TunInterface::TunConfig &&config, T } } - // Set DHCP config string - if (config.ipv4_dns.size()) { + // Extract and set IPv4 DNS servers through DHCP + { enum { kMaxDnsServers = 4 }; uint8 dhcp_options[2 + kMaxDnsServers * 4]; // max 4 dns servers - size_t num_dns = std::min(config.ipv4_dns.size(), kMaxDnsServers); - dhcp_options[0] = 6; - dhcp_options[1] = (uint8)(num_dns * 4); - for(size_t i = 0; i < num_dns; i++) - memcpy(&dhcp_options[2 + i * 4], &config.ipv4_dns[i].sin.sin_addr, num_dns * 4); - DWORD dhcp_options_size = (DWORD)(num_dns * 4 + 2); - byte output[10]; - if (!DeviceIoControl(handle_, TAP_IOCTL_CONFIG_DHCP_SET_OPT, + uint32 num_dns = 0; + for (auto it = config.dns.begin(); it != config.dns.end(); ++it) { + if (it->sin.sin_family != AF_INET) + continue; + memcpy(&dhcp_options[2 + num_dns * 4], &it->sin.sin_addr, 4); + if (++num_dns == kMaxDnsServers) + break; + } + if (num_dns != 0) { + dhcp_options[0] = 6; + dhcp_options[1] = (uint8)(num_dns * 4); + DWORD dhcp_options_size = (DWORD)(num_dns * 4 + 2); + byte output[10]; + if (!DeviceIoControl(handle_, TAP_IOCTL_CONFIG_DHCP_SET_OPT, (void*)dhcp_options, dhcp_options_size, output, sizeof(output), &len, NULL)) { - RERROR("DeviceIoControl(TAP_IOCTL_CONFIG_DHCP_SET_OPT) failed"); - return false; + RERROR("DeviceIoControl(TAP_IOCTL_CONFIG_DHCP_SET_OPT) failed"); + return false; + } } } @@ -1246,7 +1315,7 @@ bool TunWin32Adapter::ConfigureAdapter(const TunInterface::TunConfig &&config, T err = SetMtuOnNetworkAdapter(&interface_luid_, AF_INET, config.mtu); if (err) RERROR("SetMtuOnNetworkAdapter IPv4 failed: %d", err); - if (config.ipv6_cidr) { + if (ipv6_addr) { err = SetMtuOnNetworkAdapter(&interface_luid_, AF_INET6, config.mtu); if (err) RERROR("SetMtuOnNetworkAdapter IPv6 failed: %d", err); @@ -1254,18 +1323,22 @@ bool TunWin32Adapter::ConfigureAdapter(const TunInterface::TunConfig &&config, T } has_dns6_setting_ = false; - if (config.ipv6_cidr) { - SetIPV6AddressOnInterface(&interface_luid_, config.ipv6_address, config.ipv6_cidr, &old_ipv6_address_); + if (ipv6_addr) { + SetIPV6AddressOnInterface(&interface_luid_, config.addresses, &old_ipv6_address_); - if (config.ipv6_dns.size()) { - has_dns6_setting_ = true; - if (!SetIPV6DnsOnInterface(&interface_luid_, config.ipv6_dns.data(), config.ipv6_dns.size())) { - RERROR("SetIPV6DnsOnInterface: failed"); + // Check if we have at least one ipv6 setting + for (auto it = config.dns.begin(); it != config.dns.end(); ++it) { + if (it->sin.sin_family == AF_INET6) { + has_dns6_setting_ = true; + break; } } + if (has_dns6_setting_ && !SetIPV6DnsOnInterface(&interface_luid_, config.dns.data(), config.dns.size())) { + RERROR("SetIPV6DnsOnInterface: failed"); + } } - if ((config.ipv4_dns.size() || has_dns6_setting_) && config.block_dns_on_adapters) { + if (config.dns.size() && config.block_dns_on_adapters) { RINFO("Blocking standard DNS on all adapters"); dns_blocker_->BlockDnsExceptOnAdapter(interface_luid_, has_dns6_setting_); @@ -1273,7 +1346,7 @@ bool TunWin32Adapter::ConfigureAdapter(const TunInterface::TunConfig &&config, T if (err) RERROR("SetMetricOnNetworkAdapter IPv4 failed: %d", err); - if (config.ipv6_cidr) { + if (ipv6_addr) { err = SetMetricOnNetworkAdapter(&interface_luid_, AF_INET6, 2, &old_ipv6_metric_); if (err) RERROR("SetMetricOnNetworkAdapter IPv6 failed: %d", err); @@ -1289,25 +1362,17 @@ bool TunWin32Adapter::ConfigureAdapter(const TunInterface::TunConfig &&config, T RouteInfo ri, ri6; - uint32 default_route_endpoint_v4 = ToBE32(config.default_route_endpoint_v4); - // Delete any current /1 default routes and read some stuff from the routing table. - if (!GetDefaultRouteAndDeleteOldRoutes(AF_INET, &interface_luid_, block_all_traffic_route, config.use_ipv4_default_route ? (uint8*)&default_route_endpoint_v4 : NULL, &ri)) { + if (!GetDefaultRouteAndDeleteOldRoutes(AF_INET, &interface_luid_, block_all_traffic_route, &config.excluded_routes, &ri)) { RERROR("Unable to read old default gateway and delete old default routes."); return false; } - if (config.ipv6_cidr) { - // Delete any current /1 default routes and read some stuff from the routing table. - if (!GetDefaultRouteAndDeleteOldRoutes(AF_INET6, &interface_luid_, block_all_traffic_route, config.use_ipv6_default_route ? (uint8*)config.default_route_endpoint_v6 : NULL, &ri6)) { - RERROR("Unable to read old default gateway and delete old default routes for IPv6."); - return false; - } + // Delete any current /1 default routes and read some stuff from the routing table. + if (!GetDefaultRouteAndDeleteOldRoutes(AF_INET6, &interface_luid_, block_all_traffic_route, &config.excluded_routes, &ri6)) { + RERROR("Unable to read old default gateway and delete old default routes for IPv6."); } - uint32 default_route_v4 = ComputeIpv4DefaultRoute(config.ip, netmask); - uint8 default_route_v6[16]; - if (block_all_traffic_route) { RINFO("Blocking all regular Internet traffic using routing rules"); NET_LUID localhost_luid; @@ -1317,17 +1382,17 @@ bool TunWin32Adapter::ConfigureAdapter(const TunInterface::TunConfig &&config, T g_killswitch_curr |= kBlockInternet_Route; uint32 dst[4] = {0}; + if (!AddMultipleCatchallRoutes(AF_INET, 1, (uint8*)&dst, localhost_luid, NULL)) { RERROR("Unable to add routes for route based blocking."); DeactivateKillSwitch(0); return false; } - if (config.ipv6_cidr) { - if (!AddMultipleCatchallRoutes(AF_INET6, 1, (uint8*)&dst, localhost_luid, NULL)) { - RERROR("Unable to add IPv6 routes for route based blocking."); - DeactivateKillSwitch(0); - return false; - } + + if (!AddMultipleCatchallRoutes(AF_INET6, 1, (uint8*)&dst, localhost_luid, NULL)) { + RERROR("Unable to add IPv6 routes for route based blocking."); + DeactivateKillSwitch(0); + return false; } } } @@ -1335,8 +1400,7 @@ bool TunWin32Adapter::ConfigureAdapter(const TunInterface::TunConfig &&config, T if (ibs & kBlockInternet_Firewall) { RINFO("Blocking all regular Internet traffic using firewall rules"); g_killswitch_curr |= kBlockInternet_Firewall; - - if (!AddKillSwitchFirewall(interface_luid_, config.ipv6_cidr != 0, (ibs & kBlockInternet_AllowLocalNetworks) != 0)) { + if (!AddKillSwitchFirewall(interface_luid_, true, (ibs & kBlockInternet_AllowLocalNetworks) != 0)) { RERROR("Unable to activate firewall based kill switch"); DeactivateKillSwitch(0); return false; @@ -1345,63 +1409,54 @@ bool TunWin32Adapter::ConfigureAdapter(const TunInterface::TunConfig &&config, T DeactivateKillSwitch(ibs); - // Configure default route? - if (config.use_ipv4_default_route) { - // Add a bypass route to the original gateway? - if (config.default_route_endpoint_v4 != 0) { - if (!ri.found_default_adapter) { - RERROR("Unable to read old ipv4 default gateway"); - return false; - } - if (!AddRoute(AF_INET, &default_route_endpoint_v4, 32, ri.default_gw, &ri.default_adapter, &routes_to_undo_)) { - RERROR("Unable to add ipv4 gateway bypass route."); - return false; + uint8 default_route_v4[4]; + uint8 default_route_v6[16]; + + WriteBE32(default_route_v4, ComputeIpv4DefaultRoute(ipv4_ip, ipv4_netmask)); + if (ipv6_addr) + ComputeIpv6DefaultRoute(ipv6_addr->addr, ipv6_addr->cidr, default_route_v6); + + // Add all the routes that should go through the VPN + for (auto it = config.included_routes.begin(); it != config.included_routes.end(); ++it) { + if (it->cidr == 0) { + // /0 gets changed to two /1 routes, to avoid overwriting the system's default route + if (it->size == 32) { + if (!AddMultipleCatchallRoutes(AF_INET, block_all_traffic_route ? 2 : 1, default_route_v4, interface_luid_, &routes_to_undo_)) + RERROR("Unable to add new default ipv4 route."); + } else if (it->size == 128 && ipv6_addr) { + if (!AddMultipleCatchallRoutes(AF_INET6, block_all_traffic_route ? 2 : 1, default_route_v6, interface_luid_, &routes_to_undo_)) + RERROR("Unable to add new default ipv6 route."); } + continue; } - // Either add 4 routes or 2 routes, depending on if we use route blocking. - uint32 be = ToBE32(default_route_v4); - if (!AddMultipleCatchallRoutes(AF_INET, block_all_traffic_route ? 2 : 1, (uint8*)&be, interface_luid_, &routes_to_undo_)) - RERROR("Unable to add new default ipv4 route."); - } + // Avoid adding a route if it's a subset of the address + if (IsWgCidrAddrSubsetOfAny(*it, config.addresses)) + continue; - if (config.ipv6_cidr) { - ComputeIpv6DefaultRoute(config.ipv6_address, config.ipv6_cidr, default_route_v6); - - // Configure default route? - if (config.use_ipv6_default_route) { - if (IsIpv6AddressSet(config.default_route_endpoint_v6)) { - if (!ri6.found_default_adapter) { - RERROR("Unable to read old ipv6 default gateway"); - return false; - } - if (!AddRoute(AF_INET6, config.default_route_endpoint_v6, 128, ri.default_gw, &ri6.default_adapter, &routes_to_undo_)) { - RERROR("Unable to add ipv6 gateway bypass route."); - return false; - } - } - if (!AddMultipleCatchallRoutes(AF_INET6, block_all_traffic_route ? 2 : 1, default_route_v6, interface_luid_, &routes_to_undo_)) - RERROR("Unable to add new default ipv6 route."); - } - } - - // Add all the extra routes - for (auto it = config.extra_routes.begin(); it != config.extra_routes.end(); ++it) { if (it->size == 32) { - uint32 be = ToBE32(default_route_v4); - AddRoute(AF_INET, it->addr, it->cidr, &be, &interface_luid_, &routes_to_undo_); - } else if (it->size == 128 && config.ipv6_cidr) { + AddRoute(AF_INET, it->addr, it->cidr, default_route_v4, &interface_luid_, &routes_to_undo_); + } else if (it->size == 128 && ipv6_addr) { AddRoute(AF_INET6, it->addr, it->cidr, default_route_v6, &interface_luid_, &routes_to_undo_); } } // Add all the routes that should bypass vpn - for (auto it = config.excluded_ips.begin(); it != config.excluded_ips.end(); ++it) { + int warned = 0; + for (auto it = config.excluded_routes.begin(); it != config.excluded_routes.end(); ++it) { if (it->size == 32) { - if (ri.found_default_adapter) + if (ri.found_default_adapter) { AddRoute(AF_INET, it->addr, it->cidr, ri.default_gw, &ri.default_adapter, &routes_to_undo_); - } else if (it->size == 128 && config.ipv6_cidr) { - if (ri6.found_default_adapter) + } else if (!(warned & 1)) { + warned |= 1; + RERROR("Unable to read old ipv4 default gateway"); + } + } else if (it->size == 128) { + if (ri6.found_default_adapter) { AddRoute(AF_INET6, it->addr, it->cidr, ri6.default_gw, &ri6.default_adapter, &routes_to_undo_); + } else if (!(warned & 2)) { + warned |= 2; + RERROR("Unable to read old ipv6 default gateway"); + } } } @@ -1414,7 +1469,7 @@ bool TunWin32Adapter::ConfigureAdapter(const TunInterface::TunConfig &&config, T RERROR("FlushIpNetTable failed: 0x%X", err); return false; } - if (config.ipv6_cidr) { + if (ipv6_addr != NULL) { if ((err = FlushIpNetTable2(AF_INET6, InterfaceIndex)) != NO_ERROR) { RERROR("FlushIpNetTable failed: 0x%X", err); return false; @@ -1439,8 +1494,8 @@ void TunWin32Adapter::CloseAdapter(bool is_restart) { TunAdaptersInUse::GetInstance()->Release(backend_); } - if (old_ipv6_address_.size != 0) - SetIPV6AddressOnInterface(&interface_luid_, old_ipv6_address_.addr, old_ipv6_address_.cidr, NULL); + if (old_ipv6_address_.size()) + SetIPV6AddressOnInterface(&interface_luid_, old_ipv6_address_, NULL); if (old_ipv4_metric_ != kMetricNone) SetMetricOnNetworkAdapter(&interface_luid_, AF_INET, old_ipv4_metric_, NULL); if (old_ipv6_metric_ != kMetricNone) @@ -1449,7 +1504,7 @@ void TunWin32Adapter::CloseAdapter(bool is_restart) { SetIPV6DnsOnInterface(&interface_luid_, NULL, 0); old_ipv4_metric_ = old_ipv6_metric_ = -1; - old_ipv6_address_.size = 0; + old_ipv6_address_.clear(); has_dns6_setting_ = false; for (auto it = routes_to_undo_.begin(); it != routes_to_undo_.end(); ++it) @@ -2245,10 +2300,17 @@ void TunsafeBackendWin32::SendConfigurationProtocolPacket(uint32 identifier, con void TunsafeBackendWin32::OnConnected() { if (status_ != TunsafeBackend::kStatusConnected) { - ipv4_ip_ = ReadBE32(wg_processor_->tun_addr().addr); + const WgCidrAddr *ipv4_addr = NULL; + for (const WgCidrAddr &x : wg_processor_->addr()) { + if (x.size == 32) { + ipv4_addr = &x; + break; + } + } + ipv4_ip_ = ipv4_addr ? ReadBE32(ipv4_addr->addr) : 0; if (status_ != TunsafeBackend::kStatusReconnecting) { char buf[kSizeOfAddress]; - RINFO("Connection established. IP %s", print_ip_prefix(buf, AF_INET, wg_processor_->tun_addr().addr, -1)); + RINFO("Connection established. IP %s", ipv4_addr ? print_ip_prefix(buf, AF_INET, ipv4_addr->addr, -1) : "(none)"); } SetStatus(TunsafeBackend::kStatusConnected); } diff --git a/network_win32.h b/network_win32.h index 78ce0c2..6f87f02 100644 --- a/network_win32.h +++ b/network_win32.h @@ -118,7 +118,7 @@ private: int old_ipv4_metric_, old_ipv6_metric_; - WgCidrAddr old_ipv6_address_; + std::vector old_ipv6_address_; NET_LUID interface_luid_; diff --git a/wireguard.cpp b/wireguard.cpp index e4f0b33..99d025e 100644 --- a/wireguard.cpp +++ b/wireguard.cpp @@ -23,8 +23,6 @@ enum { }; WireguardProcessor::WireguardProcessor(UdpInterface *udp, TunInterface *tun, ProcessorDelegate *procdel) { - tun_addr_.size = 0; - tun6_addr_.size = 0; udp_ = udp; tun_ = tun; procdel_ = procdel; @@ -54,21 +52,16 @@ void WireguardProcessor::SetListenPort(int listen_port) { } void WireguardProcessor::AddDnsServer(const IpAddr &sin) { - std::vector *target = (sin.sin.sin_family == AF_INET6) ? &dns6_addr_ : &dns_addr_; - target->push_back(sin); + dns_addr_.push_back(sin); } bool WireguardProcessor::SetTunAddress(const WgCidrAddr &addr) { - WgCidrAddr *target = (addr.size == 128) ? &tun6_addr_ : &tun_addr_; - if (target->size != 0) - return false; - *target = addr; + addresses_.push_back(addr); return true; } void WireguardProcessor::ClearTunAddress() { - tun_addr_.size = 0; - tun6_addr_.size = 0; + addresses_.clear(); } void WireguardProcessor::AddExcludedIp(const WgCidrAddr &cidr_addr) { @@ -118,19 +111,32 @@ void WireguardProcessor::SetupCompressionHeader(WgPacketCompressionVer01 *c) { c->ttl = 64; #endif // defined(OS_WIN) WriteLE16(&c->version, EXT_PACKET_COMPRESSION_VER); - memcpy(c->ipv4_addr, &tun_addr_.addr, 4); - if (tun6_addr_.size == 128) - memcpy(c->ipv6_addr, &tun6_addr_.addr, 16); - c->flags = ((tun_addr_.cidr >> 3) & 3); + + for (auto it = addresses_.begin(); it != addresses_.end(); ++it) { + if (it->size == 32) { + memcpy(c->ipv4_addr, it->addr, 4); + c->flags = ((it->cidr >> 3) & 3); + break; + } + } + for (auto it = addresses_.begin(); it != addresses_.end(); ++it) { + if (it->size == 128) { + memcpy(c->ipv6_addr, it->addr, 16); + break; + } + } } -static inline bool CheckFirstNbitsEquals(const byte *a, const byte *b, size_t n) { - return memcmp(a, b, n >> 3) == 0 && ((n & 7) == 0 || !((a[n >> 3] ^ b[n >> 3]) & (0xff << (8 - (n & 7))))); -} - -static bool IsWgCidrAddrSubsetOf(const WgCidrAddr &inner, const WgCidrAddr &outer) { - return inner.size == outer.size && inner.cidr >= outer.cidr && - CheckFirstNbitsEquals(inner.addr, outer.addr, outer.cidr); +static WgCidrAddr WgCidrAddrFromIpAddr(const IpAddr &addr) { + WgCidrAddr r = {0}; + if (addr.sin.sin_family == AF_INET) { + r.size = r.cidr = 32; + memcpy(r.addr, &addr.sin.sin_addr, 4); + } else if (addr.sin.sin_family == AF_INET6) { + r.size = r.cidr = 128; + memcpy(r.addr, &addr.sin6.sin6_addr, 16); + } + return r; } bool WireguardProcessor::Start() { @@ -146,74 +152,52 @@ bool WireguardProcessor::ConfigureTun() { assert(dev_.IsMainThread()); TunInterface::TunConfig config = {0}; - if (tun_addr_.size == 32) { - if (tun_addr_.cidr >= 31) { - RERROR("TAP is not compatible CIDR /31 or /32. Changing to /24"); - tun_addr_.cidr = 24; - } - config.ip = ReadBE32(tun_addr_.addr); - config.cidr = tun_addr_.cidr; - } else { - RERROR("No IPv4 address configured"); - } + uint32 ipv4_broadcast_addr = 0xffffffff; - config.mtu = mtu_; - config.pre_post_commands = pre_post_; - config.excluded_ips = excluded_ips_; + for (auto it = addresses_.begin(); it != addresses_.end(); ++it) { + if (it->size == 32) { + if (it->cidr >= 31) { + RINFO("TAP is not compatible CIDR /31 or /32. Changing to /24"); + it->cidr = 24; + } - uint32 netmask = tun_addr_.cidr == 32 ? 0xffffffff : 0xffffffff << (32 - tun_addr_.cidr); - - uint32 ipv4_broadcast_addr = (netmask == 0xffffffff) ? 0xffffffff : config.ip | ~netmask; - - if (tun6_addr_.size == 128) { - if (tun6_addr_.cidr > 126) { - RERROR("IPv6 /127 or /128 not supported. Changing to 120"); - tun6_addr_.cidr = 120; - } - config.ipv6_cidr = tun6_addr_.cidr; - memcpy(&config.ipv6_address, tun6_addr_.addr, 16); - } - - if (add_routes_mode_) { - WgPeer *peer = (WgPeer *)dev_.ip_to_peer_map().LookupV4DefaultPeer(); - if (peer != NULL && peer->endpoint_.sin.sin_family != 0) { - config.default_route_endpoint_v4 = (peer->endpoint_.sin.sin_family == AF_INET) ? ReadBE32(&peer->endpoint_.sin.sin_addr) : 0; - // Set the default route to something - config.use_ipv4_default_route = true; - peer->allow_endpoint_change_ = false; - } - - // Also configure ipv6 gw? - if (config.ipv6_cidr != 0) { - peer = (WgPeer*)dev_.ip_to_peer_map().LookupV6DefaultPeer(); - if (peer != NULL && peer->endpoint_.sin.sin_family != 0) { - if (peer->endpoint_.sin.sin_family == AF_INET6) - memcpy(&config.default_route_endpoint_v6, &peer->endpoint_.sin6.sin6_addr, 16); - config.use_ipv6_default_route = true; - peer->allow_endpoint_change_ = false; + // Packets to this IP will not be sent out. + if (ipv4_broadcast_addr == 0xffffffff) { + uint32 netmask = it->cidr == 32 ? 0xffffffff : 0xffffffff << (32 - it->cidr); + ipv4_broadcast_addr = (netmask == 0xffffffff) ? 0xffffffff : ReadBE32(it->addr) | ~netmask; + } + } else if (it->size == 128) { + if (it->cidr > 126) { + RERROR("IPv6 /127 or /128 not supported. Changing to 120"); + it->cidr = 120; } } + config.addresses.push_back(*it); + } + + config.mtu = mtu_; + config.pre_post_commands = pre_post_; + config.excluded_routes = excluded_ips_; + if (add_routes_mode_) { // For each peer, add the extra routes to the extra routes table for (WgPeer *peer = dev_.first_peer(); peer; peer = peer->next_peer_) { for (auto it = peer->allowed_ips_.begin(); it != peer->allowed_ips_.end(); ++it) { - // Don't add an entry if it's identical to my address or it's a default route - if (IsWgCidrAddrSubsetOf(*it, tun_addr_) || IsWgCidrAddrSubsetOf(*it, tun6_addr_) || it->cidr == 0) - continue; - // Don't add an entry if we have no ipv6 address configured - if (config.ipv6_cidr == 0 && it->size != 32) - continue; - config.extra_routes.push_back(*it); + config.included_routes.push_back(*it); + // If peer has the ::/0 or 0.0.0.0/0 address, disallow endpoint change. + if (it->cidr == 0) + peer->allow_endpoint_change_ = false; } + // Add the peer's endpoint to the route exclusion list. + WgCidrAddr endpoint_addr = WgCidrAddrFromIpAddr(peer->endpoint_); + if (endpoint_addr.size != 0) + config.excluded_routes.push_back(endpoint_addr); } } - config.block_dns_on_adapters = dns_blocking_ && ((config.use_ipv4_default_route && dns_addr_.size()) || - (config.use_ipv6_default_route && dns6_addr_.size())); + config.block_dns_on_adapters = dns_blocking_; config.internet_blocking = internet_blocking_; - - config.ipv4_dns = dns_addr_; - config.ipv6_dns = dns6_addr_; + config.dns = dns_addr_; TunInterface::TunConfigOut config_out; if (!tun_->Configure(std::move(config), &config_out)) diff --git a/wireguard.h b/wireguard.h index 12f5dac..b0b3fa4 100644 --- a/wireguard.h +++ b/wireguard.h @@ -99,8 +99,7 @@ public: WgDevice &dev() { return dev_; } TunInterface::PrePostCommands &prepost() { return pre_post_; } - const WgCidrAddr &tun_addr() { return tun_addr_; } - + const std::vector &addr() { return addresses_; } void RunAllMainThreadScheduled(); private: void DoWriteUdpPacket(Packet *packet); @@ -138,12 +137,10 @@ private: WgDevice dev_; - WgCidrAddr tun_addr_; - WgCidrAddr tun6_addr_; - WgProcessorStats stats_; - std::vector dns_addr_, dns6_addr_; + std::vector addresses_; + std::vector dns_addr_; TunInterface::PrePostCommands pre_post_; diff --git a/wireguard_config.cpp b/wireguard_config.cpp index b1638f0..b20cba3 100644 --- a/wireguard_config.cpp +++ b/wireguard_config.cpp @@ -379,10 +379,8 @@ void WgConfig::HandleConfigurationProtocolGet(WireguardProcessor *proc, std::str CmsgAppendHex(result, "private_key", proc->dev_.s_priv_, sizeof(proc->dev_.s_priv_)); if (proc->listen_port_) CmsgAppendFmt(result, "listen_port=%d", proc->listen_port_); - if (proc->tun_addr_.size == 32) - CmsgAppendFmt(result, "address=%s", PrintWgCidrAddr(proc->tun_addr_, buf)); - if (proc->tun6_addr_.size == 128) - CmsgAppendFmt(result, "address=%s", PrintWgCidrAddr(proc->tun6_addr_, buf)); + for(const WgCidrAddr &x : proc->addresses_) + CmsgAppendFmt(result, "address=%s", PrintWgCidrAddr(x, buf)); for (WgPeer *peer = proc->dev_.peers_; peer; peer = peer->next_peer_) { WG_SCOPED_LOCK(peer->lock_);