Quellcode durchsuchen

Outgoing side of packet counter for link quality reporting. Also some cleanup and a cluster mode build fix.

Adam Ierymenko vor 8 Jahren
Ursprung
Commit
2bf9145ae6
10 geänderte Dateien mit 513 neuen und 506 gelöschten Zeilen
  1. 13 31
      node/Buffer.hpp
  2. 4 4
      node/Cluster.cpp
  3. 13 13
      node/IncomingPacket.cpp
  4. 3 3
      node/Node.cpp
  5. 431 431
      node/Packet.cpp
  6. 19 6
      node/Packet.hpp
  7. 10 0
      node/Path.hpp
  8. 12 12
      node/Peer.cpp
  9. 4 2
      node/Peer.hpp
  10. 4 4
      node/Switch.cpp

+ 13 - 31
node/Buffer.hpp

@@ -79,8 +79,7 @@ public:
 	inline const_reverse_iterator rbegin() const { return const_reverse_iterator(begin()); }
 	inline const_reverse_iterator rend() const { return const_reverse_iterator(end()); }
 
-	Buffer()
-		throw() :
+	Buffer() :
 		_l(0)
 	{
 	}
@@ -419,87 +418,70 @@ public:
 	/**
 	 * Set buffer data length to zero
 	 */
-	inline void clear()
-		throw()
-	{
-		_l = 0;
-	}
+	inline void clear() { _l = 0; }
 
 	/**
 	 * Zero buffer up to size()
 	 */
-	inline void zero()
-		throw()
-	{
-		memset(_b,0,_l);
-	}
+	inline void zero() { memset(_b,0,_l); }
 
 	/**
 	 * Zero unused capacity area
 	 */
-	inline void zeroUnused()
-		throw()
-	{
-		memset(_b + _l,0,C - _l);
-	}
+	inline void zeroUnused() { memset(_b + _l,0,C - _l); }
 
 	/**
 	 * Unconditionally and securely zero buffer's underlying memory
 	 */
-	inline void burn()
-		throw()
-	{
-		Utils::burn(_b,sizeof(_b));
-	}
+	inline void burn() { Utils::burn(_b,sizeof(_b)); }
 
 	/**
 	 * @return Constant pointer to data in buffer
 	 */
-	inline const void *data() const throw() { return _b; }
+	inline const void *data() const { return _b; }
+
+	/**
+	 * @return Non-constant pointer to data in buffer
+	 */
+	inline void *unsafeData() { return _b; }
 
 	/**
 	 * @return Size of data in buffer
 	 */
-	inline unsigned int size() const throw() { return _l; }
+	inline unsigned int size() const { return _l; }
 
 	/**
 	 * @return Capacity of buffer
 	 */
-	inline unsigned int capacity() const throw() { return C; }
+	inline unsigned int capacity() const { return C; }
 
 	template<unsigned int C2>
 	inline bool operator==(const Buffer<C2> &b) const
-		throw()
 	{
 		return ((_l == b._l)&&(!memcmp(_b,b._b,_l)));
 	}
 	template<unsigned int C2>
 	inline bool operator!=(const Buffer<C2> &b) const
-		throw()
 	{
 		return ((_l != b._l)||(memcmp(_b,b._b,_l)));
 	}
 	template<unsigned int C2>
 	inline bool operator<(const Buffer<C2> &b) const
-		throw()
 	{
 		return (memcmp(_b,b._b,std::min(_l,b._l)) < 0);
 	}
 	template<unsigned int C2>
 	inline bool operator>(const Buffer<C2> &b) const
-		throw()
 	{
 		return (b < *this);
 	}
 	template<unsigned int C2>
 	inline bool operator<=(const Buffer<C2> &b) const
-		throw()
 	{
 		return !(b < *this);
 	}
 	template<unsigned int C2>
 	inline bool operator>=(const Buffer<C2> &b) const
-		throw()
 	{
 		return !(*this < b);
 	}

+ 4 - 4
node/Cluster.cpp

