|
|
|
|
@ -485,7 +485,7 @@ public:
|
|
|
|
|
Node *_node; |
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* To properly handle NAT/gateway craziness we use three local UDP ports: |
|
|
|
|
* To attempt to handle NAT/gateway craziness we use three local UDP ports: |
|
|
|
|
* |
|
|
|
|
* [0] is the normal/default port, usually 9993 |
|
|
|
|
* [1] is a port dervied from our ZeroTier address |
|
|
|
|
@ -519,10 +519,17 @@ public:
|
|
|
|
|
// Deadline for the next background task service function
|
|
|
|
|
volatile uint64_t _nextBackgroundTaskDeadline; |
|
|
|
|
|
|
|
|
|
// Tap devices by network ID
|
|
|
|
|
std::map< uint64_t,EthernetTap * > _taps; |
|
|
|
|
std::map< uint64_t,std::vector<InetAddress> > _tapAssignedIps; // ZeroTier assigned IPs, not user or dhcp assigned
|
|
|
|
|
Mutex _taps_m; |
|
|
|
|
// Configured networks
|
|
|
|
|
struct NetworkState |
|
|
|
|
{ |
|
|
|
|
NetworkState() : tap((EthernetTap *)0),managedIps(),managedRoutes() {} |
|
|
|
|
|
|
|
|
|
EthernetTap *tap; |
|
|
|
|
std::vector<InetAddress> managedIps; |
|
|
|
|
std::vector<InetAddress> managedRoutes; // by 'target'
|
|
|
|
|
}; |
|
|
|
|
std::map<uint64_t,NetworkState> _nets; |
|
|
|
|
Mutex _nets_m; |
|
|
|
|
|
|
|
|
|
// Active TCP/IP connections
|
|
|
|
|
std::set< TcpConnection * > _tcpConnections; // no mutex for this since it's done in the main loop thread only
|
|
|
|
|
@ -872,14 +879,16 @@ public:
|
|
|
|
|
|
|
|
|
|
if ((now - lastTapMulticastGroupCheck) >= ZT_TAP_CHECK_MULTICAST_INTERVAL) { |
|
|
|
|
lastTapMulticastGroupCheck = now; |
|
|
|
|
Mutex::Lock _l(_taps_m); |
|
|
|
|
for(std::map< uint64_t,EthernetTap *>::const_iterator t(_taps.begin());t!=_taps.end();++t) { |
|
|
|
|
std::vector<MulticastGroup> added,removed; |
|
|
|
|
t->second->scanMulticastGroups(added,removed); |
|
|
|
|
for(std::vector<MulticastGroup>::iterator m(added.begin());m!=added.end();++m) |
|
|
|
|
_node->multicastSubscribe(t->first,m->mac().toInt(),m->adi()); |
|
|
|
|
for(std::vector<MulticastGroup>::iterator m(removed.begin());m!=removed.end();++m) |
|
|
|
|
_node->multicastUnsubscribe(t->first,m->mac().toInt(),m->adi()); |
|
|
|
|
Mutex::Lock _l(_nets_m); |
|
|
|
|
for(std::map<uint64_t,NetworkState>::const_iterator n(_nets.begin());n!=_nets.end();++n) { |
|
|
|
|
if (n->second.tap) { |
|
|
|
|
std::vector<MulticastGroup> added,removed; |
|
|
|
|
n->second.tap->scanMulticastGroups(added,removed); |
|
|
|
|
for(std::vector<MulticastGroup>::iterator m(added.begin());m!=added.end();++m) |
|
|
|
|
_node->multicastSubscribe(n->first,m->mac().toInt(),m->adi()); |
|
|
|
|
for(std::vector<MulticastGroup>::iterator m(removed.begin());m!=removed.end();++m) |
|
|
|
|
_node->multicastUnsubscribe(n->first,m->mac().toInt(),m->adi()); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -921,10 +930,10 @@ public:
|
|
|
|
|
} catch ( ... ) {} |
|
|
|
|
|
|
|
|
|
{ |
|
|
|
|
Mutex::Lock _l(_taps_m); |
|
|
|
|
for(std::map< uint64_t,EthernetTap * >::iterator t(_taps.begin());t!=_taps.end();++t) |
|
|
|
|
delete t->second; |
|
|
|
|
_taps.clear(); |
|
|
|
|
Mutex::Lock _l(_nets_m); |
|
|
|
|
for(std::map<uint64_t,NetworkState>::iterator n(_nets.begin());n!=_nets.end();++n) |
|
|
|
|
delete n->second.tap; |
|
|
|
|
_nets.clear(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
delete _controlPlane; |
|
|
|
|
@ -949,11 +958,11 @@ public:
|
|
|
|
|
|
|
|
|
|
virtual std::string portDeviceName(uint64_t nwid) const |
|
|
|
|
{ |
|
|
|
|
Mutex::Lock _l(_taps_m); |
|
|
|
|
std::map< uint64_t,EthernetTap * >::const_iterator t(_taps.find(nwid)); |
|
|
|
|
if (t != _taps.end()) |
|
|
|
|
return t->second->deviceName(); |
|
|
|
|
return std::string(); |
|
|
|
|
Mutex::Lock _l(_nets_m); |
|
|
|
|
std::map<uint64_t,NetworkState>::const_iterator n(_nets.find(nwid)); |
|
|
|
|
if ((n != _nets.end())&&(n->second.tap)) |
|
|
|
|
return n->second.tap->deviceName(); |
|
|
|
|
else return std::string(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
virtual bool tcpFallbackActive() const |
|
|
|
|
@ -1203,15 +1212,17 @@ public:
|
|
|
|
|
|
|
|
|
|
inline int nodeVirtualNetworkConfigFunction(uint64_t nwid,void **nuptr,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwc) |
|
|
|
|
{ |
|
|
|
|
Mutex::Lock _l(_taps_m); |
|
|
|
|
std::map< uint64_t,EthernetTap * >::iterator t(_taps.find(nwid)); |
|
|
|
|
Mutex::Lock _l(_nets_m); |
|
|
|
|
NetworkState &n = _nets[nwid]; |
|
|
|
|
|
|
|
|
|
switch(op) { |
|
|
|
|
|
|
|
|
|
case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP: |
|
|
|
|
if (t == _taps.end()) { |
|
|
|
|
if (!n.tap) { |
|
|
|
|
try { |
|
|
|
|
char friendlyName[1024]; |
|
|
|
|
char friendlyName[128]; |
|
|
|
|
Utils::snprintf(friendlyName,sizeof(friendlyName),"ZeroTier One [%.16llx]",nwid); |
|
|
|
|
t = _taps.insert(std::pair< uint64_t,EthernetTap *>(nwid,new EthernetTap( |
|
|
|
|
n.tap = new EthernetTap( |
|
|
|
|
_homePath.c_str(), |
|
|
|
|
MAC(nwc->mac), |
|
|
|
|
nwc->mtu, |
|
|
|
|
@ -1219,8 +1230,8 @@ public:
|
|
|
|
|
nwid, |
|
|
|
|
friendlyName, |
|
|
|
|
StapFrameHandler, |
|
|
|
|
(void *)this))).first; |
|
|
|
|
*nuptr = (void *)t->second; |
|
|
|
|
(void *)this); |
|
|
|
|
*nuptr = (void *)&n; |
|
|
|
|
} catch (std::exception &exc) { |
|
|
|
|
#ifdef __WINDOWS__ |
|
|
|
|
FILE *tapFailLog = fopen((_homePath + ZT_PATH_SEPARATOR_S"port_error_log.txt").c_str(),"a"); |
|
|
|
|
@ -1231,53 +1242,59 @@ public:
|
|
|
|
|
#else |
|
|
|
|
fprintf(stderr,"ERROR: unable to configure virtual network port: %s"ZT_EOL_S,exc.what()); |
|
|
|
|
#endif |
|
|
|
|
_nets.erase(nwid); |
|
|
|
|
return -999; |
|
|
|
|
} catch ( ... ) { |
|
|
|
|
return -999; // tap init failed
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// fall through...
|
|
|
|
|
case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE: |
|
|
|
|
if (t != _taps.end()) { |
|
|
|
|
t->second->setEnabled(nwc->enabled != 0); |
|
|
|
|
// After setting up tap, fall through to CONFIG_UPDATE since we also want to do this...
|
|
|
|
|
|
|
|
|
|
std::vector<InetAddress> &assignedIps = _tapAssignedIps[nwid]; |
|
|
|
|
std::vector<InetAddress> newAssignedIps; |
|
|
|
|
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) |
|
|
|
|
newAssignedIps.push_back(InetAddress(nwc->assignedAddresses[i])); |
|
|
|
|
std::sort(newAssignedIps.begin(),newAssignedIps.end()); |
|
|
|
|
newAssignedIps.erase(std::unique(newAssignedIps.begin(),newAssignedIps.end()),newAssignedIps.end()); |
|
|
|
|
for(std::vector<InetAddress>::iterator ip(newAssignedIps.begin());ip!=newAssignedIps.end();++ip) { |
|
|
|
|
if (!std::binary_search(assignedIps.begin(),assignedIps.end(),*ip)) |
|
|
|
|
if (!t->second->addIp(*ip)) |
|
|
|
|
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()); |
|
|
|
|
} |
|
|
|
|
for(std::vector<InetAddress>::iterator ip(assignedIps.begin());ip!=assignedIps.end();++ip) { |
|
|
|
|
if (!std::binary_search(newAssignedIps.begin(),newAssignedIps.end(),*ip)) |
|
|
|
|
if (!t->second->removeIp(*ip)) |
|
|
|
|
|
|
|
|
|
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()); |
|
|
|
|
} |
|
|
|
|
assignedIps.swap(newAssignedIps); |
|
|
|
|
|
|
|
|
|
n.managedIps.swap(newManagedIps); // faster than assign -- just swap pointers and let the old one die
|
|
|
|
|
} else { |
|
|
|
|
_nets.erase(nwid); |
|
|
|
|
return -999; // tap init failed
|
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN: |
|
|
|
|
case ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY: |
|
|
|
|
if (t != _taps.end()) { |
|
|
|
|
if (n.tap) { // sanity check
|
|
|
|
|
#ifdef __WINDOWS__ |
|
|
|
|
std::string winInstanceId(t->second->instanceId()); |
|
|
|
|
std::string winInstanceId(n.tap->instanceId()); |
|
|
|
|
#endif |
|
|
|
|
*nuptr = (void *)0; |
|
|
|
|
delete t->second; |
|
|
|
|
_taps.erase(t); |
|
|
|
|
_tapAssignedIps.erase(nwid); |
|
|
|
|
delete n.tap; |
|
|
|
|
_nets.erase(nwid); |
|
|
|
|
#ifdef __WINDOWS__ |
|
|
|
|
if ((op == ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY)&&(winInstanceId.length() > 0)) |
|
|
|
|
WindowsEthernetTap::deletePersistentTapDevice(winInstanceId.c_str()); |
|
|
|
|
#endif |
|
|
|
|
} else { |
|
|
|
|
_nets.erase(nwid); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
@ -1437,18 +1454,18 @@ public:
|
|
|
|
|
|
|
|
|
|
inline void nodeVirtualNetworkFrameFunction(uint64_t nwid,void **nuptr,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len) |
|
|
|
|
{ |
|
|
|
|
EthernetTap *tap = reinterpret_cast<EthernetTap *>(*nuptr); |
|
|
|
|
if (!tap) |
|
|
|
|
NetworkState *n = reinterpret_cast<NetworkState *>(*nuptr); |
|
|
|
|
if ((!n)||(!n->tap)) |
|
|
|
|
return; |
|
|
|
|
tap->put(MAC(sourceMac),MAC(destMac),etherType,data,len); |
|
|
|
|
n->tap->put(MAC(sourceMac),MAC(destMac),etherType,data,len); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
inline int nodePathCheckFunction(const struct sockaddr_storage *localAddr,const struct sockaddr_storage *remoteAddr) |
|
|
|
|
{ |
|
|
|
|
Mutex::Lock _l(_taps_m); |
|
|
|
|
for(std::map< uint64_t,EthernetTap * >::const_iterator t(_taps.begin());t!=_taps.end();++t) { |
|
|
|
|
if (t->second) { |
|
|
|
|
std::vector<InetAddress> ips(t->second->ips()); |
|
|
|
|
Mutex::Lock _l(_nets_m); |
|
|
|
|
for(std::map<uint64_t,NetworkState>::const_iterator n(_nets.begin());n!=_nets.end();++n) { |
|
|
|
|
if (n->second.tap) { |
|
|
|
|
std::vector<InetAddress> ips(n->second.tap->ips()); |
|
|
|
|
for(std::vector<InetAddress>::const_iterator i(ips.begin());i!=ips.end();++i) { |
|
|
|
|
if (i->containsAddress(*(reinterpret_cast<const InetAddress *>(remoteAddr)))) { |
|
|
|
|
return 0; |
|
|
|
|
@ -1456,6 +1473,7 @@ public:
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// TODO: also check routing table for L3 routes via ZeroTier managed devices
|
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@ -1521,10 +1539,10 @@ public:
|
|
|
|
|
if (isBlacklistedLocalInterfaceForZeroTierTraffic(ifname)) |
|
|
|
|
return false; |
|
|
|
|
|
|
|
|
|
Mutex::Lock _l(_taps_m); |
|
|
|
|
for(std::map< uint64_t,EthernetTap * >::const_iterator t(_taps.begin());t!=_taps.end();++t) { |
|
|
|
|
if (t->second) { |
|
|
|
|
std::vector<InetAddress> ips(t->second->ips()); |
|
|
|
|
Mutex::Lock _l(_nets_m); |
|
|
|
|
for(std::map<uint64_t,NetworkState>::const_iterator n(_nets.begin());n!=_nets.end();++n) { |
|
|
|
|
if (n->second.tap) { |
|
|
|
|
std::vector<InetAddress> ips(n->second.tap->ips()); |
|
|
|
|
for(std::vector<InetAddress>::const_iterator i(ips.begin());i!=ips.end();++i) { |
|
|
|
|
if (i->ipsEqual(ifaddr)) |
|
|
|
|
return false; |
|
|
|
|
|