summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--node/Address.hpp3
-rw-r--r--node/Constants.hpp2
-rw-r--r--node/PacketDecoder.cpp64
-rw-r--r--node/Switch.cpp92
4 files changed, 87 insertions, 74 deletions
diff --git a/node/Address.hpp b/node/Address.hpp
index e4cdf8a7..c63d41d9 100644
--- a/node/Address.hpp
+++ b/node/Address.hpp
@@ -177,7 +177,8 @@ public:
* @param prefixBits Number of bits in prefix bit pattern
* @return True if address is within prefix
*/
- inline bool withinMulticastPropagationPrefix(uint64_t prefix,unsigned int prefixBits)
+ inline bool withinMulticastPropagationPrefix(uint64_t prefix,unsigned int prefixBits) const
+ throw()
{
return ((_a & (0xffffffffffffffffULL >> (64 - prefixBits))) == prefix);
}
diff --git a/node/Constants.hpp b/node/Constants.hpp
index 4e131a8d..5021724f 100644
--- a/node/Constants.hpp
+++ b/node/Constants.hpp
@@ -410,6 +410,6 @@ error_no_byte_order_defined;
/**
* If there is no known route, spam to up to this many active bridges
*/
-#define ZT_MAX_BRIDGE_SPAM 4
+#define ZT_MAX_BRIDGE_SPAM 16
#endif
diff --git a/node/PacketDecoder.cpp b/node/PacketDecoder.cpp
index 2b9d034a..9248fe32 100644
--- a/node/PacketDecoder.cpp
+++ b/node/PacketDecoder.cpp
@@ -457,9 +457,15 @@ bool PacketDecoder::_doEXT_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Pe
try {
SharedPtr<Network> network(_r->nc->network(at<uint64_t>(ZT_PROTO_VERB_EXT_FRAME_IDX_NETWORK_ID)));
if (network) {
+ if ((*this)[ZT_PROTO_VERB_EXT_FRAME_IDX_FLAGS] != 0) {
+ TRACE("dropped EXT_FRAME due to unknown flags");
+ return true;
+ }
+
const MAC to(field(ZT_PROTO_VERB_EXT_FRAME_IDX_TO,ZT_PROTO_VERB_EXT_FRAME_LEN_TO),ZT_PROTO_VERB_EXT_FRAME_LEN_TO);
const MAC from(field(ZT_PROTO_VERB_EXT_FRAME_IDX_FROM,ZT_PROTO_VERB_EXT_FRAME_LEN_FROM),ZT_PROTO_VERB_EXT_FRAME_LEN_FROM);
unsigned int etherType = at<uint16_t>(ZT_PROTO_VERB_EXT_FRAME_IDX_ETHERTYPE);
+
if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) {
if ((!from)||(from.isMulticast())||(!to)) {
TRACE("dropped EXT_FRAME from %s@%s(%s) to %s: invalid source or destination MAC",from.toString().c_str(),peer->address().toString().c_str(),_remoteAddress.toString().c_str(),to.toString().c_str());
@@ -657,46 +663,44 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
if (network) {
SharedPtr<NetworkConfig> nconf(network->config2());
if (nconf) {
+ // Learn real maxDepth from netconf
maxDepth = std::min((unsigned int)ZT_MULTICAST_GLOBAL_MAX_DEPTH,nconf->multicastDepth());
if (!maxDepth)
maxDepth = ZT_MULTICAST_GLOBAL_MAX_DEPTH;
if (!network->isAllowed(origin)) {
- TRACE("didn't inject MULTICAST_FRAME from %s(%s) into %.16llx: sender %s not allowed or we don't have a certificate",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,origin.toString().c_str());
-
- // Tell them we need a certificate
+ // Papers, please...
Packet outp(source(),_r->identity.address(),Packet::VERB_ERROR);
- outp.append((unsigned char)Packet::VERB_FRAME);
+ outp.append((unsigned char)Packet::VERB_MULTICAST_FRAME);
outp.append(packetId());
outp.append((unsigned char)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
outp.append(nwid);
outp.armor(peer->key(),true);
_fromSock->send(_remoteAddress,outp.data(),outp.size());
+ TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: sender %s not allowed or we don't have a certificate",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,origin.toString().c_str());
+ return true;
+ }
- // We do not terminate here, since if the member just has an out of
- // date cert or hasn't sent us a cert yet we still want to propagate
- // the message so multicast keeps working downstream.
- } else if ((!nconf->permitsBridging(origin))&&(MAC(origin,network->id()) != sourceMac)) {
- // This *does* terminate propagation, since it's technically a
- // security violation of the network's bridging policy. But if we
- // were to keep propagating it wouldn't hurt anything, just waste
- // bandwidth as everyone else would reject it too.
+ if (MAC(origin,network->id()) != sourceMac) {
+ if (!nconf->permitsBridging(origin)) {
#ifdef ZT_TRACE_MULTICAST
- Utils::snprintf(mct,sizeof(mct),
- "%.16llx %.2u %.3u%s %c %s dropped: bridging not allowed",
- guid,
- prefix,
- depth,
- mctdepth,
- (_r->topology->amSupernode() ? 'S' : '-'),
- _r->identity.address().toString().c_str());
- _r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct));
+ Utils::snprintf(mct,sizeof(mct),
+ "%.16llx %.2u %.3u%s %c %s dropped: bridging not allowed",
+ guid,
+ prefix,
+ depth,
+ mctdepth,
+ (_r->topology->amSupernode() ? 'S' : '-'),
+ _r->identity.address().toString().c_str());
+ _r->sm->sendUdp(ZT_DEFAULTS.multicastTraceWatcher,mct,strlen(mct));
#endif
- TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: source mac %s doesn't belong to %s, and bridging is not supported on network",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,sourceMac.toString().c_str(),origin.toString().c_str());
- return true;
- } else if (!nconf->permitsEtherType(etherType)) {
- // Ditto for this-- halt propagation if this is for an ethertype
- // this network doesn't allow. Same principle as bridging test.
+ TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: source mac %s doesn't belong to %s, and bridging is not supported on network",source().toString().c_str(),_remoteAddress.toString().c_str(),nwid,sourceMac.toString().c_str(),origin.toString().c_str());
+ return true;
+ }
+ network->learnBridgeRoute(sourceMac,origin);
+ }
+
+ if (!nconf->permitsEtherType(etherType)) {
#ifdef ZT_TRACE_MULTICAST
Utils::snprintf(mct,sizeof(mct),
"%.16llx %.2u %.3u%s %c %s dropped: ethertype not allowed",
@@ -710,7 +714,9 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
#endif
TRACE("dropped MULTICAST_FRAME from %s(%s) into %.16llx: ethertype %u is not allowed",source().toString().c_str(),nwid,_remoteAddress.toString().c_str(),etherType);
return true;
- } else if (!network->updateAndCheckMulticastBalance(origin,dest,frameLen)) {
+ }
+
+ if (!network->updateAndCheckMulticastBalance(origin,dest,frameLen)) {
// Rate limits can only be checked by members of this network, but
// there should be enough of them that over-limit multicasts get
// their propagation aborted.
@@ -727,9 +733,9 @@ bool PacketDecoder::_doMULTICAST_FRAME(const RuntimeEnvironment *_r,const Shared
#endif
TRACE("dropped MULTICAST_FRAME from %s(%s): rate limits exceeded for sender %s",source().toString().c_str(),_remoteAddress.toString().c_str(),origin.toString().c_str());
return true;
- } else {
- network->tapPut(sourceMac,dest.mac(),etherType,frame,frameLen);
}
+
+ network->tapPut(sourceMac,dest.mac(),etherType,frame,frameLen);
}
}
}
diff --git a/node/Switch.cpp b/node/Switch.cpp
index 7e1d1f84..d012b841 100644
--- a/node/Switch.cpp
+++ b/node/Switch.cpp
@@ -89,11 +89,9 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
if (!nconf)
return;
- // This should not happen
- if (to == network->mac()) {
- LOG("%s: frame received from self, ignoring (bridge loop? OS bug?)",network->tapDeviceName().c_str());
+ // Sanity check -- bridge loop? OS problem?
+ if (to == network->mac())
return;
- }
// Check anti-recursion module to ensure that this is not ZeroTier talking over its own links
if (!_r->antiRec->checkEthernetFrame(data.data(),data.size())) {
@@ -111,12 +109,13 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
bool fromBridged = false;
if (from != network->mac()) {
if (!network->permitsBridging(_r->identity.address())) {
- LOG("%s: UNICAST %s -> %s %s dropped, bridging disabled on network %.16llx",network->tapDeviceName().c_str(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),network->id());
+ LOG("%s: %s -> %s %s not forwarded, bridging disabled on %.16llx or this peer not a bridge",network->tapDeviceName().c_str(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),network->id());
return;
}
fromBridged = true;
}
+ // Multicast, either bridged or local source
if (to.isMulticast()) {
MulticastGroup mg(to,0);
@@ -167,6 +166,8 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
// Then visit next hops according to multicaster (if there's room... almost certainly will be)
if (fifoPtr != fifoEnd) {
_r->mc->getNextHops(network->id(),mg,Multicaster::AddToPropagationQueue(&fifoPtr,fifoEnd,bloom,bloomNonce,_r->identity.address(),nconf->multicastPrefixBits(),prefix));
+
+ // Pad remainder of FIFO with zeroes
while (fifoPtr != fifoEnd)
*(fifoPtr++) = (unsigned char)0;
}
@@ -176,7 +177,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
if (!firstHop) {
if (supernode)
firstHop = supernode->address();
- else continue; // no first hop = nowhere to go, try next bit prefix
+ else continue; // nowhere to go
}
Packet outp(firstHop,_r->identity.address(),Packet::VERB_MULTICAST_FRAME);
@@ -193,7 +194,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
outp.append((unsigned char)((mcid >> 8) & 0xff));
outp.append((unsigned char)(mcid & 0xff));
from.appendTo(outp);
- to.appendTo(outp);
+ mg.mac().appendTo(outp);
outp.append(mg.adi());
outp.append((uint16_t)etherType);
outp.append((uint16_t)data.size());
@@ -212,8 +213,12 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
outp.compress();
send(outp,true);
}
- } else if (to[0] == MAC::firstOctetForNetwork(network->id())) {
- // Simple unicast frame from us to another node on the same virtual network
+
+ return;
+ }
+
+ // Unicast from local peer to another non-bridged ZeroTier node
+ if ((!fromBridged)&&(to[0] == MAC::firstOctetForNetwork(network->id()))) {
Address toZT(to.toAddress(network->id()));
if (network->isAllowed(toZT)) {
network->pushMembershipCertificate(toZT,false,Utils::now());
@@ -227,44 +232,45 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
} else {
TRACE("%s: UNICAST: %s -> %s %s dropped, destination not a member of closed network %.16llx",network->tapDeviceName().c_str(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType),network->id());
}
- } else {
- // Simple unicast from us to another node behind another bridge
- Address bridges[ZT_MAX_BRIDGE_SPAM];
- unsigned int numBridges = 0;
-
- bridges[0] = network->findBridgeTo(to));
- if ((bridges[0])&&(bridges[0] != _r->identity.address())&&(network->isAllowed(bridges[0]))&&(network->permitsBridging(bridges[0]))) {
- ++numBridges;
- } else if (!nconf->activeBridges().empty()) {
- // If there is no known route, spam to up to ZT_MAX_BRIDGE_SPAM active bridges
- std::set<Address>::const_iterator ab(nconf->activeBridges().begin());
- if (nconf->activeBridges().size() <= ZT_MAX_BRIDGE_SPAM) {
- // If there are <= ZT_MAX_BRIDGE_SPAM active bridges, just take them all
- while (numBridges < nconf->activeBridges().size())
+ }
+
+ // Unicast to another node behind another bridge, whether from us or not
+
+ Address bridges[ZT_MAX_BRIDGE_SPAM];
+ unsigned int numBridges = 0;
+
+ bridges[0] = network->findBridgeTo(to);
+ if ((bridges[0])&&(bridges[0] != _r->identity.address())&&(network->isAllowed(bridges[0]))&&(network->permitsBridging(bridges[0]))) {
+ ++numBridges;
+ } else if (!nconf->activeBridges().empty()) {
+ // If there is no known route, spam to up to ZT_MAX_BRIDGE_SPAM active bridges
+ std::set<Address>::const_iterator ab(nconf->activeBridges().begin());
+ if (nconf->activeBridges().size() <= ZT_MAX_BRIDGE_SPAM) {
+ // If there are <= ZT_MAX_BRIDGE_SPAM active bridges, just take them all
+ while (numBridges < nconf->activeBridges().size())
+ bridges[numBridges++] = *(ab++);
+ } else {
+ // Otherwise do this less efficient multipass thing to pick randomly from an ordered set until we have enough
+ while (numBridges < ZT_MAX_BRIDGE_SPAM) {
+ if (ab == nconf->activeBridges().end())
+ ab = nconf->activeBridges().begin();
+ if (((unsigned long)_r->prng->next32() % (unsigned long)nconf->activeBridges().size()) == 0)
bridges[numBridges++] = *(ab++);
- } else {
- // Otherwise do this less efficient multipass thing to pick randomly from an ordered set until we have enough
- while (numBridges < ZT_MAX_BRIDGE_SPAM) {
- if (ab == nconf->activeBridges().end())
- ab = nconf->activeBridges().begin();
- if (((unsigned long)_r->prng->next32() % (unsigned long)nconf->activeBridges().size()) == 0)
- bridges[numBridges++] = *(ab++);
- else ++ab;
- }
+ else ++ab;
}
}
+ }
- for(unsigned int b=0;b<numBridges;++b) {
- Packet outp(bridges[b],_r->identity.address(),Packet::VERB_EXT_FRAME);
- outp.append(network->id());
- outp.append((unsigned char)0);
- to.appendTo(outp);
- from.appendTo(outp);
- outp.append((uint16_t)etherType);
- outp.append(data);
- outp.compress();
- send(outp,true);
- }
+ for(unsigned int b=0;b<numBridges;++b) {
+ Packet outp(bridges[b],_r->identity.address(),Packet::VERB_EXT_FRAME);
+ outp.append(network->id());
+ outp.append((unsigned char)0);
+ to.appendTo(outp);
+ from.appendTo(outp);
+ outp.append((uint16_t)etherType);
+ outp.append(data);
+ outp.compress();
+ send(outp,true);
}
}