@@ -255,7 +255,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len)
 		// One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard")
 		char polykey[ZT_POLY1305_KEY_LEN];
 		memset(polykey,0,sizeof(polykey));
-		s20.encrypt12(polykey,polykey,sizeof(polykey));
+		s20.crypt12(polykey,polykey,sizeof(polykey));
 
 		// Compute 16-byte MAC
 		char mac[ZT_POLY1305_MAC_LEN];
@@ -267,7 +267,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len)
 
 		// Decrypt!
 		dmsg.setSize(len - 24);
-		s20.decrypt12(reinterpret_cast<const char *>(msg) + 24,const_cast<void *>(dmsg.data()),dmsg.size());
+		s20.crypt12(reinterpret_cast<const char *>(msg) + 24,const_cast<void *>(dmsg.data()),dmsg.size());
 	}
 
 	if (dmsg.size() < 4)
@@ -954,10 +954,10 @@ void Cluster::_flush(uint16_t memberId)
 		// One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard")
 		char polykey[ZT_POLY1305_KEY_LEN];
 		memset(polykey,0,sizeof(polykey));
-		s20.encrypt12(polykey,polykey,sizeof(polykey));
+		s20.crypt12(polykey,polykey,sizeof(polykey));
 
 		// Encrypt m.q in place
-		s20.encrypt12(reinterpret_cast<const char *>(m.q.data()) + 24,const_cast<char *>(reinterpret_cast<const char *>(m.q.data())) + 24,m.q.size() - 24);
+		s20.crypt12(reinterpret_cast<const char *>(m.q.data()) + 24,const_cast<char *>(reinterpret_cast<const char *>(m.q.data())) + 24,m.q.size() - 24);
 
 		// Add MAC for authentication (encrypt-then-MAC)
 		char mac[ZT_POLY1305_MAC_LEN];

+ 13 - 13
node/IncomingPacket.cpp

@@ -243,7 +243,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut
 							outp.append((uint8_t)Packet::VERB_HELLO);
 							outp.append((uint64_t)pid);
 							outp.append((uint8_t)Packet::ERROR_IDENTITY_COLLISION);
-							outp.armor(key,true);
+							outp.armor(key,true,_path->nextOutgoingCounter());
 							_path->send(RR,outp.data(),outp.size(),RR->node->now());
 						} else {
 							TRACE("rejected HELLO from %s(%s): packet failed authentication",id.address().toString().c_str(),_path->address().toString().c_str());
@@ -405,7 +405,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,const bool alreadyAut
 		RR->topology->appendCertificateOfRepresentation(outp);
 		outp.setAt(corSizeAt,(uint16_t)(outp.size() - (corSizeAt + 2)));
 
-		outp.armor(peer->key(),true);
+		outp.armor(peer->key(),true,_path->nextOutgoingCounter());
 		_path->send(RR,outp.data(),outp.size(),now);
 
 		peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version
@@ -584,7 +584,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,const SharedPtr<Peer>
 		}
 
 		if (count > 0) {
-			outp.armor(peer->key(),true);
+			outp.armor(peer->key(),true,_path->nextOutgoingCounter());
 			_path->send(RR,outp.data(),outp.size(),RR->node->now());
 		}
 
