diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 0a3d58af0..f54752d10 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -169,7 +169,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr // Peers can send this in response to frames if they do not have a recent enough COM from us const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); const uint64_t now = RR->node->now(); - if ( (network) && (network->config().com) && (peer->rateGateComRequest(now)) ) + if ( (network) && (network->config().com) && (peer->rateGateIncomingComRequest(now)) ) network->pushCredentialsNow(peer->address(),now); } break; @@ -184,7 +184,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr // Members of networks can use this error to indicate that they no longer // want to receive multicasts on a given channel. const SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD))); - if ((network)&&(network->gate(peer,verb(),packetId()))) { + if ((network)&&(network->gate(peer))) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 8,6),6),at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD + 14)); TRACE("%.16llx: peer %s unsubscrubed from multicast group %s",network->id(),peer->address().toString().c_str(),mg.toString().c_str()); RR->mc->remove(network->id(),mg,peer->address()); @@ -375,7 +375,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p try { const Packet::Verb inReVerb = (Packet::Verb)(*this)[ZT_PROTO_VERB_OK_IDX_IN_RE_VERB]; const uint64_t inRePacketId = at(ZT_PROTO_VERB_OK_IDX_IN_RE_PACKET_ID); - bool trustEstablished = false; if (!RR->node->expectingReplyTo(inRePacketId)) { TRACE("%s(%s): OK(%s) DROPPED: not expecting reply to %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),Packet::verbString(inReVerb),packetId()); @@ -441,8 +440,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p case Packet::VERB_MULTICAST_GATHER: { const uint64_t nwid = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); const SharedPtr network(RR->node->network(nwid)); - if ((network)&&(network->gateMulticastGatherReply(peer,verb(),packetId()))) { - trustEstablished = true; + if (network) { const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI)); //TRACE("%s(%s): OK(MULTICAST_GATHER) %.16llx/%s length %u",source().toString().c_str(),_path->address().toString().c_str(),nwid,mg.toString().c_str(),size()); const unsigned int count = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_GATHER_RESULTS + 4); @@ -468,15 +466,12 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p network->addCredential(com); } - if (network->gateMulticastGatherReply(peer,verb(),packetId())) { - trustEstablished = true; - if ((flags & 0x02) != 0) { - // OK(MULTICAST_FRAME) includes implicit gather results - offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; - unsigned int totalKnown = at(offset); offset += 4; - unsigned int count = at(offset); offset += 2; - RR->mc->addMultiple(RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); - } + if ((flags & 0x02) != 0) { + // OK(MULTICAST_FRAME) includes implicit gather results + offset += ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS; + unsigned int totalKnown = at(offset); offset += 4; + unsigned int count = at(offset); offset += 2; + RR->mc->addMultiple(RR->node->now(),nwid,mg,field(offset,count * 5),count,totalKnown); } } } break; @@ -484,7 +479,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p default: break; } - peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,trustEstablished); + peer->received(_path,hops(),packetId(),Packet::VERB_OK,inRePacketId,inReVerb,false); } catch ( ... ) { TRACE("dropped OK from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); } @@ -581,9 +576,7 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr const SharedPtr network(RR->node->network(nwid)); bool trustEstablished = false; if (network) { - if (!network->gate(peer,verb(),packetId())) { - TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); - } else { + if (network->gate(peer)) { trustEstablished = true; if (size() > ZT_PROTO_VERB_FRAME_IDX_PAYLOAD) { const unsigned int etherType = at(ZT_PROTO_VERB_FRAME_IDX_ETHERTYPE); @@ -593,9 +586,13 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,const SharedPtr if (network->filterIncomingPacket(peer,RR->identity.address(),sourceMac,network->mac(),frameData,frameLen,etherType,0) > 0) RR->node->putFrame(nwid,network->userPtr(),sourceMac,network->mac(),etherType,0,(const void *)frameData,frameLen); } + } else { + TRACE("dropped FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); + _sendErrorNeedCredentials(RR,peer,nwid); } } else { TRACE("dropped FRAME from %s(%s): we are not a member of network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); + _sendErrorNeedCredentials(RR,peer,nwid); } peer->received(_path,hops(),packetId(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished); } catch ( ... ) { @@ -620,8 +617,9 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

