From 58fa6cab4397fe7b0f4fe883e9d1632f5b73f6f9 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 7 Oct 2013 17:00:53 -0400 Subject: Auto-pushing of membership certs on: MULTICAST_FRAME,FRAME,MULTICAST_LIKE and on receipt of MULTICAST_LIKE. --- node/Network.cpp | 43 +++++++++++++++++++------------------------ node/Network.hpp | 32 +++++++++++++++++++++++++++++++- node/PacketDecoder.cpp | 24 +++++++++++++++--------- node/Switch.cpp | 15 +++++++++++++++ 4 files changed, 80 insertions(+), 34 deletions(-) diff --git a/node/Network.cpp b/node/Network.cpp index 2d08a91f..1973b643 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -169,30 +169,6 @@ void Network::addMembershipCertificate(const Address &peer,const CertificateOfMe _membershipCertificates[peer] = cert; } -void Network::pushMembershipCertificate(const Address &peer,bool force,uint64_t now) -{ - Mutex::Lock _l(_lock); - - if (_isOpen) - return; - - uint64_t timestampMaxDelta = _myCertificate.timestampMaxDelta(); - if (!timestampMaxDelta) { - LOG("unable to push my certificate to %s for network %.16llx: certificate invalid, missing required timestamp field",peer.toString().c_str(),_id); - return; // required field missing! - } - - uint64_t &lastPushed = _lastPushedMembershipCertificate[peer]; - if ((force)||((now - lastPushed) > (timestampMaxDelta / 2))) { - lastPushed = now; - - Packet outp(peer,_r->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE); - outp.append((uint64_t)_id); - _myCertificate.serialize(outp); - _r->sw->send(outp,true); - } -} - bool Network::isAllowed(const Address &peer) const { // Exceptions can occur if we do not yet have *our* configuration. @@ -282,6 +258,25 @@ void Network::_CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned } } +void Network::_pushMembershipCertificate(const Address &peer,bool force,uint64_t now) +{ + uint64_t timestampMaxDelta = _myCertificate.timestampMaxDelta(); + if (!timestampMaxDelta) { + LOG("unable to push my certificate to %s for network %.16llx: certificate invalid, missing required timestamp field",peer.toString().c_str(),_id); + return; // required field missing! + } + + uint64_t &lastPushed = _lastPushedMembershipCertificate[peer]; + if ((force)||((now - lastPushed) > (timestampMaxDelta / 2))) { + lastPushed = now; + + Packet outp(peer,_r->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE); + outp.append((uint64_t)_id); + _myCertificate.serialize(outp); + _r->sw->send(outp,true); + } +} + void Network::_restoreState() { std::string confPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + idString() + ".conf"); diff --git a/node/Network.hpp b/node/Network.hpp index 64e01c57..7d173a21 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -476,7 +476,36 @@ public: * @param force If true, push even if we've already done so within required time frame * @param now Current time */ - void pushMembershipCertificate(const Address &peer,bool force,uint64_t now); + inline void pushMembershipCertificate(const Address &peer,bool force,uint64_t now) + { + Mutex::Lock _l(_lock); + if (!_isOpen) + _pushMembershipCertificate(peer,force,now); + } + + /** + * Push membership certificate to a packed zero-terminated array of addresses + * + * This pushes to all peers in peers[] (length must be a multiple of 5) until + * len is reached or a null address is encountered. + * + * @param peers Packed array of 5-byte big-endian addresses + * @param len Length of peers[] in total, MUST be a multiple of 5 + * @param force If true, push even if we've already done so within required time frame + * @param now Current time + */ + inline void pushMembershipCertificate(const void *peers,unsigned int len,bool force,uint64_t now) + { + Mutex::Lock _l(_lock); + if (!_isOpen) { + for(unsigned int i=0;i &data); + void _pushMembershipCertificate(const Address &peer,bool force,uint64_t now); void _restoreState(); const RuntimeEnvironment *_r; diff --git a/node/PacketDecoder.cpp b/node/PacketDecoder.cpp index 56b8cc39..8fec63c9 100644 --- a/node/PacketDecoder.cpp +++ b/node/PacketDecoder.cpp @@ -438,6 +438,7 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared bool rateLimitsExceeded = false; unsigned int maxDepth = ZT_MULTICAST_GLOBAL_MAX_DEPTH; + SharedPtr network(_r->nc->network(nwid)); if ((origin == _r->identity.address())||(_r->mc->deduplicate(nwid,guid))) { // Ordinary frames will drop duplicates. Supernodes keep propagating @@ -457,7 +458,6 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared // true -- we don't want to see a ton of copies of the same frame on // its tap device. Also double or triple counting bandwidth metrics // for the same frame would not be fair. - SharedPtr network(_r->nc->network(nwid)); if (network) { maxDepth = std::min((unsigned int)ZT_MULTICAST_GLOBAL_MAX_DEPTH,network->multicastDepth()); if (!network->isAllowed(origin)) { @@ -549,6 +549,11 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared while (newFifoPtr != newFifoEnd) *(newFifoPtr++) = (unsigned char)0; + // If we're forwarding a packet within a private network that we are + // a member of, also propagate our cert forward if needed. + if (network) + network->pushMembershipCertificate(newFifo,sizeof(newFifo),false,Utils::now()); + // First element in newFifo[] is next hop Address nextHop(newFifo,ZT_ADDRESS_LENGTH); if ((!nextHop)&&(!_r->topology->amSupernode())) { @@ -593,17 +598,18 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared bool PacketDecoder::_doMULTICAST_LIKE(const RuntimeEnvironment *_r,const SharedPtr &peer) { try { - unsigned int ptr = ZT_PACKET_IDX_PAYLOAD; - if (ptr >= size()) - return true; - uint64_t now = Utils::now(); Address src(source()); + uint64_t now = Utils::now(); // Iterate through 18-byte network,MAC,ADI tuples - for(;;) { - _r->mc->likesGroup(at(ptr),src,MulticastGroup(MAC(field(ptr + 8,6)),at(ptr + 14)),now); - if ((ptr += 18) >= size()) - break; + for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptr(ptr); + SharedPtr network(_r->nc->network(nwid)); + if ((_r->topology->amSupernode())||((network)&&(network->isAllowed(peer->address())))) { + _r->mc->likesGroup(nwid,src,MulticastGroup(MAC(field(ptr + 8,6)),at(ptr + 14)),now); + if (network) + network->pushMembershipCertificate(peer->address(),false,now); + } } } catch (std::exception &ex) { TRACE("dropped MULTICAST_LIKE from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what()); diff --git a/node/Switch.cpp b/node/Switch.cpp index 55c21f09..f21f1e64 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -114,6 +114,7 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c unsigned char *const fifoEnd = fifo + sizeof(fifo); const unsigned int signedPartLen = (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME - ZT_PROTO_VERB_MULTICAST_FRAME_IDX__START_OF_SIGNED_PORTION) + data.size(); const SharedPtr supernode(_r->topology->getBestSupernode()); + uint64_t now = Utils::now(); for(unsigned int prefix=0,np=((unsigned int)2 << (network->multicastPrefixBits() - 1));prefix &network,const MAC &from,c else continue; } + // If network is not open, make sure all recipients have our membership + // certificate if we haven't sent it recently. As the multicast goes + // further down the line, peers beyond the first batch will ask us for + // our membership certificate if they need it. + network->pushMembershipCertificate(fifo,sizeof(fifo),false,now); + Packet outp(firstHop,_r->identity.address(),Packet::VERB_MULTICAST_FRAME); outp.append((uint16_t)0); outp.append(fifo + ZT_ADDRESS_LENGTH,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO); // remainder of fifo is loaded into packet @@ -161,6 +168,8 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c // Simple unicast frame from us to another node Address toZT(to.data + 1,ZT_ADDRESS_LENGTH); if (network->isAllowed(toZT)) { + network->pushMembershipCertificate(toZT,false,Utils::now()); + Packet outp(toZT,_r->identity.address(),Packet::VERB_FRAME); outp.append(network->id()); outp.append((uint16_t)etherType); @@ -388,10 +397,13 @@ void Switch::announceMulticastGroups(const std::map< SharedPtr,std::set TRACE("announcing %u multicast groups for %u networks to %u peers",totalMulticastGroups,(unsigned int)allMemberships.size(),(unsigned int)directPeers.size()); #endif + uint64_t now = Utils::now(); for(std::vector< SharedPtr >::iterator p(directPeers.begin());p!=directPeers.end();++p) { Packet outp((*p)->address(),_r->identity.address(),Packet::VERB_MULTICAST_LIKE); for(std::map< SharedPtr,std::set >::const_iterator nwmgs(allMemberships.begin());nwmgs!=allMemberships.end();++nwmgs) { + nwmgs->first->pushMembershipCertificate((*p)->address(),false,now); + if ((_r->topology->isSupernode((*p)->address()))||(nwmgs->first->isAllowed((*p)->address()))) { for(std::set::iterator mg(nwmgs->second.begin());mg!=nwmgs->second.end();++mg) { if ((outp.size() + 18) > ZT_UDP_DEFAULT_PAYLOAD_MTU) { @@ -416,8 +428,11 @@ void Switch::announceMulticastGroups(const SharedPtr &peer) { Packet outp(peer->address(),_r->identity.address(),Packet::VERB_MULTICAST_LIKE); std::vector< SharedPtr > networks(_r->nc->networks()); + uint64_t now = Utils::now(); for(std::vector< SharedPtr >::iterator n(networks.begin());n!=networks.end();++n) { if (((*n)->isAllowed(peer->address()))||(_r->topology->isSupernode(peer->address()))) { + (*n)->pushMembershipCertificate(peer->address(),false,now); + std::set mgs((*n)->multicastGroups()); for(std::set::iterator mg(mgs.begin());mg!=mgs.end();++mg) { if ((outp.size() + 18) > ZT_UDP_DEFAULT_PAYLOAD_MTU) { -- cgit v1.2.3