@@ -610,7 +610,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,const SharedPtr<
 					const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port);
 					if (RR->node->shouldUsePathForZeroTierTraffic(with,_path->localAddress(),atAddr)) {
 						RR->node->putPacket(_path->localAddress(),atAddr,"ABRE",4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls
-						rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now(),false);
+						rendezvousWith->attemptToContactAt(_path->localAddress(),atAddr,RR->node->now(),false,0);
 						TRACE("RENDEZVOUS from %s says %s might be at %s, sent verification attempt",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
 					} else {
 						TRACE("RENDEZVOUS from %s says %s might be at %s, ignoring since path is not suitable",peer->address().toString().c_str(),with.toString().c_str(),atAddr.toString().c_str());
@@ -732,7 +732,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<P
 				outp.append((uint8_t)Packet::VERB_EXT_FRAME);
 				outp.append((uint64_t)packetId());
 				outp.append((uint64_t)nwid);
-				outp.armor(peer->key(),true);
+				outp.armor(peer->key(),true,_path->nextOutgoingCounter());
 				_path->send(RR,outp.data(),outp.size(),RR->node->now());
 			}
 
@@ -762,7 +762,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr<Peer>
 		outp.append((uint64_t)pid);
 		if (size() > ZT_PACKET_IDX_PAYLOAD)
 			outp.append(reinterpret_cast<const unsigned char *>(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD);
-		outp.armor(peer->key(),true);
+		outp.armor(peer->key(),true,_path->nextOutgoingCounter());
 		_path->send(RR,outp.data(),outp.size(),RR->node->now());
 
 		peer->received(_path,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP,false);
@@ -957,7 +957,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
 			outp.append(requestPacketId);
 			outp.append((unsigned char)Packet::ERROR_UNSUPPORTED_OPERATION);
 			outp.append(nwid);
-			outp.armor(peer->key(),true);
+			outp.armor(peer->key(),true,_path->nextOutgoingCounter());
 			_path->send(RR,outp.data(),outp.size(),RR->node->now());
 		}
 
@@ -984,7 +984,7 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,const Shared
 				outp.append((uint64_t)packetId());
 				outp.append((uint64_t)network->id());
 				outp.append((uint64_t)configUpdateId);
-				outp.armor(peer->key(),true);
+				outp.armor(peer->key(),true,_path->nextOutgoingCounter());
 				_path->send(RR,outp.data(),outp.size(),RR->node->now());
 			}
 		}
@@ -1033,7 +1033,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,const Shar
 			outp.append((uint32_t)mg.adi());
 			const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit);
 			if (gatheredLocally > 0) {
-				outp.armor(peer->key(),true);
+				outp.armor(peer->key(),true,_path->nextOutgoingCounter());
 				_path->send(RR,outp.data(),outp.size(),RR->node->now());
 			}
 
@@ -1140,7 +1140,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share
 				outp.append((uint32_t)to.adi());
 				outp.append((unsigned char)0x02); // flag 0x02 = contains gather results
 				if (RR->mc->gather(peer->address(),nwid,to,outp,gatherLimit)) {
-					outp.armor(peer->key(),true);
+					outp.armor(peer->key(),true,_path->nextOutgoingCounter());
 					_path->send(RR,outp.data(),outp.size(),RR->node->now());
 				}
 			}
@@ -1198,7 +1198,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
 					if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->localAddress(),a)) ) {
 						if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) {
 							TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
-							peer->attemptToContactAt(InetAddress(),a,now,false);
+							peer->attemptToContactAt(InetAddress(),a,now,false,0);
 						} else {
 							TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
 						}
@@ -1217,7 +1217,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
 					if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(peer->address(),_path->localAddress(),a)) ) {
 						if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) {
 							TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
-							peer->attemptToContactAt(InetAddress(),a,now,false);
+							peer->attemptToContactAt(InetAddress(),a,now,false,0);
 						} else {
 							TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
 						}
@@ -1447,7 +1447,7 @@ void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,cons
 		outp.append(packetId());
 		outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
 		outp.append(nwid);
-		outp.armor(peer->key(),true);
+		outp.armor(peer->key(),true,_path->nextOutgoingCounter());
 		_path->send(RR,outp.data(),outp.size(),now);
 	}
 }

+ 3 - 3
node/Node.cpp

@@ -180,7 +180,7 @@ public:
 				for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) {
 					const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()];
 					if (addr.ss_family == AF_INET) {
-						p->sendHELLO(InetAddress(),addr,_now);
+						p->sendHELLO(InetAddress(),addr,_now,0);
 						contacted = true;
 						break;
 					}
