فهرست منبع

Take the 0.6.0 opportunity to add flags to a few protocol verbs and do a bit more cleanup. Also fix it so certificates wont be accepted unless they are newer than existing ones.

Adam Ierymenko 12 سال پیش
والد
کامیت
ce14ba9004
7فایلهای تغییر یافته به همراه84 افزوده شده و 68 حذف شده
  1. 3 3
      node/CertificateOfMembership.hpp
  2. 34 22
      node/Network.cpp
  3. 1 1
      node/Packet.cpp
  4. 12 11
      node/Packet.hpp
  5. 31 30
      node/PacketDecoder.cpp
  6. 1 1
      node/PacketDecoder.hpp
  7. 2 0
      node/Switch.cpp

+ 3 - 3
node/CertificateOfMembership.hpp

@@ -198,14 +198,14 @@ public:
 	/**
 	 * @return Timestamp for this cert in ms since epoch (according to netconf's clock)
 	 */
-	inline Address timestamp() const
+	inline uint64_t timestamp() const
 		throw()
 	{
 		for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) {
 			if (q->id == COM_RESERVED_ID_TIMESTAMP)
-				return Address(q->value);
+				return q->value;
 		}
-		return Address();
+		return 0ULL;
 	}
 
 	/**

+ 34 - 22
node/Network.cpp

@@ -178,10 +178,14 @@ void Network::requestConfiguration()
 void Network::addMembershipCertificate(const CertificateOfMembership &cert)
 {
 	Mutex::Lock _l(_lock);
+
 	// We go ahead and accept certs provisionally even if _isOpen is true, since
 	// that might be changed in short order if the user is fiddling in the UI.
 	// These will be purged on clean() for open networks eventually.
-	_membershipCertificates[cert.issuedTo()] = cert;
+
+	CertificateOfMembership &old = _membershipCertificates[cert.issuedTo()];
+	if (cert.timestamp() >= old.timestamp())
+		old = cert;
 }
 
 bool Network::isAllowed(const Address &peer) const
@@ -299,30 +303,38 @@ void Network::_restoreState()
 
 		_membershipCertificates.clear();
 
-		try {
-			FILE *mcdb = fopen(mcdbPath.c_str(),"rb");
-			if (mcdb) {
-				for(;;) {
-					long rlen = (long)fread(buf.data() + buf.size(),1,ZT_NETWORK_CERT_WRITE_BUF_SIZE - buf.size(),mcdb);
-					if (rlen <= 0)
-						break;
-					buf.setSize(buf.size() + (unsigned int)rlen);
-					unsigned int ptr = 0;
-					while ((ptr < (ZT_NETWORK_CERT_WRITE_BUF_SIZE / 2))&&(ptr < buf.size())) {
-						ptr += com.deserialize(buf,ptr);
-						if (com.issuedTo())
-							_membershipCertificates[com.issuedTo()] = com;
-					}
-					if (ptr) {
-						memmove(buf.data(),buf.data() + ptr,buf.size() - ptr);
-						buf.setSize(buf.size() - ptr);
+		FILE *mcdb = fopen(mcdbPath.c_str(),"rb");
+		if (mcdb) {
+			try {
+				char magic[6];
+				if ((fread(magic,6,1,mcdb) == 1)&&(!memcmp("ZTMCD0",magic,6))) {
+					for(;;) {
+						long rlen = (long)fread(buf.data() + buf.size(),1,ZT_NETWORK_CERT_WRITE_BUF_SIZE - buf.size(),mcdb);
+						if (rlen <= 0)
+							break;
+						buf.setSize(buf.size() + (unsigned int)rlen);
+						unsigned int ptr = 0;
+						while ((ptr < (ZT_NETWORK_CERT_WRITE_BUF_SIZE / 2))&&(ptr < buf.size())) {
+							ptr += com.deserialize(buf,ptr);
+							if (com.issuedTo())
+								_membershipCertificates[com.issuedTo()] = com;
+						}
+						if (ptr) {
+							memmove(buf.data(),buf.data() + ptr,buf.size() - ptr);
+							buf.setSize(buf.size() - ptr);
+						}
 					}
+					fclose(mcdb);
+				} else {
+					fclose(mcdb);
+					Utils::rm(mcdbPath);
 				}
+			} catch ( ... ) {
+				// Membership cert dump file invalid. We'll re-learn them off the net.
+				_membershipCertificates.clear();
+				fclose(mcdb);
+				Utils::rm(mcdbPath);
 			}
-		} catch ( ... ) {
-			// Membership cert dump file invalid. We'll re-learn them off the net.
-			_membershipCertificates.clear();
-			Utils::rm(mcdbPath);
 		}
 	}
 }

+ 1 - 1
node/Packet.cpp

@@ -42,7 +42,7 @@ const char *Packet::verbString(Verb v)
 		case VERB_WHOIS: return "WHOIS";
 		case VERB_RENDEZVOUS: return "RENDEZVOUS";
 		case VERB_FRAME: return "FRAME";
-		case VERB_PROXY_FRAME: return "PROXY_FRAME";
+		case VERB_BRIDGED_FRAME: return "BRIDGED_FRAME";
 		case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME";
 		case VERB_MULTICAST_LIKE: return "MULTICAST_LIKE";
 		case VERB_NETWORK_MEMBERSHIP_CERTIFICATE: return "NETWORK_MEMBERSHIP_CERTIFICATE";

+ 12 - 11
node/Packet.hpp

@@ -155,7 +155,8 @@
 
 #define ZT_PROTO_VERB_WHOIS_IDX_ZTADDRESS (ZT_PACKET_IDX_PAYLOAD)
 
-#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS (ZT_PACKET_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_RENDEZVOUS_IDX_FLAGS (ZT_PACKET_IDX_PAYLOAD)
+#define ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS (ZT_PROTO_VERB_RENDEZVOUS_IDX_FLAGS + 1)
 #define ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT (ZT_PROTO_VERB_RENDEZVOUS_IDX_ZTADDRESS + 5)
 #define ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN (ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT + 2)
 #define ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS (ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN + 1)
@@ -199,8 +200,6 @@
 #define ZT_PROTO_VERB_MULTICAST_FRAME_LEN_FRAME_LEN 2
 #define ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME (ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME_LEN + ZT_PROTO_VERB_MULTICAST_FRAME_LEN_FRAME_LEN)
 
-#define ZT_PROTO_VERB_NETWORK_MEMBERSHIP_CERTIFICATE_IDX_CERTIFICATE (ZT_PACKET_IDX_PAYLOAD)
-
 #define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID (ZT_PACKET_IDX_PAYLOAD)
 #define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_NETWORK_ID + 8)
 #define ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT (ZT_PROTO_VERB_NETWORK_CONFIG_REQUEST_IDX_DICT_LEN + 2)
@@ -434,11 +433,13 @@ public:
 		 * OK response payload:
 		 *   <[...] binary serialized identity>
 		 *
-		 * Error payload will be address queried.
+		 * ERROR response payload:
+		 *   <[5] address>
 		 */
 		VERB_WHOIS = 4,
 
 		/* Meet another node at a given protocol address:
+		 *   <[1] flags (unused, currently 0)>
 		 *   <[5] ZeroTier address of peer that might be found at this address>
 		 *   <[2] 16-bit protocol address port>
 		 *   <[1] protocol address length (4 for IPv4, 16 for IPv6)>
@@ -470,8 +471,7 @@ public:
 		 *   <[...] ethernet payload>
 		 *
 		 * MAC addresses are derived from the packet's source and destination
-		 * ZeroTier addresses. ZeroTier does not support VLANs or other extensions
-		 * beyond core Ethernet.
+		 * ZeroTier addresses.
 		 *
 		 * ERROR may be generated if a membership certificate is needed for a
 		 * closed network. Payload will be network ID.
@@ -479,7 +479,7 @@ public:
 		VERB_FRAME = 6,
 
 		/* TODO: not implemented yet */
