Browse Source

Clean up PUSH_DIRECT_PATH limits a bit more and make them a bit smarter.

Adam Ierymenko 9 years ago
parent
commit
da93712846
3 changed files with 27 additions and 16 deletions
  1. 5 5
      node/Constants.hpp
  2. 15 10
      node/IncomingPacket.cpp
  3. 7 1
      node/InetAddress.hpp

+ 5 - 5
node/Constants.hpp

@@ -347,11 +347,6 @@
  */
  */
 #define ZT_DIRECT_PATH_PUSH_INTERVAL 120000
 #define ZT_DIRECT_PATH_PUSH_INTERVAL 120000
 
 
-/**
- * Maximum number of endpoints to contact per address type (to limit pushes like GitHub issue #235)
- */
-#define ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE 5
-
 /**
 /**
  * Time horizon for push direct paths cutoff
  * Time horizon for push direct paths cutoff
  */
  */
@@ -366,6 +361,11 @@
  */
  */
 #define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 5
 #define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 5
 
 
+/**
+ * Maximum number of paths per IP scope (e.g. global, link-local) and family (e.g. v4/v6)
+ */
+#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 1
+
 /**
 /**
  * A test pseudo-network-ID that can be joined
  * A test pseudo-network-ID that can be joined
  *
  *

+ 15 - 10
node/IncomingPacket.cpp

@@ -901,16 +901,19 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
 {
 {
 	try {
 	try {
 		const uint64_t now = RR->node->now();
 		const uint64_t now = RR->node->now();
+
+		// First, subject this to a rate limit
 		if (!peer->shouldRespondToDirectPathPush(now)) {
 		if (!peer->shouldRespondToDirectPathPush(now)) {
 			TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_remoteAddress.toString().c_str());
 			TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_remoteAddress.toString().c_str());
 			return true;
 			return true;
 		}
 		}
 
 
-		const Path *currentBest = peer->getBestPath(now);
+		// Second, limit addresses by scope and type
+		uint8_t countPerScope[ZT_INETADDRESS_MAX_SCOPE+1][2]; // [][0] is v4, [][1] is v6
+		memset(countPerScope,0,sizeof(countPerScope));
 
 
 		unsigned int count = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD);
 		unsigned int count = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD);
 		unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2;
 		unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2;
-		unsigned int v4Count = 0,v6Count = 0;
 
 
 		while (count--) { // if ptr overflows Buffer will throw
 		while (count--) { // if ptr overflows Buffer will throw
 			// TODO: some flags are not yet implemented
 			// TODO: some flags are not yet implemented
@@ -925,20 +928,22 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
 				case 4: {
 				case 4: {
 					InetAddress a(field(ptr,4),4,at<uint16_t>(ptr + 4));
 					InetAddress a(field(ptr,4),4,at<uint16_t>(ptr + 4));
 					if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) ) {
 					if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) ) {
-						TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
-						if (v4Count++ < ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE) {
-							if ((!currentBest)||(currentBest->address() != a))
-								peer->attemptToContactAt(RR,_localAddress,a,now);
+						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(RR,_localAddress,a,now);
+						} else {
+							TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
 						}
 						}
 					}
 					}
 				}	break;
 				}	break;
 				case 6: {
 				case 6: {
 					InetAddress a(field(ptr,16),16,at<uint16_t>(ptr + 16));
 					InetAddress a(field(ptr,16),16,at<uint16_t>(ptr + 16));
 					if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) ) {
 					if ( ((flags & 0x01) == 0) && (Path::isAddressValidForPath(a)) ) {
-						TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
-						if (v6Count++ < ZT_PUSH_DIRECT_PATHS_MAX_ENDPOINTS_PER_TYPE) {
-							if ((!currentBest)||(currentBest->address() != a))
-								peer->attemptToContactAt(RR,_localAddress,a,now);
+						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(RR,_localAddress,a,now);
+						} else {
+							TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
 						}
 						}
 					}
 					}
 				}	break;
 				}	break;

+ 7 - 1
node/InetAddress.hpp

@@ -42,6 +42,11 @@
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
+/**
+ * Maximum integer value of enum IpScope
+ */
+#define ZT_INETADDRESS_MAX_SCOPE 7
+
 /**
 /**
  * Extends sockaddr_storage with friendly C++ methods
  * Extends sockaddr_storage with friendly C++ methods
  *
  *
@@ -66,7 +71,8 @@ struct InetAddress : public sockaddr_storage
 	 * IP address scope
 	 * IP address scope
 	 *
 	 *
 	 * Note that these values are in ascending order of path preference and
 	 * Note that these values are in ascending order of path preference and
-	 * MUST remain that way or Path must be changed to reflect.
+	 * MUST remain that way or Path must be changed to reflect. Also be sure
+	 * to change ZT_INETADDRESS_MAX_SCOPE if the max changes.
 	 */
 	 */
 	enum IpScope
 	enum IpScope
 	{
 	{