@@ -190,7 +190,7 @@ public:
 				for(unsigned long k=0,ptr=(unsigned long)RR->node->prng();k<(unsigned long)upstreamStableEndpoints->size();++k) {
 					const InetAddress &addr = (*upstreamStableEndpoints)[ptr++ % upstreamStableEndpoints->size()];
 					if (addr.ss_family == AF_INET6) {
-						p->sendHELLO(InetAddress(),addr,_now);
+						p->sendHELLO(InetAddress(),addr,_now,0);
 						contacted = true;
 						break;
 					}
@@ -200,7 +200,7 @@ public:
 			if ((!contacted)&&(_bestCurrentUpstream)) {
 				const SharedPtr<Path> up(_bestCurrentUpstream->getBestPath(_now,true));
 				if (up)
-					p->sendHELLO(up->localAddress(),up->address(),_now);
+					p->sendHELLO(up->localAddress(),up->address(),_now,up->nextOutgoingCounter());
 			}
 
 			lastReceiveFromUpstream = std::max(p->lastReceive(),lastReceiveFromUpstream);

Datei-Diff unterdrückt, da er zu groß ist
+ 431 - 431
node/Packet.cpp


+ 19 - 6
node/Packet.hpp

@@ -351,7 +351,7 @@ namespace ZeroTier {
  * ZeroTier packet
  *
  * Packet format:
- *   <[8] 64-bit random packet ID and crypto initialization vector>
+ *   <[8] 64-bit packet ID / crypto IV / packet counter>
  *   <[5] destination ZT address>
  *   <[5] source ZT address>
  *   <[1] flags/cipher/hops>
@@ -362,6 +362,14 @@ namespace ZeroTier {
  *
  * Packets smaller than 28 bytes are invalid and silently discarded.
  *
+ * The 64-bit packet ID is a strongly random value used as a crypto IV.
+ * Its least significant 3 bits are also used as a monotonically increasing
+ * (and looping) counter for sending packets to a particular recipient. This
+ * can be used for link quality monitoring and reporting and has no crypto
+ * impact as it does not increase the likelihood of an IV collision. (The
+ * crypto we use is not sensitive to the nature of the IV, only that it does
+ * not repeat.)
+ *
  * The flags/cipher/hops bit field is: FFCCCHHH where C is a 3-bit cipher
  * selection allowing up to 7 cipher suites, F is outside-envelope flags,
  * and H is hop count.
@@ -1102,10 +1110,8 @@ public:
 	};
 
 #ifdef ZT_TRACE
-	static const char *verbString(Verb v)
-		throw();
-	static const char *errorString(ErrorCode e)
-		throw();
+	static const char *verbString(Verb v);
+	static const char *errorString(ErrorCode e);
 #endif
 
 	template<unsigned int C2>
@@ -1303,6 +1309,12 @@ public:
 	/**
 	 * Get this packet's unique ID (the IV field interpreted as uint64_t)
 	 *
+	 * Note that the least significant 3 bits of this ID will change when armor()
+	 * is called to armor the packet for transport. This is because armor() will
+	 * mask the last 3 bits against the send counter for QoS monitoring use prior
+	 * to actually using the IV to encrypt and MAC the packet. Be aware of this
+	 * when grabbing the packetId of a new packet prior to armor/send.
+	 *
 	 * @return Packet ID
 	 */
 	inline uint64_t packetId() const { return at<uint64_t>(ZT_PACKET_IDX_IV); }
@@ -1337,8 +1349,9 @@ public:
 	 *
 	 * @param key 32-byte key
 	 * @param encryptPayload If true, encrypt packet payload, else just MAC
+	 * @param counter Packet send counter for destination peer -- only least significant 3 bits are used
 	 */
-	void armor(const void *key,bool encryptPayload);
+	void armor(const void *key,bool encryptPayload,unsigned int counter);
 
 	/**
 	 * Verify and (if encrypted) decrypt packet

+ 10 - 0
node/Path.hpp

@@ -105,6 +105,7 @@ public:
 		_lastOut(0),
 		_lastIn(0),
 		_lastTrustEstablishedPacketReceived(0),
+		_outgoingPacketCounter(0),
 		_addr(),
 		_localAddress(),
 		_ipScope(InetAddress::IP_SCOPE_NONE)
@@ -115,6 +116,7 @@ public:
 		_lastOut(0),
 		_lastIn(0),
 		_lastTrustEstablishedPacketReceived(0),
+		_outgoingPacketCounter(0),
 		_addr(addr),
 		_localAddress(localAddress),
 		_ipScope(addr.ipScope())
@@ -241,10 +243,18 @@ public:
 	 */
 	inline uint64_t lastIn() const { return _lastIn; }
 
+	/**
+	 * Return and increment outgoing packet counter (used with Packet::armor())
+	 *
+	 * @return Next value that should be used for outgoing packet counter (only least significant 3 bits are used)
+	 */
+	inline unsigned int nextOutgoingCounter() { return _outgoingPacketCounter++; }
+
 private:
 	uint64_t _lastOut;
 	uint64_t _lastIn;
 	uint64_t _lastTrustEstablishedPacketReceived;
+	unsigned int _outgoingPacketCounter;
 	InetAddress _addr;
 	InetAddress _localAddress;
 	InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often

+ 12 - 12
node/Peer.cpp

@@ -101,7 +101,7 @@ void Peer::received(
 					outp.append(redirectTo.rawIpData(),16);
 				}
 				outp.append((uint16_t)redirectTo.port());
-				outp.armor(_key,true);
+				outp.armor(_key,true,path->nextOutgoingCounter());
 				path->send(RR,outp.data(),outp.size(),now);
 			} else {
 				// For older peers we use RENDEZVOUS to coax them into contacting us elsewhere.
@@ -116,7 +116,7 @@ void Peer::received(
 					outp.append((uint8_t)16);
 					outp.append(redirectTo.rawIpData(),16);
 				}
-				outp.armor(_key,true);
+				outp.armor(_key,true,path->nextOutgoingCounter());
 				path->send(RR,outp.data(),outp.size(),now);
 			}
 			suboptimalPath = true;
@@ -203,7 +203,7 @@ void Peer::received(
 #endif
 			} else {
 				TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str());
-				attemptToContactAt(path->localAddress(),path->address(),now,true);
+				attemptToContactAt(path->localAddress(),path->address(),now,true,path->nextOutgoingCounter());
 				path->sent(now);
 			}
 		}