-		VERB_PROXY_FRAME = 7,
+		VERB_BRIDGED_FRAME = 7,
 
 		/* A multicast frame:
 		 *   <[2] 16-bit propagation depth or 0xffff for "do not forward">
@@ -556,6 +556,7 @@ public:
 
 		/* Network member certificate:
 		 *   <[...] serialized certificate of membership>
+		 *   [ ... additional certificates may follow ...]
 		 *
 		 * Certificate contains network ID, peer it was issued for, etc.
 		 *
@@ -583,9 +584,8 @@ public:
 		 * node can push to other peers to demonstrate its right to speak on
 		 * a given network.
 		 *
-		 * ERROR may be NOT_FOUND if no such network is known, or
-		 * UNSUPPORTED_OPERATION if the netconf service isn't available. The
-		 * payload will be the network ID.
+		 * ERROR response payload:
+		 *   <[8] 64-bit network ID>
 		 */
 		VERB_NETWORK_CONFIG_REQUEST = 11,
 
@@ -594,7 +594,8 @@ public:
 		 *
 		 * This message can be sent by the network configuration master node
 		 * to request that nodes refresh their network configuration. It can
-		 * thus be used to "push" updates.
+		 * thus be used to "push" updates so that network config changes will
+		 * take effect quickly.
 		 *
 		 * It does not generate an OK or ERROR message, and is treated only as
 		 * a hint to refresh now.

