diff options
Diffstat (limited to 'node/Switch.cpp')
-rw-r--r-- | node/Switch.cpp | 132 |
1 files changed, 60 insertions, 72 deletions
diff --git a/node/Switch.cpp b/node/Switch.cpp index 1677c145..7bece5f2 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -49,13 +49,15 @@ #include "NodeConfig.hpp" #include "Demarc.hpp" #include "Filter.hpp" +#include "CMWC4096.hpp" #include "../version.h" namespace ZeroTier { Switch::Switch(const RuntimeEnvironment *renv) : - _r(renv) + _r(renv), + _multicastIdCounter((unsigned int)renv->prng->next32()) // start a random spot to minimize possible collisions on startup { } @@ -81,18 +83,18 @@ void Switch::onRemotePacket(Demarc::Port localPort,const InetAddress &fromAddr,c void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data) { - if (from != network->tap().mac()) { - LOG("ignored tap: %s -> %s %s (bridging is not (yet?) supported)",from.toString().c_str(),to.toString().c_str(),Filter::etherTypeName(etherType)); + if (to == network->tap().mac()) { + LOG("%s: frame received from self, ignoring (bridge loop? OS bug?)",network->tap().deviceName().c_str()); return; } - if (to == network->tap().mac()) { - LOG("%s: frame received from self, ignoring (bridge loop? OS bug?)",network->tap().deviceName().c_str()); + if (from != network->tap().mac()) { + LOG("ignored tap: %s -> %s %s (bridging not supported)",from.toString().c_str(),to.toString().c_str(),Filter::etherTypeName(etherType)); return; } if (!network->permitsEtherType(etherType)) { - LOG("ignored tap: %s -> %s: ethernet type %s not allowed on network %.16llx",from.toString().c_str(),to.toString().c_str(),Filter::etherTypeName(etherType),(unsigned long long)network->id()); + LOG("ignored tap: %s -> %s: ethertype %s not allowed on network %.16llx",from.toString().c_str(),to.toString().c_str(),Filter::etherTypeName(etherType),(unsigned long long)network->id()); return; } @@ -105,58 +107,55 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c mg = MulticastGroup::deriveMulticastGroupForAddressResolution(InetAddress(data.field(24,4),4,0)); } - uint64_t crc = Multicaster::computeMulticastDedupCrc(network->id(),from,mg,etherType,data.data(),data.size()); - uint64_t now = Utils::now(); + unsigned int mcid = ++_multicastIdCounter & 0xffffff; + uint16_t bloomNonce = (uint16_t)_r->prng->next32(); // doesn't need to be cryptographically strong + unsigned char bloom[ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_BLOOM]; + unsigned char fifo[ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_FIFO + ZT_ADDRESS_LENGTH]; + for(unsigned int prefix=0;prefix<ZT_MULTICAST_NUM_PROPAGATION_PREFIXES;++prefix) { + memset(bloom,0,sizeof(bloom)); + + unsigned char *fifoPtr = fifo; + unsigned char *fifoEnd = fifo + sizeof(fifo); + + _r->mc->getNextHops(network->id(),mg,Multicaster::AddToPropagationQueue(&fifoPtr,fifoEnd,bloom,bloomNonce,_r->identity.address(),ZT_MULTICAST_NUM_PROPAGATION_PREFIX_BITS,prefix)); + while (fifoPtr != fifoEnd) + *(fifoPtr++) = (unsigned char)0; + + Address firstHop(fifo,ZT_ADDRESS_LENGTH); // fifo is +1 in size, with first element being used here + if (!firstHop) { + SharedPtr<Peer> sn(_r->topology->getBestSupernode()); + if (sn) + firstHop = sn->address(); + else break; + } - if (_r->multicaster->checkDuplicate(crc,now)) { - LOG("%s/%.16llx: multicast group %s: dropped %u bytes, duplicate multicast in too short a time frame",network->tap().deviceName().c_str(),(unsigned long long)network->id(),mg.toString().c_str(),(unsigned int)data.size()); - return; - } - _r->multicaster->addToDedupHistory(crc,now); - if (!network->updateAndCheckMulticastBalance(_r->identity.address(),mg,data.size())) { - LOG("%s/%.16llx: multicast group %s: dropped %u bytes, out of budget",network->tap().deviceName().c_str(),(unsigned long long)network->id(),mg.toString().c_str(),(unsigned int)data.size()); - return; - } + 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 + outp.append(bloom,ZT_PROTO_VERB_MULTICAST_FRAME_LEN_PROPAGATION_BLOOM); + outp.append((unsigned char)0); + outp.append(network->id()); + outp.append(bloomNonce); + outp.append((unsigned char)ZT_MULTICAST_NUM_PROPAGATION_PREFIX_BITS); + outp.append((uint16_t)prefix); + _r->identity.address().appendTo(outp); + outp.append((unsigned char)((mcid >> 16) & 0xff)); + outp.append((unsigned char)((mcid >> 8) & 0xff)); + outp.append((unsigned char)(mcid & 0xff)); + outp.append(from.data,6); + outp.append(mg.mac().data,6); + outp.append(mg.adi()); + outp.append((uint16_t)etherType); + outp.append((uint16_t)data.size()); + outp.append(data); - Multicaster::MulticastBloomFilter bloom; - SharedPtr<Peer> propPeers[16]; - unsigned int np = _r->multicaster->pickSocialPropagationPeers( - *(_r->prng), - *(_r->topology), - network->id(), - mg, - _r->identity.address(), - Address(), - bloom, - std::min(network->multicastPropagationBreadth(),(unsigned int)16), // 16 is a sanity check - propPeers, - now); - - if (!np) - return; - - C25519::Signature signature(Multicaster::signMulticastPacket(_r->identity,network->id(),from,mg,etherType,data.data(),data.size())); - - Packet outpTmpl(propPeers[0]->address(),_r->identity.address(),Packet::VERB_MULTICAST_FRAME); - outpTmpl.append((uint8_t)0); - outpTmpl.append((uint64_t)network->id()); - _r->identity.address().appendTo(outpTmpl); - outpTmpl.append(from.data,6); - outpTmpl.append(mg.mac().data,6); - outpTmpl.append((uint32_t)mg.adi()); - outpTmpl.append(bloom.data(),ZT_PROTO_VERB_MULTICAST_FRAME_BLOOM_FILTER_SIZE_BYTES); - outpTmpl.append((uint8_t)0); // 0 hops - outpTmpl.append((uint16_t)etherType); - outpTmpl.append((uint16_t)data.size()); - outpTmpl.append((uint16_t)signature.size()); - outpTmpl.append(data.data(),data.size()); - outpTmpl.append(signature.data,(unsigned int)signature.size()); - outpTmpl.compress(); - send(outpTmpl,true); - for(unsigned int i=1;i<np;++i) { - outpTmpl.newInitializationVector(); - outpTmpl.setDestination(propPeers[i]->address()); - send(outpTmpl,true); + unsigned int signedPartLen = (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME - ZT_PROTO_VERB_MULTICAST_FRAME_IDX__START_OF_SIGNED_PORTION) + data.size(); + C25519::Signature sig(_r->identity.sign(outp.field(ZT_PROTO_VERB_MULTICAST_FRAME_IDX__START_OF_SIGNED_PORTION,signedPartLen),signedPartLen)); + outp.append((uint16_t)sig.size()); + outp.append(sig.data,sig.size()); + + outp.compress(); + send(outp,true); } } else if (to.isZeroTier()) { // Simple unicast frame from us to another node @@ -206,7 +205,6 @@ void Switch::sendHELLO(const Address &dest) bool Switch::sendHELLO(const SharedPtr<Peer> &dest,Demarc::Port localPort,const InetAddress &remoteAddr) { uint64_t now = Utils::now(); - Packet outp(dest->address(),_r->identity.address(),Packet::VERB_HELLO); outp.append((unsigned char)ZT_PROTO_VERSION); outp.append((unsigned char)ZEROTIER_ONE_VERSION_MAJOR); @@ -214,8 +212,7 @@ bool Switch::sendHELLO(const SharedPtr<Peer> &dest,Demarc::Port localPort,const outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION); outp.append(now); _r->identity.serialize(outp,false); - outp.macSet(dest->macKey()); - + outp.armor(dest->key(),false); return _r->demarc->send(localPort,remoteAddr,outp.data(),outp.size(),-1); } @@ -268,8 +265,7 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force) outp.append((unsigned char)4); outp.append(cg.first.rawIpData(),4); } - outp.encrypt(p1p->cryptKey()); - outp.macSet(p1p->macKey()); + outp.armor(p1p->key(),true); p1p->send(_r,outp.data(),outp.size(),now); } { // tell p2 where to find p1 @@ -283,8 +279,7 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force) outp.append((unsigned char)4); outp.append(cg.second.rawIpData(),4); } - outp.encrypt(p2p->cryptKey()); - outp.macSet(p2p->macKey()); + outp.armor(p2p->key(),true); p2p->send(_r,outp.data(),outp.size(),now); } @@ -606,9 +601,7 @@ Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlread if (supernode) { Packet outp(supernode->address(),_r->identity.address(),Packet::VERB_WHOIS); addr.appendTo(outp); - outp.encrypt(supernode->cryptKey()); - outp.macSet(supernode->macKey()); - + outp.armor(supernode->key(),true); uint64_t now = Utils::now(); if (supernode->send(_r,outp.data(),outp.size(),now)) return supernode->address(); @@ -623,13 +616,10 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) if (peer) { uint64_t now = Utils::now(); - bool isRelay; SharedPtr<Peer> via; if ((_r->topology->isSupernode(peer->address()))||(peer->hasActiveDirectPath(now))) { - isRelay = false; via = peer; } else { - isRelay = true; via = _r->topology->getBestSupernode(); if (!via) return false; @@ -640,9 +630,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt) unsigned int chunkSize = std::min(tmp.size(),(unsigned int)ZT_UDP_DEFAULT_PAYLOAD_MTU); tmp.setFragmented(chunkSize < tmp.size()); - if (encrypt) - tmp.encrypt(peer->cryptKey()); - tmp.macSet(peer->macKey()); + tmp.armor(peer->key(),encrypt); if (via->send(_r,tmp.data(),chunkSize,now)) { if (chunkSize < tmp.size()) { |