Adam Ierymenko 9 years ago
parent
commit
404a0bbddd
6 changed files with 176 additions and 64 deletions
  1. 2 9
      node/Constants.hpp
  2. 4 3
      node/IncomingPacket.cpp
  3. 133 0
      node/Membership.cpp
  4. 18 44
      node/Membership.hpp
  5. 18 0
      node/NetworkConfig.hpp
  6. 1 8
      node/Packet.hpp

+ 2 - 9
node/Constants.hpp

@@ -309,13 +309,6 @@
  */
  */
 #define ZT_NAT_T_TACTICAL_ESCALATION_DELAY 1000
 #define ZT_NAT_T_TACTICAL_ESCALATION_DELAY 1000
 
 
-/**
- * How long (max) to remember network certificates of membership?
- *
- * This only applies to networks we don't belong to.
- */
-#define ZT_PEER_NETWORK_COM_EXPIRATION 3600000
-
 /**
 /**
  * Sanity limit on maximum bridge routes
  * Sanity limit on maximum bridge routes
  *
  *
@@ -330,7 +323,7 @@
 /**
 /**
  * If there is no known route, spam to up to this many active bridges
  * If there is no known route, spam to up to this many active bridges
  */
  */
-#define ZT_MAX_BRIDGE_SPAM 16
+#define ZT_MAX_BRIDGE_SPAM 32
 
 
 /**
 /**
  * Interval between direct path pushes in milliseconds
  * Interval between direct path pushes in milliseconds
@@ -357,7 +350,7 @@
 #define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 4
 #define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 4
 
 
 /**
 /**
- * Enable support for old Dictionary based network configs
+ * Enable support for older network configurations from older (pre-1.1.6) controllers
  */
  */
 #define ZT_SUPPORT_OLD_STYLE_NETCONF 1
 #define ZT_SUPPORT_OLD_STYLE_NETCONF 1
 
 

+ 4 - 3
node/IncomingPacket.cpp

@@ -709,7 +709,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S
 			p += com.deserialize(*this,p);
 			p += com.deserialize(*this,p);
 			LockingPtr<Membership> m = peer->membership(com.networkId(),true);
 			LockingPtr<Membership> m = peer->membership(com.networkId(),true);
 			if (!m) return true; // sanity check
 			if (!m) return true; // sanity check
-			m->addCredential(RR,now,com);
+			if (m->addCredential(RR,now,com) == 1) return false; // wait for WHOIS
 		}
 		}
 		++p; // skip trailing 0 after COMs if present
 		++p; // skip trailing 0 after COMs if present
 
 
@@ -719,14 +719,15 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S
 				p += cap.deserialize(*this,p);
 				p += cap.deserialize(*this,p);
 				LockingPtr<Membership> m = peer->membership(cap.networkId(),true);
 				LockingPtr<Membership> m = peer->membership(cap.networkId(),true);
 				if (!m) return true; // sanity check
 				if (!m) return true; // sanity check
-				m->addCredential(RR,now,cap);
+				if (m->addCredential(RR,now,cap) == 1) return false; // wait for WHOIS
 			}
 			}
+
 			const unsigned int numTags = at<uint16_t>(p); p += 2;
 			const unsigned int numTags = at<uint16_t>(p); p += 2;
 			for(unsigned int i=0;i<numTags;++i) {
 			for(unsigned int i=0;i<numTags;++i) {
 				p += tag.deserialize(*this,p);
 				p += tag.deserialize(*this,p);
 				LockingPtr<Membership> m = peer->membership(tag.networkId(),true);
 				LockingPtr<Membership> m = peer->membership(tag.networkId(),true);
 				if (!m) return true; // sanity check
 				if (!m) return true; // sanity check
-				m->addCredential(RR,now,tag);
+				if (m->addCredential(RR,now,tag) == 1) return false; // wait for WHOIS
 			}
 			}
 		}
 		}
 
 

+ 133 - 0
node/Membership.cpp