+ 31 - 30
node/PacketDecoder.cpp

@@ -102,8 +102,8 @@ bool PacketDecoder::tryDecode(const RuntimeEnvironment *_r)
 				return _doRENDEZVOUS(_r,peer);
 			case Packet::VERB_FRAME:
 				return _doFRAME(_r,peer);
-			case Packet::VERB_PROXY_FRAME:
-				return _doPROXY_FRAME(_r,peer);
+			case Packet::VERB_BRIDGED_FRAME:
+				return _doBRIDGED_FRAME(_r,peer);
 			case Packet::VERB_MULTICAST_FRAME:
 				return _doMULTICAST_FRAME(_r,peer);
 			case Packet::VERB_MULTICAST_LIKE:
@@ -151,9 +151,6 @@ bool PacketDecoder::_doERROR(const RuntimeEnvironment *_r,const SharedPtr<Peer>
 				// if (_r->topology->isSupernode(source())) {}
 				break;
 			case Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE: {
-				// TODO: this allows anyone to request a membership cert, which is
-				// harmless until these contain possibly privacy-sensitive info.
-				// Then we'll need to be more careful.
 				SharedPtr<Network> network(_r->nc->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
 				if (network)
 					network->pushMembershipCertificate(source(),true,Utils::now());
@@ -399,7 +396,7 @@ bool PacketDecoder::_doFRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer>
 	return true;
 }
 
-bool PacketDecoder::_doPROXY_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer)
+bool PacketDecoder::_doBRIDGED_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer)
 {
 	// TODO: bridging is not implemented yet
 	return true;
@@ -654,40 +651,44 @@ bool PacketDecoder::_doMULTICAST_LIKE(const RuntimeEnvironment *_r,const SharedP
 bool PacketDecoder::_doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer)
 {
 	try {
-		CertificateOfMembership com(*this,ZT_PROTO_VERB_NETWORK_MEMBERSHIP_CERTIFICATE_IDX_CERTIFICATE);
-		if (!com.hasRequiredFields()) {
-			TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): invalid cert: at least one required field is missing",source().toString().c_str(),_remoteAddress.toString().c_str());
-			return true;
-		} else if (com.signedBy()) {
-			SharedPtr<Peer> signer(_r->topology->getPeer(com.signedBy()));
-			if (signer) {
-				if (com.verify(signer->identity())) {
-					uint64_t nwid = com.networkId();
-					SharedPtr<Network> network(_r->nc->network(nwid));
-					if (network) {
-						if (network->controller() == signer) {
-							network->addMembershipCertificate(com);
-							return true;
+		CertificateOfMembership com;
+		unsigned int ptr = ZT_PACKET_IDX_PAYLOAD;
+		while (ptr < size()) {
+			ptr += com.deserialize(*this,ptr);
+			if (!com.hasRequiredFields()) {
+				TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): invalid cert: at least one required field is missing",source().toString().c_str(),_remoteAddress.toString().c_str());
+				return true;
+			} else if (com.signedBy()) {
+				SharedPtr<Peer> signer(_r->topology->getPeer(com.signedBy()));
+				if (signer) {
+					if (com.verify(signer->identity())) {
+						uint64_t nwid = com.networkId();
+						SharedPtr<Network> network(_r->nc->network(nwid));
+						if (network) {
+							if (network->controller() == signer) {
+								network->addMembershipCertificate(com);
+								return true;
+							} else {
+								TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): signer %s is not the controller for network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),signer->address().toString().c_str(),(unsigned long long)nwid);
+								return true;
+							}
 						} else {
-							TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): signer %s is not the controller for network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),signer->address().toString().c_str(),(unsigned long long)nwid);
+							TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): not a member of network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned long long)nwid);
 							return true;
 						}
 					} else {
-						TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): not a member of network %.16llx",source().toString().c_str(),_remoteAddress.toString().c_str(),(unsigned long long)nwid);
+						TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): failed signature verification for signer %s",source().toString().c_str(),_remoteAddress.toString().c_str(),signer->address().toString().c_str());
 						return true;
 					}
 				} else {
-					TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): failed signature verification for signer %s",source().toString().c_str(),_remoteAddress.toString().c_str(),signer->address().toString().c_str());
-					return true;
+					_r->sw->requestWhois(com.signedBy());
+					_step = DECODE_WAITING_FOR_NETWORK_MEMBERSHIP_CERTIFICATE_SIGNER_LOOKUP;
+					return false;
 				}
 			} else {
-				_r->sw->requestWhois(com.signedBy());
-				_step = DECODE_WAITING_FOR_NETWORK_MEMBERSHIP_CERTIFICATE_SIGNER_LOOKUP;
-				return false;
+				TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): invalid cert: no signature",source().toString().c_str(),_remoteAddress.toString().c_str());
+				return true;
 			}
