فهرست منبع

It builds... almost ready to test some rules engine stuff.

Adam Ierymenko 9 سال پیش
والد
کامیت
00fd9c3a15
14فایلهای تغییر یافته به همراه121 افزوده شده و 154 حذف شده
  1. 21 14
      node/Capability.hpp
  2. 28 27
      node/IncomingPacket.cpp
  3. 12 10
      node/Membership.cpp
  4. 3 3
      node/Membership.hpp
  5. 1 14
      node/Multicaster.cpp
  6. 0 2
      node/Multicaster.hpp
  7. 1 1
      node/Network.cpp
  8. 36 0
      node/Network.hpp
  9. 2 3
      node/Packet.cpp
  10. 2 2
      node/Packet.hpp
  11. 1 3
      node/Peer.cpp
  12. 7 46
      node/Switch.cpp
  13. 7 1
      node/Tag.hpp
  14. 0 28
      node/Topology.cpp

+ 21 - 14
node/Capability.hpp

@@ -71,16 +71,18 @@ public:
 	/**
 	 * @param id Capability ID
 	 * @param nwid Network ID
+	 * @param ts Timestamp (at controller)
 	 * @param expiration Expiration relative to network config timestamp
 	 * @param name Capability short name (max strlen == ZT_MAX_CAPABILITY_NAME_LENGTH, overflow ignored)
 	 * @param mccl Maximum custody chain length (1 to create non-transferrable capability)
 	 * @param rules Network flow rules for this capability
 	 * @param ruleCount Number of flow rules
 	 */