@@ -277,7 +277,7 @@ void Peer::received(
 
 					if (count) {
 						outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count);
-						outp.armor(_key,true);
+						outp.armor(_key,true,path->nextOutgoingCounter());
 						path->send(RR,outp.data(),outp.size(),now);
 					}
 				}
@@ -342,7 +342,7 @@ SharedPtr<Path> Peer::getBestPath(uint64_t now,bool includeExpired)
 	}
 }
 
-void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now)
+void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter)
 {
 	Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO);
 
@@ -383,22 +383,22 @@ void Peer::sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,u
 	RR->node->expectReplyTo(outp.packetId());
 
 	if (atAddress) {
-		outp.armor(_key,false); // false == don't encrypt full payload, but add MAC
+		outp.armor(_key,false,counter); // false == don't encrypt full payload, but add MAC
 		RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size());
 	} else {
 		RR->sw->send(outp,false); // false == don't encrypt full payload, but add MAC
 	}
 }
 
-void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello)
+void Peer::attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter)
 {
 	if ( (!sendFullHello) && (_vProto >= 5) && (!((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0))) ) {
 		Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO);
 		RR->node->expectReplyTo(outp.packetId());
-		outp.armor(_key,true);
+		outp.armor(_key,true,counter);
 		RR->node->putPacket(localAddr,atAddress,outp.data(),outp.size());
 	} else {
-		sendHELLO(localAddr,atAddress,now);
+		sendHELLO(localAddr,atAddress,now,counter);
 	}
 }
 
@@ -408,7 +408,7 @@ void Peer::tryMemorizedPath(uint64_t now)
 		_lastTriedMemorizedPath = now;
 		InetAddress mp;
 		if (RR->node->externalPathLookup(_id.address(),-1,mp))
-			attemptToContactAt(InetAddress(),mp,now,true);
+			attemptToContactAt(InetAddress(),mp,now,true,0);
 	}
 }
 