@@ -0,0 +1,133 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2016  ZeroTier, Inc.  https://www.zerotier.com/
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "Membership.hpp"
+#include "RuntimeEnvironment.hpp"
+#include "Peer.hpp"
+#include "Topology.hpp"
+#include "Switch.hpp"
+#include "Packet.hpp"
+#include "Node.hpp"
+
+#define ZT_CREDENTIAL_PUSH_EVERY (ZT_NETWORK_AUTOCONF_DELAY / 2)
+
+namespace ZeroTier {
+
+bool Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Peer &peer,const NetworkConfig &nconf,const uint32_t *capIds,const unsigned int capCount,const uint32_t *tagIds,const unsigned int tagCount)
+{
+	try {
+		Buffer<ZT_PROTO_MAX_PACKET_LENGTH> capsAndTags;
+
+		capsAndTags.addSize(2);
+		unsigned int appendedCaps = 0;
+		for(unsigned int i=0;i<capCount;++i) {
+			CState *cs = _caps.get(capIds[i]);
+			if ((now - cs->lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) {
+				if ((capsAndTags.size() + sizeof(Capability)) > (ZT_PROTO_MAX_PACKET_LENGTH - sizeof(CertificateOfMembership)))
+					break;
+				const Capability *c = nconf.capability(capIds[i]);
+				if (c) {
+					c->serialize(capsAndTags);
+					++appendedCaps;
+					cs->lastPushed = now;
+				}
+			}
+		}
+		capsAndTags.setAt<uint16_t>(0,(uint16_t)appendedCaps);
+
+		const unsigned int tagCountPos = capsAndTags.size();
+		capsAndTags.addSize(2);
+		unsigned int appendedTags = 0;
+		for(unsigned int i=0;i<tagCount;++i) {
+			TState *ts = _tags.get(tagIds[i]);
+			if ((now - ts->lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) {
+				if ((capsAndTags.size() + sizeof(Tag)) > (ZT_PROTO_MAX_PACKET_LENGTH - sizeof(CertificateOfMembership)))
+					break;
+				const Tag *t = nconf.tag(tagIds[i]);
+				if (t) {
+					t->serialize(capsAndTags);
+					++appendedTags;
+					ts->lastPushed = now;
+				}
+			}
+		}
+		capsAndTags.setAt<uint16_t>(tagCountPos,(uint16_t)appendedTags);
+
+		if (((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY)||(appendedCaps)||(appendedTags)) {
+			Packet outp(peer.address(),RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
+			nconf.com.serialize(outp);
+			outp.append((uint8_t)0x00);
+			outp.append(capsAndTags.data(),capsAndTags.size());
+			outp.compress();
+			RR->sw->send(outp,true,0);
+			_lastPushedCom = now;
+			return true;
+		}
+	} catch ( ... ) {
+		TRACE("unable to send credentials due to unexpected exception");
+		return false;
+	}
+}
+
+int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,const CertificateOfMembership &com)
+{
+	if (com.issuedTo() != RR->identity.address())
+		return -1;
+	if (_com == com)
+		return 0;
+	const int vr = com.verify(RR);
+	if (vr == 0)
+		_com = com;
+	return vr;
+}
+
+int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Tag &tag)
+{
+	if (tag.issuedTo() != RR->identity.address())
+		return -1;
+	TState *t = _tags.get(tag.networkId());
+	if ((t)&&(t->lastReceived != 0)&&(t->tag == tag))
+		return 0;
+	const int vr = tag.verify(RR);
+	if (vr == 0) {
+		if (!t)
+			t = &(_tags[tag.networkId()]);
+		t->lastReceived = now;
+		t->tag = tag;
+	}
+	return vr;
+}
+
+int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Capability &cap)
+{
+	if (!cap.wasIssuedTo(RR->identity.address()))
+		return -1;
+	CState *c = _caps.get(cap.networkId());
+	if ((c)&&(c->lastReceived != 0)&&(c->cap == cap))
+		return 0;
+	const int vr = cap.verify(RR);
+	if (vr == 0) {
+		if (!c)
+			c = &(_caps[cap.networkId()]);
+		c->lastReceived = now;
+		c->cap = cap;
+	}
+	return vr;
+}
+
+} // namespace ZeroTier

+ 18 - 44
node/Membership.hpp

@@ -98,7 +98,21 @@ public:
 	 * @param tagCount Number of tag IDs
 	 * @param tagCount Number of tag IDs
 	 * @return True if we pushed something
 	 * @return True if we pushed something
 	 */
 	 */
-	bool sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Peer &peer,const NetworkConfig &nconf,const uint32_t *capIds,const unsigned int capCount,const uint32_t *tagIds,const unsigned int tagCount) const;
+	bool sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Peer &peer,const NetworkConfig &nconf,const uint32_t *capIds,const unsigned int capCount,const uint32_t *tagIds,const unsigned int tagCount);
+
+	/**
+	 * Send COM if needed
+	 *
+	 * @param RR Runtime environment
+	 * @param now Current time
+	 * @param peer Peer that "owns" this membership
+	 * @param nconf Network configuration
+	 * @return True if we pushed something
+	 */
+	inline bool sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint64_t now,const Peer &peer,const NetworkConfig &nconf)
+	{
+		return sendCredentialsIfNeeded(RR,now,peer,nconf,(const uint32_t *)0,0,(const uint32_t *)0,0);
+	}
 
 
 	/**
 	/**
 	 * @param nconf Network configuration
 	 * @param nconf Network configuration
@@ -127,61 +141,21 @@ public:
 	 *
 	 *
 	 * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
 	 * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
 	 */
 	 */