-	Capability(uint32_t id,uint64_t nwid,uint64_t expiration,const char *name,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount)
+	Capability(uint32_t id,uint64_t nwid,uint64_t ts,uint64_t expiration,const char *name,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount)
 	{
 		memset(this,0,sizeof(Capability));
 		_nwid = nwid;
+		_ts = ts;
 		_expiration = expiration;
 		_id = id;
 		_maxCustodyChainLength = (mccl > 0) ? ((mccl < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) ? mccl : (unsigned int)ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) : 1;
@@ -115,20 +117,22 @@ public:
 	inline uint64_t expiration() const { return _expiration; }
 
 	/**
-	 * Check to see if a given address is a 'to' address in the custody chain
-	 *
-	 * This does not actually do certificate checking. That must be done with verify().
-	 *
-	 * @param a Address to check
-	 * @return True if address is present
+	 * @return Timestamp
+	 */
+	inline uint64_t timestamp() const { return _ts; }
+
+	/**
+	 * @return Last 'to' address in chain of custody
 	 */
-	inline bool wasIssuedTo(const Address &a) const
+	inline Address issuedTo() const
 	{
+		Address i2;
 		for(unsigned int i=0;i<ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH;++i) {
-			if (_custody[i].to == a)
-				return true;
+			if (!_custody[i].to)
+				return i2;
+			else i2 = _custody[i].to;
 		}
-		return false;
+		return i2;
 	}
 
 	/**
@@ -265,9 +269,10 @@ public:
 	{
 		if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
 
-		b.append(_id);
 		b.append(_nwid);
+		b.append(_ts);
 		b.append(_expiration);
+		b.append(_id);
 		serializeRules(b,_rules,_ruleCount);
 		b.append((uint8_t)_maxCustodyChainLength);
 
@@ -375,15 +380,16 @@ public:
 
 		unsigned int p = startAt;
 
-		_id = b.template at<uint32_t>(p); p += 4;
 		_nwid = b.template at<uint64_t>(p); p += 8;
+		_ts = b.template at<uint64_t>(p); p += 8;
 		_expiration = b.template at<uint64_t>(p); p += 8;
+		_id = b.template at<uint32_t>(p); p += 4;
 		deserializeRules(b,p,_rules,_ruleCount,ZT_MAX_CAPABILITY_RULES);
 		_maxCustodyChainLength = (unsigned int)b[p++];
 
 		if ((_maxCustodyChainLength < 1)||(_maxCustodyChainLength > ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH))
 			throw std::runtime_error("invalid max custody chain length");
-		for(unsigned int i;;++i) {
+		for(unsigned int i=0;;++i) {
 			const Address to(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
 			if (!to)
 				break;
@@ -409,6 +415,7 @@ public:
 
 private:
 	uint64_t _nwid;
+	uint64_t _ts;
 	uint64_t _expiration;
 	uint32_t _id;
 

+ 28 - 27
node/IncomingPacket.cpp

@@ -437,8 +437,11 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
 				if ((flags & 0x01) != 0) { // deprecated but still used by older peers
 					CertificateOfMembership com;
 					offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_COM_AND_GATHER_RESULTS);
-					LockingPtr<Membership> m(peer->membership(com.networkId(),true));
-					if (m) m->addCredential(RR,RR->node->now(),com);
+					if (com) {
+						SharedPtr<Network> network(RR->node->network(com.networkId()));
+						if (network)
+							network->addCredential(com);
+					}
 				}
 
 				if ((flags & 0x02) != 0) {
@@ -567,8 +570,8 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,const SharedPtr<P
 				if ((flags & 0x01) != 0) { // deprecated but still used by old peers
 					CertificateOfMembership com;
 					comLen = com.deserialize(*this,ZT_PROTO_VERB_EXT_FRAME_IDX_COM);
-					LockingPtr<Membership> m(peer->membership(com.networkId(),true));
-					if (m) m->addCredential(RR,RR->node->now(),com);
+					if (com)
+						network->addCredential(com);
 				}
 
 				if (!network->isAllowed(peer)) {
@@ -661,7 +664,6 @@ bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,const Shared
 bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const SharedPtr<Peer> &peer)
 {
 	try {
-		const uint64_t now = RR->node->now();
 		CertificateOfMembership com;
 		Capability cap;
 		Tag tag;
@@ -669,9 +671,13 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S
 		unsigned int p = ZT_PACKET_IDX_PAYLOAD;
 		while ((p < size())&&((*this)[p])) {
 			p += com.deserialize(*this,p);
-			LockingPtr<Membership> m(peer->membership(com.networkId(),true));
-			if (!m) return true; // sanity check
-			if (m->addCredential(RR,now,com) == 1) return false; // wait for WHOIS
+			if (com) {
+				SharedPtr<Network> network(RR->node->network(com.networkId()));
+				if (network) {
+					if (network->addCredential(com) == 1)
+						return false; // wait for WHOIS
+				}
+			}
 		}
 		++p; // skip trailing 0 after COMs if present
 
@@ -679,17 +685,21 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,const S
 			const unsigned int numCapabilities = at<uint16_t>(p); p += 2;
 			for(unsigned int i=0;i<numCapabilities;++i) {
 				p += cap.deserialize(*this,p);
-				LockingPtr<Membership> m(peer->membership(cap.networkId(),true));
-				if (!m) return true; // sanity check
-				if (m->addCredential(RR,now,cap) == 1) return false; // wait for WHOIS
+				SharedPtr<Network> network(RR->node->network(cap.networkId()));
+				if (network) {
+					if (network->addCredential(cap) == 1)
+						return false; // wait for WHOIS
+				}
 			}
 
 			const unsigned int numTags = at<uint16_t>(p); p += 2;
 			for(unsigned int i=0;i<numTags;++i) {
 				p += tag.deserialize(*this,p);
-				LockingPtr<Membership> m(peer->membership(tag.networkId(),true));
-				if (!m) return true; // sanity check
-				if (m->addCredential(RR,now,tag) == 1) return false; // wait for WHOIS
+				SharedPtr<Network> network(RR->node->network(tag.networkId()));
+				if (network) {
+					if (network->addCredential(tag) == 1)
+						return false; // wait for WHOIS
+				}
 			}
 		}
 
@@ -830,8 +840,8 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,const Share
 			if ((flags & 0x01) != 0) { // deprecated but still used by older peers
 				CertificateOfMembership com;
 				offset += com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_FRAME_IDX_COM);
-				LockingPtr<Membership> m(peer->membership(com.networkId(),true));
-				if (m) m->addCredential(RR,RR->node->now(),com);
+				if (com)
+					network->addCredential(com);
 			}
 
 			// Check membership after we've read any included COM, since
@@ -1037,17 +1047,8 @@ bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,const SharedPt
 		NetworkConfig originatorCredentialNetworkConfig;
 		if (originatorCredentialNetworkId) {
 			if (Network::controllerFor(originatorCredentialNetworkId) == originatorAddress) {
-				SharedPtr<Network> nw(RR->node->network(originatorCredentialNetworkId));
-				if ((nw)&&(nw->hasConfig())) {
-					originatorCredentialNetworkConfig = nw->config();
-					if ( ( (originatorCredentialNetworkConfig.isPublic()) || (peer->address() == originatorAddress) || ((originatorCredentialNetworkConfig.com)&&(previousHopCom)&&(originatorCredentialNetworkConfig.com.agreesWith(previousHopCom))) ) ) {
-						TRACE("CIRCUIT_TEST %.16llx received from hop %s(%s) and originator %s with valid network ID credential %.16llx (verified from originator and next hop)",testId,source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId);
-					} else {
-						TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and previous hop %s did not supply a valid COM",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId,peer->address().toString().c_str());
-						return true;
-					}
-				} else {
-					TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we are not a member",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId);
+				if (!RR->node->network(originatorCredentialNetworkId)) {
+					TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we are not a member of that network",source().toString().c_str(),_remoteAddress.toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId);
 					return true;
 				}
 			} else {

+ 12 - 10
node/Membership.cpp

@@ -79,19 +79,19 @@ bool Membership::sendCredentialsIfNeeded(const RuntimeEnvironment *RR,const uint
 	return false;
 }
 
-int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,const CertificateOfMembership &com)
+int Membership::addCredential(const RuntimeEnvironment *RR,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)
+	if ((vr == 0)&&(com.revision() > _com.revision()))
 		_com = com;
 	return vr;
 }
 
-int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Tag &tag)
+int Membership::addCredential(const RuntimeEnvironment *RR,const Tag &tag)
 {
 	if (tag.issuedTo() != RR->identity.address())
 		return -1;
@@ -102,15 +102,17 @@ int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,co
 	if (vr == 0) {
 		if (!t)
 			t = &(_tags[tag.id()]);
-		t->lastReceived = now;
-		t->tag = tag;
+		if (t->tag.timestamp() <= tag.timestamp()) {
+			t->lastReceived = RR->node->now();
+			t->tag = tag;
+		}
 	}
 	return vr;
 }
 
-int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Capability &cap)
+int Membership::addCredential(const RuntimeEnvironment *RR,const Capability &cap)
 {
-	if (!cap.wasIssuedTo(RR->identity.address()))
+	if (cap.issuedTo() != RR->identity.address())
 		return -1;
 	std::map<uint32_t,CState>::iterator c(_caps.find(cap.id()));
 	if ((c != _caps.end())&&(c->second.lastReceived != 0)&&(c->second.cap == cap))
@@ -119,10 +121,10 @@ int Membership::addCredential(const RuntimeEnvironment *RR,const uint64_t now,co
 	if (vr == 0) {
 		if (c == _caps.end()) {
 			CState &c2 = _caps[cap.id()];
-			c2.lastReceived = now;
+			c2.lastReceived = RR->node->now();
 			c2.cap = cap;
-		} else {
-			c->second.lastReceived = now;
+		} else if (c->second.cap.timestamp() <= cap.timestamp()) {
+			c->second.lastReceived = RR->node->now();
 			c->second.cap = cap;
 		}
 	}

+ 3 - 3
node/Membership.hpp

@@ -180,21 +180,21 @@ public:
 	 *
 	 * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
 	 */
-	int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const CertificateOfMembership &com);
+	int addCredential(const RuntimeEnvironment *RR,const CertificateOfMembership &com);
 
 	/**
 	 * 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
 	 */
