|
|
|
|
@ -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,45 +338,58 @@ Network::Status Network::status() const
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Network::_CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data) |
|
|
|
|
void Network::learnBridgeRoute(const MAC &mac,const Address &addr) |
|
|
|
|
{ |
|
|
|
|
if ((!((Network *)arg)->_enabled)||(((Network *)arg)->status() != NETWORK_OK)) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
const RuntimeEnvironment *RR = ((Network *)arg)->RR; |
|
|
|
|
if (RR->shutdownInProgress) |
|
|
|
|
return; |
|
|
|
|
Mutex::Lock _l(_lock); |
|
|
|
|
_remoteBridgeRoutes[mac] = addr; |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
RR->sw->onLocalEthernet(SharedPtr<Network>((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"); |
|
|
|
|
// If _remoteBridgeRoutes exceeds sanity limit, trim worst offenders until below -- denial of service circuit breaker
|
|
|
|
|
while (_remoteBridgeRoutes.size() > ZT_MAX_BRIDGE_ROUTES) { |
|
|
|
|
std::map<Address,unsigned long> counts; |
|
|
|
|
Address maxAddr; |
|
|
|
|
unsigned long maxCount = 0; |
|
|
|
|
for(std::map<MAC,Address>::iterator br(_remoteBridgeRoutes.begin());br!=_remoteBridgeRoutes.end();++br) { |
|
|
|
|
unsigned long c = ++counts[br->second]; |
|
|
|
|
if (c > maxCount) { |
|
|
|
|
maxCount = c; |
|
|
|
|
maxAddr = br->second; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
for(std::map<MAC,Address>::iterator br(_remoteBridgeRoutes.begin());br!=_remoteBridgeRoutes.end();) { |
|
|
|
|
if (br->second == maxAddr) |
|
|
|
|
_remoteBridgeRoutes.erase(br++); |
|
|
|
|
else ++br; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Network::_pushMembershipCertificate(const Address &peer,bool force,uint64_t now) |
|
|
|
|
void Network::setEnabled(bool enabled) |
|
|
|
|
{ |
|
|
|
|
uint64_t pushTimeout = _config->com().timestampMaxDelta() / 2; |
|
|
|
|
if (!pushTimeout) |
|
|
|
|
return; // still waiting on my own cert
|
|
|
|
|
if (pushTimeout > 1000) |
|
|
|
|
pushTimeout -= 1000; |
|
|
|
|
Mutex::Lock _l(_lock); |
|
|
|
|
_enabled = enabled; |
|
|
|
|
if (_tap) |
|
|
|
|
_tap->setEnabled(enabled); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
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()); |
|
|
|
|
void Network::destroy() |
|
|
|
|
{ |
|
|
|
|
Mutex::Lock _l(_lock); |
|
|
|
|
|
|
|
|
|
Packet outp(peer,RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE); |
|
|
|
|
_config->com().serialize(outp); |
|
|
|
|
RR->sw->send(outp,true); |
|
|
|
|
} |
|
|
|
|
_enabled = false; |
|
|
|
|
_destroyed = true; |
|
|
|
|
|
|
|
|
|
if (_setupThread) |
|
|
|
|
Thread::join(_setupThread); |
|
|
|
|
_setupThread = Thread(); |
|
|
|
|
|
|
|
|
|
if (_tap) |
|
|
|
|
RR->tapFactory->close(_tap,true); |
|
|
|
|
_tap = (EthernetTap *)0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Ethernet tap creation thread -- required on some platforms where tap
|
|
|
|
|
// creation may be time consuming (e.g. Windows).
|
|
|
|
|
// creation may be time consuming (e.g. Windows). Thread exits after tap
|
|
|
|
|
// device setup.
|
|
|
|
|
void Network::threadMain() |
|
|
|
|
throw() |
|
|
|
|
{ |
|
|
|
|
@ -420,53 +433,46 @@ void Network::threadMain()
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Network::learnBridgeRoute(const MAC &mac,const Address &addr) |
|
|
|
|
void Network::_CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data) |
|
|
|
|
{ |
|
|
|
|
Mutex::Lock _l(_lock); |
|
|
|
|
_remoteBridgeRoutes[mac] = addr; |
|
|
|
|
if ((!((Network *)arg)->_enabled)||(((Network *)arg)->status() != NETWORK_OK)) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
// If _remoteBridgeRoutes exceeds sanity limit, trim worst offenders until below -- denial of service circuit breaker
|
|
|
|
|
while (_remoteBridgeRoutes.size() > ZT_MAX_BRIDGE_ROUTES) { |
|
|
|
|
std::map<Address,unsigned long> counts; |
|
|
|
|
Address maxAddr; |
|
|
|
|
unsigned long maxCount = 0; |
|
|
|
|
for(std::map<MAC,Address>::iterator br(_remoteBridgeRoutes.begin());br!=_remoteBridgeRoutes.end();++br) { |
|
|
|
|
unsigned long c = ++counts[br->second]; |
|
|
|
|
if (c > maxCount) { |
|
|
|
|
maxCount = c; |
|
|
|
|
maxAddr = br->second; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
for(std::map<MAC,Address>::iterator br(_remoteBridgeRoutes.begin());br!=_remoteBridgeRoutes.end();) { |
|
|
|
|
if (br->second == maxAddr) |
|
|
|
|
_remoteBridgeRoutes.erase(br++); |
|
|
|
|
else ++br; |
|
|
|
|
} |
|
|
|
|
const RuntimeEnvironment *RR = ((Network *)arg)->RR; |
|
|
|
|
if (RR->shutdownInProgress) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
try { |
|
|
|
|
RR->sw->onLocalEthernet(SharedPtr<Network>((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::setEnabled(bool enabled) |
|
|
|
|
void Network::_pushMembershipCertificate(const Address &peer,bool force,uint64_t now) |
|
|
|
|
{ |
|
|
|
|
Mutex::Lock _l(_lock); |
|
|
|
|
_enabled = enabled; |
|
|
|
|
if (_tap) |
|
|
|
|
_tap->setEnabled(enabled); |
|
|
|
|
} |
|
|
|
|
// assumes _lock is locked
|
|
|
|
|
uint64_t pushTimeout = _config->com().timestampMaxDelta() / 2; |
|
|
|
|
|
|
|
|
|
void Network::destroy() |
|
|
|
|
{ |
|
|
|
|
Mutex::Lock _l(_lock); |
|
|
|
|
// Zero means we're still waiting on our own cert
|
|
|
|
|
if (!pushTimeout) |
|
|
|
|
return; |
|
|
|
|
|
|
|
|
|
_enabled = false; |
|
|
|
|
_destroyed = true; |
|
|
|
|
// Give a 1s margin around +/- 1/2 max delta to account for latency
|
|
|
|
|
if (pushTimeout > 1000) |
|
|
|
|
pushTimeout -= 1000; |
|
|
|
|
|
|
|
|
|
if (_setupThread) |
|
|
|
|
Thread::join(_setupThread); |
|
|
|
|
_setupThread = Thread(); |
|
|
|
|
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()); |
|
|
|
|
|
|
|
|
|
if (_tap) |
|
|
|
|
RR->tapFactory->close(_tap,true); |
|
|
|
|
_tap = (EthernetTap *)0; |
|
|
|
|
Packet outp(peer,RR->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE); |
|
|
|
|
_config->com().serialize(outp); |
|
|
|
|
RR->sw->send(outp,true); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Network::_restoreState() |
|
|
|
|
@ -537,7 +543,7 @@ void Network::_restoreState()
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void Network::_dumpMulticastCerts() |
|
|
|
|
void Network::_dumpMembershipCerts() |
|
|
|
|
{ |
|
|
|
|
Buffer<ZT_NETWORK_CERT_WRITE_BUF_SIZE> buf; |
|
|
|
|
std::string mcdbPath(RR->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + idString() + ".mcerts"); |
|
|
|
|
|