-	inline int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const CertificateOfMembership &com)
-	{
-		if (com.issuedTo() != RR->identity.address())
-			return -1;
-		if (_com == com)
-			return 0;
-		const int vr = com.verify(RR);
-		if (vr == 0)
-			_com = com;
-		return vr;
-	}
+	int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const CertificateOfMembership &com);
 
 
 	/**
 	/**
 	 * Validate and add a credential if signature is okay and it's otherwise good
 	 * Validate and add a credential if signature is okay and it's otherwise good
 	 *
 	 *
 	 * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
 	 * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
 	 */
 	 */
-	inline int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Tag &tag)
-	{
-		if (tag.issuedTo() != RR->identity.address())
-			return -1;
-		TState *t = _tags.get(tag.networkId());
-		if ((t)&&(t->lastReceived != 0)&&(t->tag == tag))
-			return 0;
-		const int vr = tag.verify(RR);
-		if (vr == 0) {
-			if (!t)
-				t = &(_tags[tag.networkId()]);
-			t->lastReceived = now;
-			t->tag = tag;
-		}
-		return vr;
-	}
+	int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Tag &tag);
 
 
 	/**
 	/**
 	 * Validate and add a credential if signature is okay and it's otherwise good
 	 * Validate and add a credential if signature is okay and it's otherwise good
 	 *
 	 *
 	 * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
 	 * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
 	 */
 	 */
-	inline int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Capability &cap)
-	{
-		if (!cap.wasIssuedTo(RR->identity.address()))
-			return -1;
-		CState *c = _caps.get(cap.networkId());
-		if ((c)&&(c->lastReceived != 0)&&(c->cap == cap))
-			return 0;
-		const int vr = cap.verify(RR);
-		if (vr == 0) {
-			if (!c)
-				c = &(_caps[cap.networkId()]);
-			c->lastReceived = now;
-			c->cap = cap;
-		}
-		return vr;
-	}
+	int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Capability &cap);
 
 
 	/**
 	/**
 	 * Clean up old or stale entries
 	 * Clean up old or stale entries

+ 18 - 0
node/NetworkConfig.hpp

@@ -318,6 +318,24 @@ public:
 		return false;
 		return false;
 	}
 	}
 
 
+	const Capability *capability(const uint32_t id) const
+	{
+		for(unsigned int i=0;i<capabilityCount;++i) {
+			if (capabilities[i].id() == id)
+				return &(capabilities[i]);
+		}
+		return (Capability *)0;
+	}
+
+	const Tag *tag(const uint32_t id) const
+	{
+		for(unsigned int i=0;i<tagCount;++i) {
+			if (tags[i].id() == id)
+				return &(tags[i]);
+		}
+		return (Tag *)0;
+	}
+
 	/*
 	/*
 	inline void dump() const
 	inline void dump() const
 	{
 	{

+ 1 - 8
node/Packet.hpp

@@ -704,7 +704,7 @@ public:
 		 * Network membership credential push:
 		 * Network membership credential push:
 		 *   <[...] serialized certificate of membership>
 		 *   <[...] serialized certificate of membership>
 		 *   [<[...] additional certificates of membership>]
 		 *   [<[...] additional certificates of membership>]
-		 *   <[1] null byte for backward compatibility (see below)>
+		 *   <[1] 0x00, null byte marking end of COM array>
 		 *   <[2] 16-bit number of capabilities>
 		 *   <[2] 16-bit number of capabilities>
 		 *   <[...] one or more serialized Capability>
 		 *   <[...] one or more serialized Capability>
 		 *   <[2] 16-bit number of tags>
 		 *   <[2] 16-bit number of tags>
@@ -713,13 +713,6 @@ public:
 		 * This is sent in response to ERROR_NEED_MEMBERSHIP_CERTIFICATE and may
 		 * This is sent in response to ERROR_NEED_MEMBERSHIP_CERTIFICATE and may
 		 * be pushed at any other time to keep exchanged certificates up to date.
 		 * be pushed at any other time to keep exchanged certificates up to date.
 		 *
 		 *
-		 * Protocol versions prior to 8 do not support capabilities or tags and
-		 * just expect an array of COMs. Adding a single NULL byte after the COM
-		 * array causes these older versions to harmlessly abort parsing and
-		 * ignore the newer fields. The new version checks for this null byte to
-		 * indicate the end of the COM array, since all serialized COMs begin with
-		 * non-zero bytes (see CertificateOfMembership).
-		 *
 		 * OK/ERROR are not generated.
 		 * OK/ERROR are not generated.
 		 */
 		 */
 		VERB_NETWORK_CREDENTIALS = 0x0a,
 		VERB_NETWORK_CREDENTIALS = 0x0a,