@@ -430,7 +430,7 @@ bool Peer::doPingAndKeepalive(uint64_t now,int inetAddressFamily)
 
 	if (bestp >= 0) {
 		if ( ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) || (_paths[bestp].path->needsHeartbeat(now)) ) {
-			attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false);
+			attemptToContactAt(_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false,_paths[bestp].path->nextOutgoingCounter());
 			_paths[bestp].path->sent(now);
 		}
 		return true;
@@ -454,7 +454,7 @@ void Peer::resetWithinScope(InetAddress::IpScope scope,int inetAddressFamily,uin
 	Mutex::Lock _l(_paths_m);
 	for(unsigned int p=0;p<_numPaths;++p) {
 		if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) {
-			attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now,false);
+			attemptToContactAt(_paths[p].path->localAddress(),_paths[p].path->address(),now,false,_paths[p].path->nextOutgoingCounter());
 			_paths[p].path->sent(now);
 			_paths[p].lastReceive = 0; // path will not be used unless it speaks again
 		}

+ 4 - 2
node/Peer.hpp

@@ -150,8 +150,9 @@ public:
 	 * @param localAddr Local address
 	 * @param atAddress Destination address
 	 * @param now Current time
+	 * @param counter Outgoing packet counter
 	 */
-	void sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now);
+	void sendHELLO(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter);
 
 	/**
 	 * Send ECHO (or HELLO for older peers) to this peer at the given address
@@ -162,8 +163,9 @@ public:
 	 * @param atAddress Destination address
 	 * @param now Current time
 	 * @param sendFullHello If true, always send a full HELLO instead of just an ECHO
+	 * @param counter Outgoing packet counter
 	 */
-	void attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello);
+	void attemptToContactAt(const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,bool sendFullHello,unsigned int counter);
 
 	/**
 	 * Try a memorized or statically defined path if any are known

+ 4 - 4
node/Switch.cpp

@@ -88,7 +88,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from
 				if ((now - _lastBeaconResponse) >= 2500) { // limit rate of responses
 					_lastBeaconResponse = now;
 					Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP);
-					outp.armor(peer->key(),true);
+					outp.armor(peer->key(),true,path->nextOutgoingCounter());
 					path->send(RR,outp.data(),outp.size(),now);
 				}
 			}
@@ -777,7 +777,7 @@ bool Switch::_trySend(Packet &packet,bool encrypt)
 			if ((clusterMostRecentMemberId < 0)||(viaPath->lastIn() > clusterMostRecentTs)) {
 #endif
 				if ((now - viaPath->lastOut()) > std::max((now - viaPath->lastIn()) * 4,(uint64_t)ZT_PATH_MIN_REACTIVATE_INTERVAL)) {
-					peer->attemptToContactAt(viaPath->localAddress(),viaPath->address(),now,false);
+					peer->attemptToContactAt(viaPath->localAddress(),viaPath->address(),now,false,viaPath->nextOutgoingCounter());
 					viaPath->sent(now);
 				}
 #ifdef ZT_ENABLE_CLUSTER
@@ -825,14 +825,14 @@ bool Switch::_trySend(Packet &packet,bool encrypt)
 	if (trustedPathId) {
 		packet.setTrusted(trustedPathId);
 	} else {
-		packet.armor((clusterMostRecentMemberId >= 0) ? clusterPeerSecret : peer->key(),encrypt);
+		packet.armor((clusterMostRecentMemberId >= 0) ? clusterPeerSecret : peer->key(),encrypt,(viaPath) ? viaPath->nextOutgoingCounter() : 0);
 	}
 #else
 	const uint64_t trustedPathId = RR->topology->getOutboundPathTrust(viaPath->address());
 	if (trustedPathId) {
 		packet.setTrusted(trustedPathId);
 	} else {
-		packet.armor(peer->key(),encrypt);
+		packet.armor(peer->key(),encrypt,viaPath->nextOutgoingCounter());
 	}
 #endif
 

Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.