-	int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Tag &tag);
+	int addCredential(const RuntimeEnvironment *RR,const Tag &tag);
 
 	/**
 	 * 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
 	 */
-	int addCredential(const RuntimeEnvironment *RR,const uint64_t now,const Capability &cap);
+	int addCredential(const RuntimeEnvironment *RR,const Capability &cap);
 
 	/**
 	 * Clean up old or stale entries

+ 1 - 14
node/Multicaster.cpp

@@ -152,7 +152,6 @@ std::vector<Address> Multicaster::getMembers(uint64_t nwid,const MulticastGroup
 }
 
 void Multicaster::send(
-	const CertificateOfMembership *com,
 	unsigned int limit,
 	uint64_t now,
 	uint64_t nwid,
@@ -194,7 +193,6 @@ void Multicaster::send(
 				RR,
 				now,
 				nwid,
-				com,
 				limit,
 				1, // we'll still gather a little from peers to keep multicast list fresh
 				src,
@@ -236,22 +234,12 @@ void Multicaster::send(
 					if (!p)
 						continue;
 					//TRACE(">>MC upstream GATHER up to %u for group %.16llx/%s",gatherLimit,nwid,mg.toString().c_str());
-
-					const CertificateOfMembership *com = (CertificateOfMembership *)0;
-					{
-						SharedPtr<Network> nw(RR->node->network(nwid));
-						if ((nw)&&(nw->hasConfig())&&(nw->config().com)&&(nw->config().isPrivate())&&(p->needsOurNetworkMembershipCertificate(nwid,now,true)))
-							com = &(nw->config().com);
-					}
-
 					Packet outp(p->address(),RR->identity.address(),Packet::VERB_MULTICAST_GATHER);
 					outp.append(nwid);
-					outp.append((uint8_t)(com ? 0x01 : 0x00));
+					outp.append((uint8_t)0x00);
 					mg.mac().appendTo(outp);
 					outp.append((uint32_t)mg.adi());
 					outp.append((uint32_t)gatherLimit);
-					if (com)
-						com->serialize(outp);
 					RR->sw->send(outp,true,0);
 				}
 				gatherLimit = 0;
@@ -264,7 +252,6 @@ void Multicaster::send(
 				RR,
 				now,
 				nwid,
-				com,
 				limit,
 				gatherLimit,
 				src,

+ 0 - 2
node/Multicaster.hpp

@@ -150,7 +150,6 @@ public:
 	/**
 	 * Send a multicast
 	 *
-	 * @param com Certificate of membership to include or NULL for none
 	 * @param limit Multicast limit
 	 * @param now Current time
 	 * @param nwid Network ID
@@ -162,7 +161,6 @@ public:
 	 * @param len Length of packet data
 	 */
 	void send(
-		const CertificateOfMembership *com,
 		unsigned int limit,
 		uint64_t now,
 		uint64_t nwid,

+ 1 - 1
node/Network.cpp

@@ -348,7 +348,7 @@ Network::Network(const RuntimeEnvironment *renv,uint64_t nwid,void *uptr) :
 	_netconfFailure(NETCONF_FAILURE_NONE),
 	_portError(0)
 {
-	char confn[128],mcdbn[128];
+	char confn[128];
 	Utils::snprintf(confn,sizeof(confn),"networks.d/%.16llx.conf",_id);
 
 	if (_id == ZT_TEST_NETWORK_ID) {

+ 36 - 0
node/Network.hpp

@@ -336,6 +336,42 @@ public:
 	 */
 	void learnBridgedMulticastGroup(const MulticastGroup &mg,uint64_t now);
 
+	/**
+	 * @param com Certificate of membership
+	 * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
+	 */
+	inline int addCredential(const CertificateOfMembership &com)
+	{
+		if (com.networkId() != _id)
+			return -1;
+		Mutex::Lock _l(_lock);
+		return _memberships[com.issuedTo()].addCredential(RR,com);
+	}
+
+	/**
+	 * @param cap Capability
+	 * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
+	 */
+	inline int addCredential(const Capability &cap)
+	{
+		if (cap.networkId() != _id)
+			return -1;
+		Mutex::Lock _l(_lock);
+		return _memberships[cap.issuedTo()].addCredential(RR,cap);
+	}
+
+	/**
+	 * @param cap Tag
+	 * @return 0 == OK, 1 == waiting for WHOIS, -1 == BAD signature or credential
+	 */
+	inline int addCredential(const Tag &tag)
+	{
+		if (tag.networkId() != _id)
+			return -1;
+		Mutex::Lock _l(_lock);
+		return _memberships[tag.issuedTo()].addCredential(RR,tag);
+	}
+
 	/**
 	 * Destroy this network
 	 *

+ 2 - 3
node/Packet.cpp

@@ -22,7 +22,7 @@ namespace ZeroTier {
 
 const unsigned char Packet::ZERO_KEY[32] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 };
 
-//#ifdef ZT_TRACE
+#ifdef ZT_TRACE
 
 const char *Packet::verbString(Verb v)
 	throw()
@@ -60,14 +60,13 @@ const char *Packet::errorString(ErrorCode e)
 		case ERROR_OBJ_NOT_FOUND: return "OBJECT_NOT_FOUND";
 		case ERROR_IDENTITY_COLLISION: return "IDENTITY_COLLISION";
 		case ERROR_UNSUPPORTED_OPERATION: return "UNSUPPORTED_OPERATION";
-		case ERROR_NEED_MEMBERSHIP_CERTIFICATE: return "NEED_MEMBERSHIP_CERTIFICATE";
 		case ERROR_NETWORK_ACCESS_DENIED_: return "NETWORK_ACCESS_DENIED";
 		case ERROR_UNWANTED_MULTICAST: return "UNWANTED_MULTICAST";
 	}
 	return "(unknown)";
 }
 
-//#endif // ZT_TRACE
+#endif // ZT_TRACE
 
 void Packet::armor(const void *key,bool encryptPayload)
 {

+ 2 - 2
node/Packet.hpp

@@ -1060,12 +1060,12 @@ public:
 		ERROR_UNWANTED_MULTICAST = 0x08
 	};
 
-//#ifdef ZT_TRACE
+#ifdef ZT_TRACE
 	static const char *verbString(Verb v)
 		throw();
 	static const char *errorString(ErrorCode e)
 		throw();
-//#endif
+#endif
 
 	template<unsigned int C2>
 	Packet(const Buffer<C2> &b) :

+ 1 - 3
node/Peer.cpp

@@ -53,9 +53,7 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
 	_id(peerIdentity),
 	_numPaths(0),
 	_latency(0),
-	_directPathPushCutoffCount(0),
-	_networkComs(4),
-	_lastPushedComs(4)
+	_directPathPushCutoffCount(0)
 {
 	if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH))
 		throw std::runtime_error("new peer identity key agreement failed");

+ 7 - 46
node/Switch.cpp

@@ -35,7 +35,6 @@
 #include "Peer.hpp"
 #include "SelfAwareness.hpp"
 #include "Packet.hpp"
-#include "Filter.hpp"
 #include "Cluster.hpp"
 
 namespace ZeroTier {
@@ -438,26 +437,12 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
 
 		//TRACE("%.16llx: MULTICAST %s -> %s %s %u",network->id(),from.toString().c_str(),mg.toString().c_str(),etherTypeName(etherType),len);
 
-		if (!Filter::run(
-			RR,
-			network->id(),
-			RR->identity.address(),
-			Address(), // 0 destination ZT address for multicasts since this is unknown at time of send
-			from,
-			to,
-			(const uint8_t *)data,
-			len,
-			etherType,
-			vlanId,
-			network->config().rules,
-			network->config().ruleCount))
-		{
-			TRACE("%.16llx: %s -> %s %s packet not sent: Filter::run() == false (multicast)",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType));
+		if (!network->filterOutgoingPacket(RR->identity.address(),Address(),from,to,(const uint8_t *)data,len,etherType,vlanId)) {
+			TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType));
 			return;
 		}
 
 		RR->mc->send(
-			((!network->config().isPublic())&&(network->config().com)) ? &(network->config().com) : (const CertificateOfMembership *)0,
 			network->config().multicastLimit,
 			RR->node->now(),
 			network->id(),
@@ -477,34 +462,15 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
 		Address toZT(to.toAddress(network->id())); // since in-network MACs are derived from addresses and network IDs, we can reverse this
 		SharedPtr<Peer> toPeer(RR->topology->getPeer(toZT));
 
-		if (!Filter::run(
-			RR,
-			network->id(),
-			RR->identity.address(),
-			toZT,
-			from,
-			to,
-			(const uint8_t *)data,
-			len,
-			etherType,
-			vlanId,
-			network->config().rules,
-			network->config().ruleCount))
-		{
-			TRACE("%.16llx: %s -> %s %s packet not sent: Filter::run() == false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType));
+		if (!network->filterOutgoingPacket(RR->identity.address(),toZT,from,to,(const uint8_t *)data,len,etherType,vlanId)) {
+			TRACE("%.16llx: %s -> %s %s packet not sent: filterOutgoingPacket() returned false",network->id(),from.toString().c_str(),to.toString().c_str(),etherTypeName(etherType));
 			return;
 		}
 
-		const bool includeCom = ( (network->config().isPrivate()) && (network->config().com) && ((!toPeer)||(toPeer->needsOurNetworkMembershipCertificate(network->id(),RR->node->now(),true))) );
-		if ((fromBridged)||(includeCom)) {
+		if (fromBridged) {
 			Packet outp(toZT,RR->identity.address(),Packet::VERB_EXT_FRAME);
 			outp.append(network->id());
-			if (includeCom) {
-				outp.append((unsigned char)0x01); // 0x01 -- COM included
-				network->config().com.serialize(outp);
-			} else {
-				outp.append((unsigned char)0x00);
-			}
+			outp.append((unsigned char)0x00);
 			to.appendTo(outp);
 			from.appendTo(outp);
 			outp.append((uint16_t)etherType);
@@ -564,12 +530,7 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &network,const MAC &from,c
 			SharedPtr<Peer> bridgePeer(RR->topology->getPeer(bridges[b]));
 			Packet outp(bridges[b],RR->identity.address(),Packet::VERB_EXT_FRAME);
 			outp.append(network->id());
-			if ( (network->config().isPrivate()) && (network->config().com) && ((!bridgePeer)||(bridgePeer->needsOurNetworkMembershipCertificate(network->id(),RR->node->now(),true))) ) {
-				outp.append((unsigned char)0x01); // 0x01 -- COM included
-				network->config().com.serialize(outp);
-			} else {
-				outp.append((unsigned char)0);
-			}
+			outp.append((uint8_t)0x00);
 			to.appendTo(outp);
 			from.appendTo(outp);
 			outp.append((uint16_t)etherType);

+ 7 - 1
node/Tag.hpp

@@ -61,13 +61,15 @@ public:
 
 	/**
 	 * @param nwid Network ID
+	 * @param ts Timestamp
 	 * @param expiration Tag expiration relative to network config timestamp
 	 * @param issuedTo Address to which this tag was issued
 	 * @param id Tag ID
 	 * @param value Tag value
 	 */
-	Tag(const uint64_t nwid,const uint64_t expiration,const Address &issuedTo,const uint32_t id,const uint32_t value) :
+	Tag(const uint64_t nwid,const uint64_t ts,const uint64_t expiration,const Address &issuedTo,const uint32_t id,const uint32_t value) :
 		_nwid(nwid),
+		_ts(ts),
 		_expiration(expiration),
 		_id(id),
 		_value(value),
@@ -78,6 +80,7 @@ public:
 
 	inline uint64_t networkId() const { return _nwid; }
 	inline uint64_t expiration() const { return _expiration; }
+	inline uint64_t timestamp() const { return _ts; }
 	inline uint32_t id() const { return _id; }
 	inline const uint32_t &value() const { return _value; }
 	inline const Address &issuedTo() const { return _issuedTo; }
@@ -115,6 +118,7 @@ public:
 		if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
 
 		b.append(_nwid);
+		b.append(_ts);
 		b.append(_expiration);
 		b.append(_id);
 		b.append(_value);
@@ -136,6 +140,7 @@ public:
 		unsigned int p = startAt;
 
 		_nwid = b.template at<uint64_t>(p); p += 8;
+		_ts = b.template at<uint64_t>(p); p += 8;
 		_expiration = b.template at<uint64_t>(p); p += 8;
 		_id = b.template at<uint32_t>(p); p += 4;
 		_value = b.template at<uint32_t>(p); p += 4;
@@ -163,6 +168,7 @@ public:
 
 private:
 	uint64_t _nwid;
+	uint64_t _ts;
 	uint64_t _expiration;
 	uint32_t _id;
 	uint32_t _value;

+ 0 - 28
node/Topology.cpp

@@ -74,34 +74,6 @@ Topology::Topology(const RuntimeEnvironment *renv) :
 
 Topology::~Topology()
 {
-	Buffer<ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE> *pbuf = 0;
-	try {
-		pbuf = new Buffer<ZT_PEER_SUGGESTED_SERIALIZATION_BUFFER_SIZE>();
-		std::string all;
-
-		Address *a = (Address *)0;
-		SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
-		Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
-		while (i.next(a,p)) {
-			if (std::find(_rootAddresses.begin(),_rootAddresses.end(),*a) == _rootAddresses.end()) {
-				pbuf->clear();
-				try {
-					(*p)->serialize(*pbuf);
-					try {
-						all.append((const char *)pbuf->data(),pbuf->size());
-					} catch ( ... ) {
-						return; // out of memory? just skip
-					}
-				} catch ( ... ) {} // peer too big? shouldn't happen, but it so skip
-			}
-		}
-
-		RR->node->dataStorePut("peers.save",all,true);
-
-		delete pbuf;
-	} catch ( ... ) {
-		delete pbuf;
-	}
 }
 
 SharedPtr<Peer> Topology::addPeer(const SharedPtr<Peer> &peer)