summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--attic/RoutingTable.cpp (renamed from osdep/RoutingTable.cpp)118
-rw-r--r--attic/RoutingTable.hpp (renamed from osdep/RoutingTable.hpp)4
-rw-r--r--node/InetAddress.hpp20
-rw-r--r--node/Utils.hpp16
-rw-r--r--objects.mk1
-rw-r--r--osdep/ManagedRoute.cpp456
-rw-r--r--osdep/ManagedRoute.hpp95
-rw-r--r--service/OneService.cpp102
8 files changed, 726 insertions, 86 deletions
diff --git a/osdep/RoutingTable.cpp b/attic/RoutingTable.cpp
index 40523898..f8856d79 100644
--- a/osdep/RoutingTable.cpp
+++ b/attic/RoutingTable.cpp
@@ -86,8 +86,8 @@ std::vector<RoutingTable::Entry> RoutingTable::get(bool includeLinkLocal,bool in
}
char *iface = (char *)0;
- uint32_t destination = 0;
- uint32_t gateway = 0;
+ uint32_t target = 0;
+ uint32_t via = 0;
int metric = 0;
uint32_t mask = 0;
@@ -95,23 +95,23 @@ std::vector<RoutingTable::Entry> RoutingTable::get(bool includeLinkLocal,bool in
for(char *f=Utils::stok(line,"\t \r\n",&stmp2);(f);f=Utils::stok((char *)0,"\t \r\n",&stmp2)) {
switch(fno) {
case 0: iface = f; break;
- case 1: destination = (uint32_t)Utils::hexStrToULong(f); break;
- case 2: gateway = (uint32_t)Utils::hexStrToULong(f); break;
+ case 1: target = (uint32_t)Utils::hexStrToULong(f); break;
+ case 2: via = (uint32_t)Utils::hexStrToULong(f); break;
case 6: metric = (int)Utils::strToInt(f); break;
case 7: mask = (uint32_t)Utils::hexStrToULong(f); break;
}
++fno;
}
- if ((iface)&&(destination)) {
+ if ((iface)&&(target)) {
RoutingTable::Entry e;
- if (destination)
- e.destination.set(&destination,4,Utils::countBits(mask));
- e.gateway.set(&gateway,4,0);
+ if (target)
+ e.target.set(&target,4,Utils::countBits(mask));
+ e.via.set(&via,4,0);
e.deviceIndex = 0; // not used on Linux
e.metric = metric;
Utils::scopy(e.device,sizeof(e.device),iface);
- if ((e.destination)&&((includeLinkLocal)||(!e.destination.isLinkLocal()))&&((includeLoopback)||((!e.destination.isLoopback())&&(!e.gateway.isLoopback())&&(strcmp(iface,"lo")))))
+ if ((e.target)&&((includeLinkLocal)||(!e.target.isLinkLocal()))&&((includeLoopback)||((!e.target.isLoopback())&&(!e.via.isLoopback())&&(strcmp(iface,"lo")))))
entries.push_back(e);
}
@@ -131,36 +131,36 @@ std::vector<RoutingTable::Entry> RoutingTable::get(bool includeLinkLocal,bool in
}
for(char *line=Utils::stok(buf,"\r\n",&stmp);(line);line=Utils::stok((char *)0,"\r\n",&stmp)) {
- char *destination = (char *)0;
+ char *target = (char *)0;
unsigned int destPrefixLen = 0;
- char *gateway = (char *)0; // next hop in ipv6 terminology
+ char *via = (char *)0; // next hop in ipv6 terminology
int metric = 0;
char *device = (char *)0;
int fno = 0;
for(char *f=Utils::stok(line,"\t \r\n",&stmp2);(f);f=Utils::stok((char *)0,"\t \r\n",&stmp2)) {
switch(fno) {
- case 0: destination = f; break;
+ case 0: target = f; break;
case 1: destPrefixLen = (unsigned int)Utils::hexStrToULong(f); break;
- case 4: gateway = f; break;
+ case 4: via = f; break;
case 5: metric = (int)Utils::hexStrToLong(f); break;
case 9: device = f; break;
}
++fno;
}
- if ((device)&&(destination)) {
+ if ((device)&&(target)) {
unsigned char tmp[16];
RoutingTable::Entry e;
- Utils::unhex(destination,tmp,16);
+ Utils::unhex(target,tmp,16);
if ((!Utils::isZero(tmp,16))&&(tmp[0] != 0xff))
- e.destination.set(tmp,16,destPrefixLen);
- Utils::unhex(gateway,tmp,16);
- e.gateway.set(tmp,16,0);
+ e.target.set(tmp,16,destPrefixLen);
+ Utils::unhex(via,tmp,16);
+ e.via.set(tmp,16,0);
e.deviceIndex = 0; // not used on Linux
e.metric = metric;
Utils::scopy(e.device,sizeof(e.device),device);
- if ((e.destination)&&((includeLinkLocal)||(!e.destination.isLinkLocal()))&&((includeLoopback)||((!e.destination.isLoopback())&&(!e.gateway.isLoopback())&&(strcmp(device,"lo")))))
+ if ((e.target)&&((includeLinkLocal)||(!e.target.isLinkLocal()))&&((includeLoopback)||((!e.target.isLoopback())&&(!e.via.isLoopback())&&(strcmp(device,"lo")))))
entries.push_back(e);
}
}
@@ -169,11 +169,11 @@ std::vector<RoutingTable::Entry> RoutingTable::get(bool includeLinkLocal,bool in
return entries;
}
-RoutingTable::Entry RoutingTable::set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric,bool ifscope)
+RoutingTable::Entry RoutingTable::set(const InetAddress &target,const InetAddress &via,const char *device,int metric,bool ifscope)
{
char metstr[128];
- if ((!gateway)&&((!device)||(!device[0])))
+ if ((!via)&&((!device)||(!device[0])))
return RoutingTable::Entry();
Utils::snprintf(metstr,sizeof(metstr),"%d",metric);
@@ -181,14 +181,14 @@ RoutingTable::Entry RoutingTable::set(const InetAddress &destination,const InetA
if (metric < 0) {
long pid = (long)vfork();
if (pid == 0) {
- if (gateway) {
+ if (via) {
if ((device)&&(device[0])) {
- ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","del",destination.toString().c_str(),"via",gateway.toIpString().c_str(),"dev",device,(const char *)0);
+ ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","del",target.toString().c_str(),"via",via.toIpString().c_str(),"dev",device,(const char *)0);
} else {
- ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","del",destination.toString().c_str(),"via",gateway.toIpString().c_str(),(const char *)0);
+ ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","del",target.toString().c_str(),"via",via.toIpString().c_str(),(const char *)0);
}
} else {
- ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","del",destination.toString().c_str(),"dev",device,(const char *)0);
+ ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","del",target.toString().c_str(),"dev",device,(const char *)0);
}
::_exit(-1);
} else if (pid > 0) {
@@ -198,14 +198,14 @@ RoutingTable::Entry RoutingTable::set(const InetAddress &destination,const InetA
} else {
long pid = (long)vfork();
if (pid == 0) {
- if (gateway) {
+ if (via) {
if ((device)&&(device[0])) {
- ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","replace",destination.toString().c_str(),"metric",metstr,"via",gateway.toIpString().c_str(),"dev",device,(const char *)0);
+ ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","replace",target.toString().c_str(),"metric",metstr,"via",via.toIpString().c_str(),"dev",device,(const char *)0);
} else {
- ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","replace",destination.toString().c_str(),"metric",metstr,"via",gateway.toIpString().c_str(),(const char *)0);
+ ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","replace",target.toString().c_str(),"metric",metstr,"via",via.toIpString().c_str(),(const char *)0);
}
} else {
- ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","replace",destination.toString().c_str(),"metric",metstr,"dev",device,(const char *)0);
+ ::execl(ZT_LINUX_IP_COMMAND,ZT_LINUX_IP_COMMAND,"route","replace",target.toString().c_str(),"metric",metstr,"dev",device,(const char *)0);
}
::_exit(-1);
} else if (pid > 0) {
@@ -217,7 +217,7 @@ RoutingTable::Entry RoutingTable::set(const InetAddress &destination,const InetA
std::vector<RoutingTable::Entry> rtab(get(true,true));
std::vector<RoutingTable::Entry>::iterator bestEntry(rtab.end());
for(std::vector<RoutingTable::Entry>::iterator e(rtab.begin());e!=rtab.end();++e) {
- if ((e->destination == destination)&&(e->gateway.ipsEqual(gateway))) {
+ if ((e->target == target)&&(e->via.ipsEqual(via))) {
if ((device)&&(device[0])) {
if (!strcmp(device,e->device)) {
if (metric == e->metric)
@@ -305,7 +305,7 @@ std::vector<RoutingTable::Entry> RoutingTable::get(bool includeLinkLocal,bool in
sin6->sin6_scope_id = interfaceIndex;
}
}
- e.destination = *sa;
+ e.target = *sa;
break;
case 1:
//printf("RTA_GATEWAY\n");
@@ -315,12 +315,12 @@ std::vector<RoutingTable::Entry> RoutingTable::get(bool includeLinkLocal,bool in
break;
case AF_INET:
case AF_INET6:
- e.gateway = *sa;
+ e.via = *sa;
break;
}
break;
case 2: {
- if (e.destination.isV6()) {
+ if (e.target.isV6()) {
salen = sizeof(struct sockaddr_in6); // Confess!
unsigned int bits = 0;
for(int i=0;i<16;++i) {
@@ -338,10 +338,10 @@ std::vector<RoutingTable::Entry> RoutingTable::get(bool includeLinkLocal,bool in
}
*/
}
- e.destination.setPort(bits);
+ e.target.setPort(bits);
} else {
salen = sizeof(struct sockaddr_in); // Confess!
- e.destination.setPort((unsigned int)Utils::countBits((uint32_t)((const struct sockaddr_in *)sa)->sin_addr.s_addr));
+ e.target.setPort((unsigned int)Utils::countBits((uint32_t)((const struct sockaddr_in *)sa)->sin_addr.s_addr));
}
//printf("RTA_NETMASK\n");
} break;
@@ -368,8 +368,8 @@ std::vector<RoutingTable::Entry> RoutingTable::get(bool includeLinkLocal,bool in
if (e.metric < 0)
e.metric = 0;
- InetAddress::IpScope dscope = e.destination.ipScope();
- if ( ((includeLinkLocal)||(dscope != InetAddress::IP_SCOPE_LINK_LOCAL)) && ((includeLoopback)||((dscope != InetAddress::IP_SCOPE_LOOPBACK) && (e.gateway.ipScope() != InetAddress::IP_SCOPE_LOOPBACK) )))
+ InetAddress::IpScope dscope = e.target.ipScope();
+ if ( ((includeLinkLocal)||(dscope != InetAddress::IP_SCOPE_LINK_LOCAL)) && ((includeLoopback)||((dscope != InetAddress::IP_SCOPE_LOOPBACK) && (e.via.ipScope() != InetAddress::IP_SCOPE_LOOPBACK) )))
entries.push_back(e);
}
@@ -386,10 +386,10 @@ std::vector<RoutingTable::Entry> RoutingTable::get(bool includeLinkLocal,bool in
if_indextoname(e1->deviceIndex,e1->device);
}
for(std::vector<ZeroTier::RoutingTable::Entry>::iterator e1(entries.begin());e1!=entries.end();++e1) {
- if ((!e1->device[0])&&(e1->gateway)) {
+ if ((!e1->device[0])&&(e1->via)) {
int bestMetric = 9999999;
for(std::vector<ZeroTier::RoutingTable::Entry>::iterator e2(entries.begin());e2!=entries.end();++e2) {
- if ((e2->destination.containsAddress(e1->gateway))&&(e2->metric <= bestMetric)) {
+ if ((e2->target.containsAddress(e1->via))&&(e2->metric <= bestMetric)) {
bestMetric = e2->metric;
Utils::scopy(e1->device,sizeof(e1->device),e2->device);
}
@@ -402,15 +402,15 @@ std::vector<RoutingTable::Entry> RoutingTable::get(bool includeLinkLocal,bool in
return entries;
}
-RoutingTable::Entry RoutingTable::set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric,bool ifscope)
+RoutingTable::Entry RoutingTable::set(const InetAddress &target,const InetAddress &via,const char *device,int metric,bool ifscope)
{
- if ((!gateway)&&((!device)||(!device[0])))
+ if ((!via)&&((!device)||(!device[0])))
return RoutingTable::Entry();
std::vector<RoutingTable::Entry> rtab(get(true,true));
for(std::vector<RoutingTable::Entry>::iterator e(rtab.begin());e!=rtab.end();++e) {
- if (e->destination == destination) {
+ if (e->target == target) {
if (((!device)||(!device[0]))||(!strcmp(device,e->device))) {
long p = (long)fork();
if (p > 0) {
@@ -419,7 +419,7 @@ RoutingTable::Entry RoutingTable::set(const InetAddress &destination,const InetA
} else if (p == 0) {
::close(STDOUT_FILENO);
::close(STDERR_FILENO);
- ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,"delete",(destination.isV6() ? "-inet6" : "-inet"),destination.toString().c_str(),(const char *)0);
+ ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,"delete",(target.isV6() ? "-inet6" : "-inet"),target.toString().c_str(),(const char *)0);
::_exit(-1);
}
}
@@ -439,10 +439,10 @@ RoutingTable::Entry RoutingTable::set(const InetAddress &destination,const InetA
} else if (p == 0) {
::close(STDOUT_FILENO);
::close(STDERR_FILENO);
- if (gateway) {
- ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,"add",(destination.isV6() ? "-inet6" : "-inet"),destination.toString().c_str(),gateway.toIpString().c_str(),"-hopcount",hcstr,(const char *)0);
+ if (via) {
+ ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,"add",(target.isV6() ? "-inet6" : "-inet"),target.toString().c_str(),via.toIpString().c_str(),"-hopcount",hcstr,(const char *)0);
} else if ((device)&&(device[0])) {
- ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,"add",(destination.isV6() ? "-inet6" : "-inet"),destination.toString().c_str(),"-interface",device,"-hopcount",hcstr,(const char *)0);
+ ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,"add",(target.isV6() ? "-inet6" : "-inet"),target.toString().c_str(),"-interface",device,"-hopcount",hcstr,(const char *)0);
}
::_exit(-1);
}
@@ -451,7 +451,7 @@ RoutingTable::Entry RoutingTable::set(const InetAddress &destination,const InetA
rtab = get(true,true);
std::vector<RoutingTable::Entry>::iterator bestEntry(rtab.end());
for(std::vector<RoutingTable::Entry>::iterator e(rtab.begin());e!=rtab.end();++e) {
- if ((e->destination == destination)&&(e->gateway.ipsEqual(gateway))) {
+ if ((e->target == target)&&(e->via.ipsEqual(via))) {
if ((device)&&(device[0])) {
if (!strcmp(device,e->device)) {
if (metric == e->metric)
@@ -502,24 +502,24 @@ std::vector<RoutingTable::Entry> RoutingTable::get(bool includeLinkLocal,bool in
RoutingTable::Entry e;
switch(rtbl->Table[r].DestinationPrefix.Prefix.si_family) {
case AF_INET:
- e.destination.set(&(rtbl->Table[r].DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr),4,rtbl->Table[r].DestinationPrefix.PrefixLength);
+ e.target.set(&(rtbl->Table[r].DestinationPrefix.Prefix.Ipv4.sin_addr.S_un.S_addr),4,rtbl->Table[r].DestinationPrefix.PrefixLength);
break;
case AF_INET6:
- e.destination.set(rtbl->Table[r].DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte,16,rtbl->Table[r].DestinationPrefix.PrefixLength);
+ e.target.set(rtbl->Table[r].DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte,16,rtbl->Table[r].DestinationPrefix.PrefixLength);
break;
}
switch(rtbl->Table[r].NextHop.si_family) {
case AF_INET:
- e.gateway.set(&(rtbl->Table[r].NextHop.Ipv4.sin_addr.S_un.S_addr),4,0);
+ e.via.set(&(rtbl->Table[r].NextHop.Ipv4.sin_addr.S_un.S_addr),4,0);
break;
case AF_INET6:
- e.gateway.set(rtbl->Table[r].NextHop.Ipv6.sin6_addr.u.Byte,16,0);
+ e.via.set(rtbl->Table[r].NextHop.Ipv6.sin6_addr.u.Byte,16,0);
break;
}
e.deviceIndex = (int)rtbl->Table[r].InterfaceIndex;
e.metric = (int)rtbl->Table[r].Metric;
ConvertInterfaceLuidToNameA(&(rtbl->Table[r].InterfaceLuid),e.device,sizeof(e.device));
- if ((e.destination)&&((includeLinkLocal)||(!e.destination.isLinkLocal()))&&((includeLoopback)||((!e.destination.isLoopback())&&(!e.gateway.isLoopback()))))
+ if ((e.target)&&((includeLinkLocal)||(!e.target.isLinkLocal()))&&((includeLoopback)||((!e.target.isLoopback())&&(!e.via.isLoopback()))))
entries.push_back(e);
}
@@ -528,7 +528,7 @@ std::vector<RoutingTable::Entry> RoutingTable::get(bool includeLinkLocal,bool in
return entries;
}
-RoutingTable::Entry RoutingTable::set(const InetAddress &destination,const InetAddress &gateway,const char *device,int metric,bool ifscope)
+RoutingTable::Entry RoutingTable::set(const InetAddress &target,const InetAddress &via,const char *device,int metric,bool ifscope)
{
NET_LUID luid;
luid.Value = 0;
@@ -552,9 +552,9 @@ RoutingTable::Entry RoutingTable::set(const InetAddress &destination,const InetA
rdest.set(rtbl->Table[r].DestinationPrefix.Prefix.Ipv6.sin6_addr.u.Byte,16,rtbl->Table[r].DestinationPrefix.PrefixLength);
break;
}
- if (rdest == destination) {
+ if (rdest == target) {
if (metric >= 0) {
- _copyInetAddressToSockaddrInet(gateway,rtbl->Table[r].NextHop);
+ _copyInetAddressToSockaddrInet(via,rtbl->Table[r].NextHop);
rtbl->Table[r].Metric = metric;
SetIpForwardEntry2(&(rtbl->Table[r]));
needCreate = false;
@@ -572,9 +572,9 @@ RoutingTable::Entry RoutingTable::set(const InetAddress &destination,const InetA
MIB_IPFORWARD_ROW2 nr;
InitializeIpForwardEntry(&nr);
nr.InterfaceLuid.Value = luid.Value;
- _copyInetAddressToSockaddrInet(destination,nr.DestinationPrefix.Prefix);
- nr.DestinationPrefix.PrefixLength = destination.netmaskBits();
- _copyInetAddressToSockaddrInet(gateway,nr.NextHop);
+ _copyInetAddressToSockaddrInet(target,nr.DestinationPrefix.Prefix);
+ nr.DestinationPrefix.PrefixLength = target.netmaskBits();
+ _copyInetAddressToSockaddrInet(via,nr.NextHop);
nr.Metric = metric;
nr.Protocol = MIB_IPPROTO_NETMGMT;
DWORD result = CreateIpForwardEntry2(&nr);
@@ -585,7 +585,7 @@ RoutingTable::Entry RoutingTable::set(const InetAddress &destination,const InetA
std::vector<RoutingTable::Entry> rtab(get(true,true));
std::vector<RoutingTable::Entry>::iterator bestEntry(rtab.end());
for(std::vector<RoutingTable::Entry>::iterator e(rtab.begin());e!=rtab.end();++e) {
- if ((e->destination == destination)&&(e->gateway.ipsEqual(gateway))) {
+ if ((e->target == target)&&(e->via.ipsEqual(via))) {
if ((device)&&(device[0])) {
if (!strcmp(device,e->device)) {
if (metric == e->metric)
diff --git a/osdep/RoutingTable.hpp b/attic/RoutingTable.hpp
index 71ca006d..69155c00 100644
--- a/osdep/RoutingTable.hpp
+++ b/attic/RoutingTable.hpp
@@ -34,12 +34,12 @@ public:
/**
* Destination IP and netmask bits (CIDR format)
*/
- InetAddress destination;
+ InetAddress target;
/**
* Gateway or null address if direct link-level route, netmask/port part of InetAddress not used
*/
- InetAddress gateway;
+ InetAddress via;
/**
* Metric or hop count -- higher = lower routing priority
diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp
index b60a5a3a..1d171ba7 100644
--- a/node/InetAddress.hpp
+++ b/node/InetAddress.hpp
@@ -231,7 +231,6 @@ struct InetAddress : public sockaddr_storage
* @param port Port, 0 to 65535
*/
inline void setPort(unsigned int port)
- throw()
{
switch(ss_family) {
case AF_INET:
@@ -244,6 +243,25 @@ struct InetAddress : public sockaddr_storage
}
/**
+ * @return True if this network/netmask route describes a default route (e.g. 0.0.0.0/0)
+ */
+ inline bool isDefaultRoute()
+ {
+ switch(ss_family) {
+ case AF_INET:
+ return ( (reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr == 0) && (reinterpret_cast<struct sockaddr_in *>(this)->sin_port == 0) );
+ case AF_INET6:
+ const uint8_t *ipb = reinterpret_cast<const uint8_t *>(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
+ for(int i=0;i<16;++i) {
+ if (ipb[i])
+ return false;
+ }
+ return (reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_port == 0);
+ }
+ return false;
+ }
+
+ /**
* @return ASCII IP/port format representation
*/
std::string toString() const;
diff --git a/node/Utils.hpp b/node/Utils.hpp
index 3f4cc765..04838f1c 100644
--- a/node/Utils.hpp
+++ b/node/Utils.hpp
@@ -225,18 +225,24 @@ public:
}
/**
- * Perform a safe C string copy
+ * Perform a safe C string copy, ALWAYS null-terminating the result
*
- * @param dest Destination buffer
- * @param len Length of buffer
- * @param src Source string
+ * This will never ever EVER result in dest[] not being null-terminated
+ * regardless of any input parameter (other than len==0 which is invalid).
+ *
+ * @param dest Destination buffer (must not be NULL)
+ * @param len Length of dest[] (if zero, false is returned and nothing happens)
+ * @param src Source string (if NULL, dest will receive a zero-length string and true is returned)
* @return True on success, false on overflow (buffer will still be 0-terminated)
*/
static inline bool scopy(char *dest,unsigned int len,const char *src)
- throw()
{
if (!len)
return false; // sanity check
+ if (!src) {
+ *dest = (char)0;
+ return true;
+ }
char *end = dest + len;
while ((*dest++ = *src++)) {
if (dest == end) {
diff --git a/objects.mk b/objects.mk
index a281c97e..24b7fdfa 100644
--- a/objects.mk
+++ b/objects.mk
@@ -23,6 +23,7 @@ OBJS=\
node/Topology.o \
node/Utils.o \
osdep/BackgroundResolver.o \
+ osdep/ManagedRoute.o \
osdep/Http.o \
osdep/OSUtils.o \
service/ClusterGeoIpService.o \
diff --git a/osdep/ManagedRoute.cpp b/osdep/ManagedRoute.cpp
new file mode 100644
index 00000000..c31f6dd0
--- /dev/null
+++ b/osdep/ManagedRoute.cpp
@@ -0,0 +1,456 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "../node/Constants.hpp"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __WINDOWS__
+#include <WinSock2.h>
+#include <Windows.h>
+#include <netioapi.h>
+#include <IPHlpApi.h>
+#endif
+
+#ifdef __UNIX_LIKE__
+#include <unistd.h>
+#include <sys/param.h>
+#include <sys/sysctl.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/route.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <ifaddrs.h>
+#endif
+
+#include <vector>
+#include <algorithm>
+#include <utility>
+
+#include "ManagedRoute.hpp"
+
+#define ZT_BSD_ROUTE_CMD "/sbin/route"
+#define ZT_LINUX_IP_COMMAND "/sbin/ip"
+
+namespace ZeroTier {
+
+namespace {
+
+// Fork a target into two more specific targets e.g. 0.0.0.0/0 -> 0.0.0.0/1, 128.0.0.0/1
+// If the target is already maximally-specific, 'right' will be unchanged and 'left' will be 't'
+static void _forkTarget(const InetAddress &t,InetAddress &left,InetAddress &right)
+{
+ const unsigned int bits = t.netmaskBits() + 1;
+ left = t;
+ if ((t.ss_family == AF_INET)&&(bits <= 32)) {
+ left.setPort(bits);
+ right = t;
+ reinterpret_cast<struct sockaddr_in *>(&right)->sin_addr.s_addr ^= Utils::hton((uint32_t)(1 << (32 - bits)));
+ right.setPort(bits);
+ } else if ((t.ss_family == AF_INET6)&&(bits <= 128)) {
+ left.setPort(bits);
+ right = t;
+ uint8_t *b = reinterpret_cast<uint8_t *>(reinterpret_cast<struct sockaddr_in6 *>(&right)->sin6_addr.s6_addr);
+ b[bits / 8] ^= 1 << (8 - (bits % 8));
+ right.setPort(bits);
+ }
+}
+
+#ifdef __BSD__ // ------------------------------------------------------------
+#define ZT_ROUTING_SUPPORT_FOUND 1
+
+struct _RTE
+{
+ InetAddress target;
+ InetAddress via;
+ char device[128];
+ int metric;
+ bool ifscope;
+};
+
+static std::vector<_RTE> _getRTEs(const InetAddress &target,bool contains)
+{
+ std::vector<_RTE> rtes;
+ int mib[6];
+ size_t needed;
+
+ mib[0] = CTL_NET;
+ mib[1] = PF_ROUTE;
+ mib[2] = 0;
+ mib[3] = 0;
+ mib[4] = NET_RT_DUMP;
+ mib[5] = 0;
+ if (!sysctl(mib,6,NULL,&needed,NULL,0)) {
+ if (needed <= 0)
+ return rtes;
+
+ char *buf = (char *)::malloc(needed);
+ if (buf) {
+ if (!sysctl(mib,6,buf,&needed,NULL,0)) {
+ struct rt_msghdr *rtm;
+ for(char *next=buf,*end=buf+needed;next<end;) {
+ rtm = (struct rt_msghdr *)next;
+ char *saptr = (char *)(rtm + 1);
+ char *saend = next + rtm->rtm_msglen;
+
+ InetAddress sa_t,sa_v;
+ int deviceIndex = -9999;
+
+ if (((rtm->rtm_flags & RTF_LLINFO) == 0)&&((rtm->rtm_flags & RTF_HOST) == 0)&&((rtm->rtm_flags & RTF_UP) != 0)&&((rtm->rtm_flags & RTF_MULTICAST) == 0)) {
+ int which = 0;
+ while (saptr < saend) {
+ struct sockaddr *sa = (struct sockaddr *)saptr;
+ unsigned int salen = sa->sa_len;
+ if (!salen)
+ break;
+
+ // Skip missing fields in rtm_addrs bit field
+ while ((rtm->rtm_addrs & 1) == 0) {
+ rtm->rtm_addrs >>= 1;
+ ++which;
+ if (which > 6)
+ break;
+ }
+ if (which > 6)
+ break;
+
+ rtm->rtm_addrs >>= 1;
+ switch(which++) {
+ case 0:
+ //printf("RTA_DST\n");
+ if (sa->sa_family == AF_INET6) {
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
+ if ((sin6->sin6_addr.s6_addr[0] == 0xfe)&&((sin6->sin6_addr.s6_addr[1] & 0xc0) == 0x80)) {
+ // BSD uses this fucking strange in-band signaling method to encode device scope IDs for IPv6 addresses... probably a holdover from very early versions of the spec.
+ unsigned int interfaceIndex = ((((unsigned int)sin6->sin6_addr.s6_addr[2]) << 8) & 0xff) | (((unsigned int)sin6->sin6_addr.s6_addr[3]) & 0xff);
+ sin6->sin6_addr.s6_addr[2] = 0;
+ sin6->sin6_addr.s6_addr[3] = 0;
+ if (!sin6->sin6_scope_id)
+ sin6->sin6_scope_id = interfaceIndex;
+ }
+ }
+ sa_t = *sa;
+ break;
+ case 1:
+ //printf("RTA_GATEWAY\n");
+ switch(sa->sa_family) {
+ case AF_LINK:
+ deviceIndex = (int)((const struct sockaddr_dl *)sa)->sdl_index;
+ break;
+ case AF_INET:
+ case AF_INET6:
+ sa_v = *sa;
+ break;
+ }
+ break;
+ case 2: {
+ //printf("RTA_NETMASK\n");
+ if (sa_t.ss_family == AF_INET6) {
+ salen = sizeof(struct sockaddr_in6);
+ unsigned int bits = 0;
+ for(int i=0;i<16;++i) {
+ unsigned char c = (unsigned char)((const struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[i];
+ if (c == 0xff)
+ bits += 8;
+ else break;
+ }
+ sa_t.setPort(bits);
+ } else if (sa_t.ss_family == AF_INET) {
+ salen = sizeof(struct sockaddr_in);
+ sa_t.setPort((unsigned int)Utils::countBits((uint32_t)((const struct sockaddr_in *)sa)->sin_addr.s_addr));
+ }
+ } break;
+ /*
+ case 3:
+ //printf("RTA_GENMASK\n");
+ break;
+ case 4:
+ //printf("RTA_IFP\n");
+ break;
+ case 5:
+ //printf("RTA_IFA\n");
+ break;
+ case 6:
+ //printf("RTA_AUTHOR\n");
+ break;
+ */
+ }
+
+ saptr += salen;
+ }
+
+ if (((contains)&&(sa_t.containsAddress(target)))||(sa_t == target)) {
+ rtes.push_back(_RTE());
+ rtes.back().target = sa_t;
+ rtes.back().via = sa_v;
+ if (deviceIndex >= 0) {
+ if_indextoname(deviceIndex,rtes.back().device);
+ } else {
+ rtes.back().device[0] = (char)0;
+ }
+ rtes.back().metric = ((int)rtm->rtm_rmx.rmx_hopcount < 0) ? 0 : (int)rtm->rtm_rmx.rmx_hopcount;
+ }
+ }
+
+ next = saend;
+ }
+ }
+
+ ::free(buf);
+ }
+ }
+
+ return rtes;
+}
+
+static void _routeCmd(const char *op,const InetAddress &target,const InetAddress &via,const char *ifscope,const char *localInterface)
+{
+ long p = (long)fork();
+ if (p > 0) {
+ int exitcode = -1;
+ ::waitpid(p,&exitcode,0);
+ } else if (p == 0) {
+ //::close(STDOUT_FILENO);
+ //::close(STDERR_FILENO);
+ if (via) {
+ if ((ifscope)&&(ifscope[0])) {
+ ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString().c_str(),via.toIpString().c_str(),(const char *)0);
+ } else {
+ ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString().c_str(),via.toIpString().c_str(),(const char *)0);
+ }
+ } else if ((localInterface)&&(localInterface[0])) {
+ if ((ifscope)&&(ifscope[0])) {
+ ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,"-ifscope",ifscope,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString().c_str(),"-interface",localInterface,(const char *)0);
+ } else {
+ ::execl(ZT_BSD_ROUTE_CMD,ZT_BSD_ROUTE_CMD,op,((target.ss_family == AF_INET6) ? "-inet6" : "-inet"),target.toString().c_str(),"-interface",localInterface,(const char *)0);
+ }
+ }
+ ::_exit(-1);
+ }
+}
+
+#endif // __BSD__ ------------------------------------------------------------
+
+#ifdef __LINUX__ // ----------------------------------------------------------
+#define ZT_ROUTING_SUPPORT_FOUND 1
+
+#endif // __LINUX__ ----------------------------------------------------------
+
+#ifdef __WINDOWS__ // --------------------------------------------------------
+#define ZT_ROUTING_SUPPORT_FOUND 1
+
+#endif // __WINDOWS__ --------------------------------------------------------
+
+} // anonymous namespace
+
+bool ManagedRoute::sync()
+{
+ if (this->target.isDefaultRoute()) {
+ /* In ZeroTier we use a forked-route trick to override the default
+ * with a more specific one while leaving the original system route
+ * intact. We also create a shadow more specific route to the
+ * original gateway that is device-bound so that ZeroTier's device
+ * bound ports go via the physical Internet link. This has to be
+ * done *slightly* differently on different platforms. */
+
+ InetAddress leftt,rightt;
+ _forkTarget(this->target,leftt,rightt);
+
+#ifdef __BSD__ // ------------------------------------------------------------
+
+ InetAddress systemVia;
+ char systemDevice[128];
+ int systemMetric = 9999999;
+ systemDevice[0] = (char)0;
+
+ std::vector<_RTE> rtes(_getRTEs(this->target,false));
+ for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) {
+ if (r->via) {
+ if ((!systemVia)||(r->metric < systemMetric)) {
+ systemVia = r->via;
+ Utils::scopy(systemDevice,sizeof(systemDevice),r->device);
+ systemMetric = r->metric;
+ }
+ }
+ }
+
+ if (!systemDevice[0]) {
+ rtes = _getRTEs(systemVia,true);
+ for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) {
+ if (r->device[0])
+ Utils::scopy(systemDevice,sizeof(systemDevice),r->device);
+ }
+ }
+
+ if ((!systemVia)||(!systemDevice[0]))
+ return false;
+
+ _routeCmd("add",leftt,systemVia,systemDevice,(const char *)0);
+ _routeCmd("change",leftt,systemVia,systemDevice,(const char *)0);
+ _routeCmd("add",rightt,systemVia,systemDevice,(const char *)0);
+ _routeCmd("change",rightt,systemVia,systemDevice,(const char *)0);
+
+ if (this->via) {
+ _routeCmd("add",leftt,this->via,(const char *)0,(const char *)0);
+ _routeCmd("change",leftt,this->via,(const char *)0,(const char *)0);
+ _routeCmd("add",rightt,this->via,(const char *)0,(const char *)0);
+ _routeCmd("change",rightt,this->via,(const char *)0,(const char *)0);
+ } else if ((this->device)&&(this->device[0])) {
+ _routeCmd("add",leftt,this->via,(const char *)0,this->device);
+ _routeCmd("change",leftt,this->via,(const char *)0,this->device);
+ _routeCmd("add",rightt,this->via,(const char *)0,this->device);
+ _routeCmd("change",rightt,this->via,(const char *)0,this->device);
+ }
+
+#endif // __BSD__ ------------------------------------------------------------
+
+#ifdef __LINUX__ // ----------------------------------------------------------
+
+#endif // __LINUX__ ----------------------------------------------------------
+
+#ifdef __WINDOWS__ // --------------------------------------------------------
+
+#endif // __WINDOWS__ --------------------------------------------------------
+
+ } else {
+
+ // TODO
+
+#ifdef __BSD__ // ------------------------------------------------------------
+
+#endif // __BSD__ ------------------------------------------------------------
+
+#ifdef __LINUX__ // ----------------------------------------------------------
+
+#endif // __LINUX__ ----------------------------------------------------------
+
+#ifdef __WINDOWS__ // --------------------------------------------------------
+
+#endif // __WINDOWS__ --------------------------------------------------------
+
+ }
+
+ return true;
+}
+
+void ManagedRoute::remove()
+{
+ if (!this->applied)
+ return;
+
+ if (this->target.isDefaultRoute()) {
+ /* In ZeroTier we use a forked-route trick to override the default
+ * with a more specific one while leaving the original system route
+ * intact. We also create a shadow more specific route to the
+ * original gateway that is device-bound so that ZeroTier's device
+ * bound ports go via the physical Internet link. This has to be
+ * done *slightly* differently on different platforms. */
+
+ InetAddress leftt,rightt;
+ _forkTarget(this->target,leftt,rightt);
+
+#ifdef __BSD__ // ------------------------------------------------------------
+
+ InetAddress systemVia;
+ char systemDevice[128];
+ int systemMetric = 9999999;
+ systemDevice[0] = (char)0;
+
+ std::vector<_RTE> rtes(_getRTEs(this->target,false));
+ for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) {
+ if (r->via) {
+ if ((!systemVia)||(r->metric < systemMetric)) {
+ systemVia = r->via;
+ Utils::scopy(systemDevice,sizeof(systemDevice),r->device);
+ systemMetric = r->metric;
+ }
+ }
+ }
+
+ if (!systemDevice[0]) {
+ rtes = _getRTEs(systemVia,true);
+ for(std::vector<_RTE>::iterator r(rtes.begin());r!=rtes.end();++r) {
+ if (r->device[0])
+ Utils::scopy(systemDevice,sizeof(systemDevice),r->device);
+ }
+ }
+
+ if ((!systemVia)||(!systemDevice[0]))
+ return false;
+
+ _routeCmd("delete",leftt,systemVia,systemDevice,(const char *)0);
+ _routeCmd("delete",rightt,systemVia,systemDevice,(const char *)0);
+
+ if (this->via) {
+ _routeCmd("delete",leftt,this->via,(const char *)0,(const char *)0);
+ _routeCmd("delete",rightt,this->via,(const char *)0,(const char *)0);
+ } else if ((this->device)&&(this->device[0])) {
+ _routeCmd("delete",leftt,this->via,(const char *)0,this->device);
+ _routeCmd("delete",rightt,this->via,(const char *)0,this->device);
+ }
+
+#endif // __BSD__ ------------------------------------------------------------
+
+#ifdef __LINUX__ // ----------------------------------------------------------
+
+#endif // __LINUX__ ----------------------------------------------------------
+
+#ifdef __WINDOWS__ // --------------------------------------------------------
+
+#endif // __WINDOWS__ --------------------------------------------------------
+
+ } else {
+
+ // TODO
+
+#ifdef __BSD__ // ------------------------------------------------------------
+
+#endif // __BSD__ ------------------------------------------------------------
+
+#ifdef __LINUX__ // ----------------------------------------------------------
+
+#endif // __LINUX__ ----------------------------------------------------------
+
+#ifdef __WINDOWS__ // --------------------------------------------------------
+
+#endif // __WINDOWS__ --------------------------------------------------------
+
+ }
+}
+
+} // namespace ZeroTier
+
+#ifndef ZT_ROUTING_SUPPORT_FOUND
+#error ManagedRoute.cpp has no support for managing routes on this platform! You'll need to check and see if one of the existing ones will work and make sure proper defines are set, or write one. Please do a Github pull request if you do this for a new OS!
+#endif
+
+/*
+int main(int argc,char **argv)
+{
+ ZeroTier::ManagedRoute t;
+ t.set(ZeroTier::InetAddress("0.0.0.0/0"),ZeroTier::InetAddress("10.6.6.112"),"zt2");
+ sleep(10000);
+}
+*/
diff --git a/osdep/ManagedRoute.hpp b/osdep/ManagedRoute.hpp
new file mode 100644
index 00000000..081d516d
--- /dev/null
+++ b/osdep/ManagedRoute.hpp
@@ -0,0 +1,95 @@
+#ifndef ZT_MANAGEDROUTE_HPP
+#define ZT_MANAGEDROUTE_HPP
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "../node/InetAddress.hpp"
+#include "../node/Utils.hpp"
+
+#include <stdexcept>
+#include <vector>
+
+namespace ZeroTier {
+
+/**
+ * A ZT-managed route that used C++ RAII semantics to automatically clean itself up on deallocate
+ */
+class ManagedRoute
+{
+public:
+ ManagedRoute() :
+ target(),
+ via(),
+ applied(false)
+ {
+ device[0] = (char)0;
+ }
+
+ ~ManagedRoute()
+ {
+ this->remove();
+ }
+
+ /**
+ * @param target Route target (e.g. 0.0.0.0/0 for default)
+ * @param via Route next L3 hop or NULL InetAddress if local
+ * @param device Device name/ID if 'via' is null and route is local, otherwise ignored
+ * @return True if route was successfully set
+ */
+ inline bool set(const InetAddress &target,const InetAddress &via,const char *device)
+ {
+ if ((!via)&&((!device)||(!device[0])))
+ return false;
+ this->remove();
+ this->target = target;
+ this->via = via;
+ this->applied = true;
+ Utils::scopy(this->device,sizeof(this->device),device);
+ return this->sync();
+ }
+
+ /**
+ * Set or update currently set route
+ *
+ * This must be called periodically for routes that shadow others so that
+ * shadow routes can be updated. In some cases it has no effect
+ *
+ * @return True if route add/update was successful
+ */
+ bool sync();
+
+ /**
+ * Remove and clear this ManagedRoute (also done automatically on destruct)
+ *
+ * This does nothing if this ManagedRoute is not set or has already been removed.
+ */
+ void remove();
+
+private:
+ /*
+ static inline bool _viaCompare(const InetAddress &v1,const InetAddress &v2)
+ {
+ if (v1) {
+ if (v2)
+ return v1.ipsEqual(v2);
+ else return false;
+ } else if (v2)
+ return false;
+ else return true;
+ }
+ */
+
+ // non-copyable
+ ManagedRoute(const ManagedRoute &mr) {}
+ inline ManagedRoute &operator=(const ManagedRoute &mr) { return *this; }
+
+ InetAddress target;
+ InetAddress via;
+ bool applied;
+ char device[128];
+};
+
+} // namespace ZeroTier
+
+#endif
diff --git a/service/OneService.cpp b/service/OneService.cpp
index f8d35a66..da440aff 100644
--- a/service/OneService.cpp
+++ b/service/OneService.cpp
@@ -51,6 +51,7 @@
#include "../osdep/BackgroundResolver.hpp"
#include "../osdep/PortMapper.hpp"
#include "../osdep/Binder.hpp"
+#include "../osdep/RoutingTable.hpp"
#include "OneService.hpp"
#include "ControlPlane.hpp"
@@ -522,11 +523,14 @@ public:
// Configured networks
struct NetworkState
{
- NetworkState() : tap((EthernetTap *)0),managedIps(),managedRoutes() {}
+ NetworkState() : tap((EthernetTap *)0),managedIps(),managedRoutes(),allowManaged(true),allowGlobal(true),allowDefault(true) {}
EthernetTap *tap;
std::vector<InetAddress> managedIps;
- std::vector<InetAddress> managedRoutes; // by 'target'
+ std::vector< std::pair<InetAddress,InetAddress> > managedRoutes; // target/via (flags and metric not currently used)
+ bool allowManaged; // allow managed addresses and routes
+ bool allowGlobal; // allow global (non-private) IP routes?
+ bool allowDefault; // allow default route?
};
std::map<uint64_t,NetworkState> _nets;
Mutex _nets_m;
@@ -1252,25 +1256,85 @@ public:
case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE:
if (n.tap) { // sanity check
- std::vector<InetAddress> newManagedIps;
- for(unsigned int i=0;i<nwc->assignedAddressCount;++i)
- newManagedIps.push_back(*(reinterpret_cast<const InetAddress *>(&(nwc->assignedAddresses[i]))));
- std::sort(newManagedIps.begin(),newManagedIps.end());
- newManagedIps.erase(std::unique(newManagedIps.begin(),newManagedIps.end()),newManagedIps.end());
-
- for(std::vector<InetAddress>::iterator ip(newManagedIps.begin());ip!=newManagedIps.end();++ip) {
- if (!std::binary_search(n.managedIps.begin(),n.managedIps.end(),*ip))
- if (!n.tap->addIp(*ip))
- fprintf(stderr,"ERROR: unable to add ip address %s"ZT_EOL_S, ip->toString().c_str());
- }
+ if (n.allowManaged) {
+ { // configure managed IP addresses
+ std::vector<InetAddress> newManagedIps;
+ for(unsigned int i=0;i<nwc->assignedAddressCount;++i) {
+ const InetAddress *ii = reinterpret_cast<const InetAddress *>(&(nwc->assignedAddresses[i]));
+ switch(ii->ipScope()) {
+ case IP_SCOPE_NONE:
+ case IP_SCOPE_MULTICAST:
+ case IP_SCOPE_LOOPBACK:
+ case IP_SCOPE_LINK_LOCAL:
+ break; // ignore these -- they shouldn't appear here
+ case IP_SCOPE_GLOBAL:
+ if (!n.allowGlobal)
+ continue; // skip global IP ranges if we haven't given this network permission to assign them
+ // else fall through for PSEUDOPRIVATE, SHARED, PRIVATE
+ default:
+ newManagedIps.push_back(*ii);
+ break;
+ }
+ }
+ std::sort(newManagedIps.begin(),newManagedIps.end());
+ newManagedIps.erase(std::unique(newManagedIps.begin(),newManagedIps.end()),newManagedIps.end());
- for(std::vector<InetAddress>::iterator ip(n.managedIps.begin());ip!=n.managedIps.end();++ip) {
- if (!std::binary_search(newManagedIps.begin(),newManagedIps.end(),*ip))
- if (!n.tap->removeIp(*ip))
- fprintf(stderr,"ERROR: unable to remove ip address %s"ZT_EOL_S, ip->toString().c_str());
- }
+ for(std::vector<InetAddress>::iterator ip(newManagedIps.begin());ip!=newManagedIps.end();++ip) {
+ if (std::find(n.managedIps.begin(),n.managedIps.end(),*ip) == n.managedIps.end()) {
+ if (!n.tap->addIp(*ip))
+ fprintf(stderr,"ERROR: unable to add ip address %s"ZT_EOL_S, ip->toString().c_str());
+ }
+ }
+ for(std::vector<InetAddress>::iterator ip(n.managedIps.begin());ip!=n.managedIps.end();++ip) {
+ if (std::find(newManagedIps.begin(),newManagedIps.end(),*ip) == newManagedIps.end()) {
+ if (!n.tap->removeIp(*ip))
+ fprintf(stderr,"ERROR: unable to remove ip address %s"ZT_EOL_S, ip->toString().c_str());
+ }
+ }
+
+ n.managedIps.swap(newManagedIps);
+ }
+ { // configure managed routes
+ std::vector< std::pair<InetAddress,InetAddress> > newManagedRoutes;
+ for(unsigned int i=0;i<nwc->routeCount;++i) {
+ const InetAddress *target = reinterpret_cast<const InetAddress *>(&(nwc->routes[i].target));
+ const InetAddress *via = reinterpret_cast<const InetAddress *>(&(nwc->routes[i].via));
+ if ((target->isDefaultRoute())&&(n.allowDefault)) {
+ newManagedRoutes.push_back(std::pair<InetAddress,InetAddress>(*target,*via));
+ } else {
+ switch(target->ipScope()) {
+ case IP_SCOPE_NONE:
+ case IP_SCOPE_MULTICAST:
+ case IP_SCOPE_LOOPBACK:
+ case IP_SCOPE_LINK_LOCAL:
+ break;
+ case IP_SCOPE_GLOBAL:
+ if (!n.allowGlobal)
+ continue; // skip global IP ranges if we haven't given this network permission to assign them
+ // else fall through for PSEUDOPRIVATE, SHARED, PRIVATE
+ default:
+ newManagedRoutes.push_back(std::pair<InetAddress,InetAddress>(*target,*via));
+ break;
+ }
+ }
+ }
+ std::sort(newManagedRoutes.begin(),newManagedRoutes.end());
+ newManagedRoutes.erase(std::unique(newManagedRoutes.begin(),newManagedRoutes.end()),newManagedRoutes.end());
+
+ for(std::vector< std::pair<InetAddress,InetAddress> >::iterator mr(newManagedRoutes.begin()),mr!=newManagedRoutes.end();++mr) {
+ if (std::find(n.managedRoutes.begin(),n.managedRoutes.end(),*mr) == n.managedRoutes.end()) {
+ printf("ADDING ROUTE: %s -> %s\n",mr->first.toString().c_str(),mr->second.toString().c_str());
+ }
+ }
+ for(std::vector< std::pair<InetAddress,InetAddress> >::iterator mr(n.managedRoutes.begin());mr!=n.managedRoutes.end();++mr) {
+ if (std::find(newManagedRoutes.begin(),newManagedRoutes.end(),*mr) != newManagedRoutes.end()) {
+ printf("REMOVING ROUTE: %s -> %s\n",mr->first.toString().c_str(),mr->second.toString().c_str());
+ }
+ }
- n.managedIps.swap(newManagedIps); // faster than assign -- just swap pointers and let the old one die
+ n.managedRoutes.swap(newManagedRoutes);
+ }
+ }
} else {
_nets.erase(nwid);
return -999; // tap init failed