-		} else {
-			TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): invalid cert: no signature",source().toString().c_str(),_remoteAddress.toString().c_str());
-			return true;
 		}
 	} catch (std::exception &ex) {
 		TRACE("dropped NETWORK_MEMBERSHIP_CERTIFICATE from %s(%s): unexpected exception: %s",source().toString().c_str(),_remoteAddress.toString().c_str(),ex.what());

+ 1 - 1
node/PacketDecoder.hpp

@@ -117,7 +117,7 @@ private:
 	bool _doWHOIS(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
 	bool _doRENDEZVOUS(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
 	bool _doFRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
-	bool _doPROXY_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
+	bool _doBRIDGED_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
 	bool _doMULTICAST_FRAME(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
 	bool _doMULTICAST_LIKE(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);
 	bool _doNETWORK_MEMBERSHIP_CERTIFICATE(const RuntimeEnvironment *_r,const SharedPtr<Peer> &peer);

+ 2 - 0
node/Switch.cpp

@@ -265,6 +265,7 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force)
 
 	{	// tell p1 where to find p2
 		Packet outp(p1,_r->identity.address(),Packet::VERB_RENDEZVOUS);
+		outp.append((unsigned char)0);
 		p2.appendTo(outp);
 		outp.append((uint16_t)cg.first.port());
 		if (cg.first.isV6()) {
@@ -279,6 +280,7 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force)
 	}
 	{	// tell p2 where to find p1
 		Packet outp(p2,_r->identity.address(),Packet::VERB_RENDEZVOUS);
+		outp.append((unsigned char)0);
 		p1.appendTo(outp);
 		outp.append((uint16_t)cg.second.port());
 		if (cg.second.isV6()) {