diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 5697c7926..b89e259c3 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -124,7 +124,13 @@ private: bool _doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doNETWORK_CONFIG_REFRESH(const RuntimeEnvironment *RR,const SharedPtr &peer); + bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,const SharedPtr &peer); + bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,const SharedPtr &peer); + // Both OK(MULTICAST_GATHER) and OK(MULTICAST_FRAME) can carry this payload + void _handleMulticastGatherResponse(const RuntimeEnvironment *RR,const SharedPtr &peer,unsigned int startIdx); + + // Send an ERROR_NEED_MEMBERSHIP_CERTIFICATE to a peer indicating that an updated cert is needed to join void _sendErrorNeedCertificate(const RuntimeEnvironment *RR,const SharedPtr &peer,uint64_t nwid); uint64_t _receiveTime; diff --git a/node/Network.cpp b/node/Network.cpp index 6968fb0d2..18fbb6249 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -81,7 +81,7 @@ Network::~Network() Utils::rm(std::string(RR->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + idString() + ".mcerts")); } else { clean(); - _dumpMulticastCerts(); + _dumpMembershipCerts(); } } @@ -338,88 +338,6 @@ Network::Status Network::status() const } } -void Network::_CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data) -{ - if ((!((Network *)arg)->_enabled)||(((Network *)arg)->status() != NETWORK_OK)) - return; - - const RuntimeEnvironment *RR = ((Network *)arg)->RR; - if (RR->shutdownInProgress) - return; - - try { - RR->sw->onLocalEthernet(SharedPtr((Network *)arg),from,to,etherType,data); - } catch (std::exception &exc) { - TRACE("unexpected exception handling local packet: %s",exc.what()); - } catch ( ... ) { - TRACE("unexpected exception handling local packet"); - } -} - -void Network::_pushMembershipCertificate(const Address &peer,bool force,uint64_t now) -{ - uint64_t pushTimeout = _config->com().timestampMaxDelta() / 2; - if (!pushTimeout) - return; // still waiting on my own cert - if (pushTimeout > 1000) - pushTimeout -= 1000; - - uint64_t &lastPushed = _lastPushedMembershipCertificate[peer]; - if ((force)||((now - lastPushed) > pushTimeout)) { - lastPushed = now; - TRACE("pushing membership cert for %.16llx to %s",(unsigned long long)_id,peer.toString().c_str()); - - Packet outp(peer,RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE); - _config->com().serialize(outp); - RR->sw->send(outp,true); - } -} - -// Ethernet tap creation thread -- required on some platforms where tap -// creation may be time consuming (e.g. Windows). -void Network::threadMain() - throw() -{ - char fname[1024],lcentry[128]; - Utils::snprintf(lcentry,sizeof(lcentry),"_dev_for_%.16llx",(unsigned long long)_id); - - EthernetTap *t = (EthernetTap *)0; - try { - std::string desiredDevice(_nc->getLocalConfig(lcentry)); - _mkNetworkFriendlyName(fname,sizeof(fname)); - - t = RR->tapFactory->open(_mac,ZT_IF_MTU,ZT_DEFAULT_IF_METRIC,_id,(desiredDevice.length() > 0) ? desiredDevice.c_str() : (const char *)0,fname,_CBhandleTapData,this); - - std::string dn(t->deviceName()); - if ((dn.length())&&(dn != desiredDevice)) - _nc->putLocalConfig(lcentry,dn); - } catch (std::exception &exc) { - delete t; - t = (EthernetTap *)0; - LOG("network %.16llx failed to initialize: %s",_id,exc.what()); - _netconfFailure = NETCONF_FAILURE_INIT_FAILED; - } catch ( ... ) { - delete t; - t = (EthernetTap *)0; - LOG("network %.16llx failed to initialize: unknown error",_id); - _netconfFailure = NETCONF_FAILURE_INIT_FAILED; - } - - { - Mutex::Lock _l(_lock); - if (_tap) // the tap creation thread can technically be re-launched, though this isn't done right now - RR->tapFactory->close(_tap,false); - _tap = t; - if (t) { - if (_config) { - for(std::set::const_iterator newip(_config->staticIps().begin());newip!=_config->staticIps().end();++newip) - t->addIP(*newip); - } - t->setEnabled(_enabled); - } - } -} - void Network::learnBridgeRoute(const MAC &mac,const Address &addr) { Mutex::Lock _l(_lock); @@ -469,6 +387,94 @@ void Network::destroy() _tap = (EthernetTap *)0; } +// Ethernet tap creation thread -- required on some platforms where tap +// creation may be time consuming (e.g. Windows). Thread exits after tap +// device setup. +void Network::threadMain() + throw() +{ + char fname[1024],lcentry[128]; + Utils::snprintf(lcentry,sizeof(lcentry),"_dev_for_%.16llx",(unsigned long long)_id); + + EthernetTap *t = (EthernetTap *)0; + try { + std::string desiredDevice(_nc->getLocalConfig(lcentry)); + _mkNetworkFriendlyName(fname,sizeof(fname)); + + t = RR->tapFactory->open(_mac,ZT_IF_MTU,ZT_DEFAULT_IF_METRIC,_id,(desiredDevice.length() > 0) ? desiredDevice.c_str() : (const char *)0,fname,_CBhandleTapData,this); + + std::string dn(t->deviceName()); + if ((dn.length())&&(dn != desiredDevice)) + _nc->putLocalConfig(lcentry,dn); + } catch (std::exception &exc) { + delete t; + t = (EthernetTap *)0; + LOG("network %.16llx failed to initialize: %s",_id,exc.what()); + _netconfFailure = NETCONF_FAILURE_INIT_FAILED; + } catch ( ... ) { + delete t; + t = (EthernetTap *)0; + LOG("network %.16llx failed to initialize: unknown error",_id); + _netconfFailure = NETCONF_FAILURE_INIT_FAILED; + } + + { + Mutex::Lock _l(_lock); + if (_tap) // the tap creation thread can technically be re-launched, though this isn't done right now + RR->tapFactory->close(_tap,false); + _tap = t; + if (t) { + if (_config) { + for(std::set::const_iterator newip(_config->staticIps().begin());newip!=_config->staticIps().end();++newip) + t->addIP(*newip); + } + t->setEnabled(_enabled); + } + } +} + +void Network::_CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data) +{ + if ((!((Network *)arg)->_enabled)||(((Network *)arg)->status() != NETWORK_OK)) + return; + + const RuntimeEnvironment *RR = ((Network *)arg)->RR; + if (RR->shutdownInProgress) + return; + + try { + RR->sw->onLocalEthernet(SharedPtr((Network *)arg),from,to,etherType,data); + } catch (std::exception &exc) { + TRACE("unexpected exception handling local packet: %s",exc.what()); + } catch ( ... ) { + TRACE("unexpected exception handling local packet"); + } +} + +void Network::_pushMembershipCertificate(const Address &peer,bool force,uint64_t now) +{ + // assumes _lock is locked + uint64_t pushTimeout = _config->com().timestampMaxDelta() / 2; + + // Zero means we're still waiting on our own cert + if (!pushTimeout) + return; + + // Give a 1s margin around +/- 1/2 max delta to account for latency + if (pushTimeout > 1000) + pushTimeout -= 1000; + + uint64_t &lastPushed = _lastPushedMembershipCertificate[peer]; + if ((force)||((now - lastPushed) > pushTimeout)) { + lastPushed = now; + TRACE("pushing membership cert for %.16llx to %s",(unsigned long long)_id,peer.toString().c_str()); + + Packet outp(peer,RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE); + _config->com().serialize(outp); + RR->sw->send(outp,true); + } +} + void Network::_restoreState() { Buffer buf; @@ -537,7 +543,7 @@ void Network::_restoreState() } } -void Network::_dumpMulticastCerts() +void Network::_dumpMembershipCerts() { Buffer buf; std::string mcdbPath(RR->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + idString() + ".mcerts"); diff --git a/node/Network.hpp b/node/Network.hpp index d6e869587..8d4092bbe 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -249,7 +249,7 @@ public: Status status() const; /** - * Update and check multicast rate balance for a group + * Update and check multicast rate balance for a multicast group * * @param mg Multicast group * @param bytes Size of packet @@ -301,12 +301,6 @@ public: return _config; } - /** - * Thread main method; do not call elsewhere - */ - void threadMain() - throw(); - /** * Inject a frame into tap (if it's created and network is enabled) * @@ -318,6 +312,7 @@ public: */ inline void tapPut(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) { + Mutex::Lock _l(_lock); if (!_enabled) return; EthernetTap *t = _tap; @@ -330,6 +325,7 @@ public: */ inline std::string tapDeviceName() const { + Mutex::Lock _l(_lock); EthernetTap *t = _tap; if (t) return t->deviceName(); @@ -339,17 +335,14 @@ public: /** * @return Ethernet MAC address for this network's local interface */ - inline const MAC &mac() const - throw() - { - return _mac; - } + inline const MAC &mac() const throw() { return _mac; } /** * @return Set of IPs currently assigned to interface */ inline std::set ips() const { + Mutex::Lock _l(_lock); EthernetTap *t = _tap; if (t) return t->ips(); @@ -371,8 +364,10 @@ public: } /** + * Find the node on this network that has this MAC behind it (if any) + * * @param mac MAC address - * @return ZeroTier address of bridge to this MAC or null address if not found (also check result for self, since this can happen) + * @return ZeroTier address of bridge to this MAC */ inline Address findBridgeTo(const MAC &mac) const { @@ -422,12 +417,18 @@ public: */ void destroy(); + /** + * Thread main method; do not call elsewhere + */ + void threadMain() + throw(); + private: static void _CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data); void _pushMembershipCertificate(const Address &peer,bool force,uint64_t now); void _restoreState(); - void _dumpMulticastCerts(); + void _dumpMembershipCerts(); inline void _mkNetworkFriendlyName(char *buf,unsigned int len) {