addCredential(com); } - if (!network->gate(peer,verb(),packetId())) { + if (!network->gate(peer)) { TRACE("dropped EXT_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),network->id()); + _sendErrorNeedCredentials(RR,peer,nwid); peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -681,6 +679,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr

received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,true); } else { TRACE("dropped EXT_FRAME from %s(%s): we are not connected to network %.16llx",source().toString().c_str(),_path->address().toString().c_str(),at(ZT_PROTO_VERB_FRAME_IDX_NETWORK_ID)); + _sendErrorNeedCredentials(RR,peer,nwid); peer->received(_path,hops(),packetId(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { @@ -737,7 +736,7 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared if (!auth) { if ((!network)||(network->id() != nwid)) network = RR->node->network(nwid); - const bool authOnNet = ((network)&&(network->gate(peer,verb(),packetId()))); + const bool authOnNet = ((network)&&(network->gate(peer))); trustEstablished |= authOnNet; if (authOnNet||RR->mc->cacheAuthorized(peer->address(),nwid,now)) { auth = true; @@ -986,7 +985,6 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const Shared _path->send(RR,outp.data(),outp.size(),RR->node->now()); } } - peer->received(_path,hops(),packetId(),Packet::VERB_NETWORK_CONFIG,0,Packet::VERB_NOP,false); } catch ( ... ) { TRACE("dropped NETWORK_CONFIG_REFRESH from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); @@ -1020,7 +1018,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar } } - const bool trustEstablished = ((network)&&(network->gate(peer,verb(),packetId()))); + const bool trustEstablished = ((network)&&(network->gate(peer))); if ( ( trustEstablished || RR->mc->cacheAuthorized(peer->address(),nwid,RR->node->now()) ) && (gatherLimit > 0) ) { Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER); @@ -1067,8 +1065,9 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share network->addCredential(com); } - if (!network->gate(peer,verb(),packetId())) { + if (!network->gate(peer)) { TRACE("dropped MULTICAST_FRAME from %s(%s): not a member of private network %.16llx",peer->address().toString().c_str(),_path->address().toString().c_str(),(unsigned long long)network->id()); + _sendErrorNeedCredentials(RR,peer,nwid); peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); return true; } @@ -1143,6 +1142,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); } else { + _sendErrorNeedCredentials(RR,peer,nwid); peer->received(_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false); } } catch ( ... ) { @@ -1288,7 +1288,7 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt peer->received(_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false); return true; } - if (network->gate(peer,verb(),packetId())) + if (network->gate(peer)) reportFlags |= ZT_CIRCUIT_TEST_REPORT_FLAGS_UPSTREAM_AUTHORIZED_IN_PATH; } else { TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str()); @@ -1479,6 +1479,19 @@ bool IncomingPacket::_doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const return true; } +void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,const SharedPtr &peer,const uint64_t nwid) +{ + if (peer->rateGateOutgoingComRequest(RR->node->now())) { + Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR); + outp.append((uint8_t)verb()); + outp.append(packetId()); + outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); + outp.append(nwid); + outp.armor(peer->key(),true); + _path->send(RR,outp.data(),outp.size(),RR->node->now()); + } +} + void IncomingPacket::computeSalsa2012Sha512ProofOfWork(unsigned int difficulty,const void *challenge,unsigned int challengeLength,unsigned char result[16]) { unsigned char salsabuf[131072]; // 131072 == protocol constant, size of memory buffer for this proof of work function diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index 86c2b5e7b..c36322161 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -154,6 +154,8 @@ private: bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,const SharedPtr &peer); bool _doREQUEST_PROOF_OF_WORK(const RuntimeEnvironment *RR,const SharedPtr &peer); + void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,const SharedPtr &peer,const uint64_t nwid); + uint64_t _receiveTime; SharedPtr _path; }; diff --git a/node/Network.cpp b/node/Network.cpp index 601395d00..52abbcf9a 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -50,6 +50,7 @@ static const char *_rtn(const ZT_VirtualNetworkRuleType rt) case ZT_NETWORK_RULE_ACTION_DROP: return "ACTION_DROP"; case ZT_NETWORK_RULE_ACTION_ACCEPT: return "ACTION_ACCEPT"; case ZT_NETWORK_RULE_ACTION_TEE: return "ACTION_TEE"; + case ZT_NETWORK_RULE_ACTION_WATCH: return "ACTION_WATCH"; case ZT_NETWORK_RULE_ACTION_REDIRECT: return "ACTION_REDIRECT"; case ZT_NETWORK_RULE_ACTION_DEBUG_LOG: return "ACTION_DEBUG_LOG"; case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: return "MATCH_SOURCE_ZEROTIER_ADDRESS"; @@ -882,7 +883,7 @@ uint64_t Network::handleConfigChunk(const Packet &chunk,unsigned int ptr) const unsigned int start = ptr; ptr += 8; // skip network ID, which is already obviously known - const uint16_t chunkLen = chunk.at(ptr); ptr += 2; + const unsigned int chunkLen = chunk.at(ptr); ptr += 2; const void *chunkData = chunk.field(ptr,chunkLen); ptr += chunkLen; Mutex::Lock _l(_lock); @@ -975,8 +976,6 @@ uint64_t Network::handleConfigChunk(const Packet &chunk,unsigned int ptr) if (c->updateId != configUpdateId) { c->updateId = configUpdateId; - for(int i=0;ihaveChunkIds[i] = 0; c->haveChunks = 0; c->haveBytes = 0; } @@ -1065,7 +1064,7 @@ void Network::requestConfiguration() RR->sw->send(outp,true); } -bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId) +bool Network::gate(const SharedPtr &peer) { const uint64_t now = RR->node->now(); Mutex::Lock _l(_lock); @@ -1081,15 +1080,6 @@ bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uin m->likingMulticasts(now); } return true; - } else { - if (peer->rateGateRequestCredentials(now)) { - Packet outp(peer->address(),RR->identity.address(),Packet::VERB_ERROR); - outp.append((uint8_t)verb); - outp.append(packetId); - outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE); - outp.append(_id); - RR->sw->send(outp,true); - } } } } catch ( ... ) { @@ -1098,11 +1088,6 @@ bool Network::gate(const SharedPtr &peer,const Packet::Verb verb,const uin return false; } -bool Network::gateMulticastGatherReply(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId) -{ - return ( (peer->address() == controller()) || RR->topology->isUpstream(peer->identity()) || gate(peer,verb,packetId) || _config.isAnchor(peer->address()) ); -} - void Network::clean() { const uint64_t now = RR->node->now(); diff --git a/node/Network.hpp b/node/Network.hpp index 128c46683..527d30481 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -212,21 +212,8 @@ public: /** * Determine whether this peer is permitted to communicate on this network - * - * This also performs certain periodic actions such as pushing renewed - * credentials to peers, so like the filters it is not side-effect-free. - * - * @param peer Peer to check - * @param verb Packet verb - * @param packetId Packet ID - * @return True if peer is allowed to communicate on this network */ - bool gate(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); - - /** - * Check whether this peer is allowed to provide multicast info for this network - */ - bool gateMulticastGatherReply(const SharedPtr &peer,const Packet::Verb verb,const uint64_t packetId); + bool gate(const SharedPtr &peer); /** * Do periodic cleanup and housekeeping tasks diff --git a/node/Node.hpp b/node/Node.hpp index 114625314..ddc52651a 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -267,17 +267,19 @@ public: } /** - * Check whether a given packet ID is something we are expecting a reply to + * Check whether a given packet ID is something we are expecting a reply to (and erase from list) * * @param packetId Packet ID to check * @return True if we're expecting a reply */ - inline bool expectingReplyTo(const uint64_t packetId) const + inline bool expectingReplyTo(const uint64_t packetId) { const unsigned long bucket = (unsigned long)(packetId & ZT_EXPECTING_REPLIES_BUCKET_MASK1); for(unsigned long i=0;i<=ZT_EXPECTING_REPLIES_BUCKET_MASK2;++i) { - if (_expectingRepliesTo[bucket][i] == packetId) + if (_expectingRepliesTo[bucket][i] == packetId) { + _expectingRepliesTo[bucket][i] = 0; return true; + } } return false; } diff --git a/node/Peer.cpp b/node/Peer.cpp index d742964ae..87882dadc 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -50,6 +50,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident _lastWhoisRequestReceived(0), _lastEchoRequestReceived(0), _lastComRequestReceived(0), + _lastComRequestSent(0), _lastCredentialsReceived(0), _lastTrustEstablishedPacketReceived(0), RR(renv), diff --git a/node/Peer.hpp b/node/Peer.hpp index c5ef43edb..d0589ccfd 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -395,9 +395,9 @@ public: } /** - * Rate gate requests for network COM + * Rate gate incoming requests for network COM */ - inline bool rateGateComRequest(const uint64_t now) + inline bool rateGateIncomingComRequest(const uint64_t now) { if ((now - _lastComRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) { _lastComRequestReceived = now; @@ -406,6 +406,18 @@ public: return false; } + /** + * Rate gate outgoing requests for network COM + */ + inline bool rateGateOutgoingComRequest(const uint64_t now) + { + if ((now - _lastComRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) { + _lastComRequestSent = now; + return true; + } + return false; + } + /** * Find a common set of addresses by which two peers can link, if any * @@ -465,6 +477,7 @@ private: uint64_t _lastWhoisRequestReceived; uint64_t _lastEchoRequestReceived; uint64_t _lastComRequestReceived; + uint64_t _lastComRequestSent; uint64_t _lastCredentialsReceived; uint64_t _lastTrustEstablishedPacketReceived; const RuntimeEnvironment *RR;