Simplify tun configuration
This commit is contained in:
parent
335133fa8f
commit
a7776ab7c4
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
|
|
31
netapi.h
31
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<WgCidrAddr> addresses;
|
||||
|
||||
// Set this to configure DNS server for ipv4,ipv6
|
||||
std::vector<IpAddr> ipv4_dns;
|
||||
std::vector<IpAddr> 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<IpAddr> dns;
|
||||
|
||||
// This holds all cidr addresses to add as additional routing entries
|
||||
std::vector<WgCidrAddr> extra_routes;
|
||||
std::vector<WgCidrAddr> included_routes;
|
||||
|
||||
// This holds all the ips to exclude
|
||||
std::vector<WgCidrAddr> excluded_ips;
|
||||
std::vector<WgCidrAddr> excluded_routes;
|
||||
|
||||
// This holds the pre/post commands
|
||||
PrePostCommands pre_post_commands;
|
||||
|
|
|
@ -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);
|
||||
|
@ -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!");
|
||||
|
@ -462,71 +440,73 @@ 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)) {
|
||||
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)) {
|
||||
AddRoute(ReadBE32(it->addr), it->cidr, ipv4_default_gw, NULL);
|
||||
} else if (it->size == 128) {
|
||||
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_);
|
||||
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(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(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, 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -80,6 +80,7 @@ protected:
|
|||
WireguardProcessor *processor_;
|
||||
std::vector<RouteInfo> cleanup_commands_;
|
||||
std::vector<std::string> pre_down_, post_down_;
|
||||
std::vector<WgCidrAddr> addresses_to_remove_;
|
||||
sigset_t orig_signal_mask_;
|
||||
char devname_[16];
|
||||
bool tun_interface_gone_;
|
||||
|
|
|
@ -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<WgCidrAddr> &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<WgCidrAddr> *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<WgCidrAddr> &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<WgCidrAddr> &addresses, std::vector<WgCidrAddr> *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;
|
||||
}
|
||||
|
||||
if (!IsIpv6AddressSet(new_address))
|
||||
return true;
|
||||
|
||||
if (old_address != NULL)
|
||||
old_address->size = 128;
|
||||
// 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 = new_cidr;
|
||||
Row.OnLinkPrefixLength = it->cidr;
|
||||
Row.Address.si_family = AF_INET6;
|
||||
memcpy(&Row.Address.Ipv6.sin6_addr, new_address, 16);
|
||||
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(new_address), new_cidr);
|
||||
return false;
|
||||
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);
|
||||
}
|
||||
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<WgCidrAddr> &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,15 +1264,21 @@ 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<size_t>(config.ipv4_dns.size(), kMaxDnsServers);
|
||||
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);
|
||||
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,
|
||||
|
@ -1219,6 +1287,7 @@ bool TunWin32Adapter::ConfigureAdapter(const TunInterface::TunConfig &&config, T
|
|||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Get device MAC address
|
||||
if (!DeviceIoControl(handle_, TAP_IOCTL_GET_MAC, mac_adress_, 6, mac_adress_, sizeof(mac_adress_), &len, NULL)) {
|
||||
|
@ -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()) {
|
||||
// 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;
|
||||
if (!SetIPV6DnsOnInterface(&interface_luid_, config.ipv6_dns.data(), config.ipv6_dns.size())) {
|
||||
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,24 +1362,16 @@ 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)) {
|
||||
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.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
|
@ -1317,12 +1382,13 @@ 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);
|
||||
|
@ -1330,13 +1396,11 @@ 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;
|
||||
}
|
||||
}
|
||||
// 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_))
|
||||
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.");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
// Avoid adding a route if it's a subset of the address
|
||||
if (IsWgCidrAddrSubsetOfAny(*it, config.addresses))
|
||||
continue;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
|
|
@ -118,7 +118,7 @@ private:
|
|||
|
||||
int old_ipv4_metric_, old_ipv6_metric_;
|
||||
|
||||
WgCidrAddr old_ipv6_address_;
|
||||
std::vector<WgCidrAddr> old_ipv6_address_;
|
||||
|
||||
NET_LUID interface_luid_;
|
||||
|
||||
|
|
132
wireguard.cpp
132
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<IpAddr> *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;
|
||||
uint32 ipv4_broadcast_addr = 0xffffffff;
|
||||
|
||||
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;
|
||||
}
|
||||
config.ip = ReadBE32(tun_addr_.addr);
|
||||
config.cidr = tun_addr_.cidr;
|
||||
} else {
|
||||
RERROR("No IPv4 address configured");
|
||||
|
||||
// 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_ips = excluded_ips_;
|
||||
|
||||
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);
|
||||
}
|
||||
config.excluded_routes = excluded_ips_;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// 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))
|
||||
|
|
|
@ -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<WgCidrAddr> &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<IpAddr> dns_addr_, dns6_addr_;
|
||||
std::vector<WgCidrAddr> addresses_;
|
||||
std::vector<IpAddr> dns_addr_;
|
||||
|
||||
TunInterface::PrePostCommands pre_post_;
|
||||
|
||||
|
|
|
@ -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_);
|
||||
|
|
Loading…
Reference in a new issue