Browse Source

Work in progress...

Adam Ierymenko 12 years ago
parent
commit
5557a8192d
5 changed files with 95 additions and 136 deletions
  1. 23 8
      node/Network.cpp
  2. 11 48
      node/Network.hpp
  3. 50 60
      node/Packet.hpp
  4. 1 1
      node/Peer.cpp
  5. 10 19
      node/Peer.hpp

+ 23 - 8
node/Network.cpp

@@ -147,6 +147,7 @@ Network::~Network()
 SharedPtr<Network> Network::newInstance(const RuntimeEnvironment *renv,uint64_t id)
 	throw(std::runtime_error)
 {
+	// Tag to identify tap device -- used on some OSes like Windows
 	char tag[32];
 	Utils::snprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)id);
 
@@ -159,8 +160,7 @@ SharedPtr<Network> Network::newInstance(const RuntimeEnvironment *renv,uint64_t
 	nw->_ready = false; // disable handling of Ethernet frames during construct
 	nw->_r = renv;
 	nw->_tap = new EthernetTap(renv,tag,renv->identity.address().toMAC(),ZT_IF_MTU,&_CBhandleTapData,nw.ptr());
-	nw->_multicastPropagationBreadth = 0;
-	nw->_multicastPropagationDepth = 0;
+	nw->_isOpen = false;
 	memset(nw->_etWhitelist,0,sizeof(nw->_etWhitelist));
 	nw->_id = id;
 	nw->_lastConfigUpdate = 0;
@@ -179,28 +179,39 @@ void Network::setConfiguration(const Network::Config &conf)
 	try {
 		if (conf.networkId() == _id) { // sanity check
 			_configuration = conf;
+
+			// Grab some things from conf for faster lookup and memoize them
 			_myCertificate = conf.certificateOfMembership();
 			_mcRates = conf.multicastRates();
-			_multicastPropagationBreadth = conf.multicastPropagationBreadth();
-			_multicastPropagationDepth = conf.multicastPropagationDepth();
+			_staticAddresses = conf.staticAddresses();
+			_isOpen = conf.isOpen();
+
 			_lastConfigUpdate = Utils::now();
 
-			_tap->setIps(conf.staticAddresses());
+			_tap->setIps(_staticAddresses);
 			_tap->setDisplayName((std::string("ZeroTier One [") + conf.name() + "]").c_str());
 
+			// Expand ethertype whitelist into fast-lookup bit field
 			memset(_etWhitelist,0,sizeof(_etWhitelist));
 			std::set<unsigned int> wl(conf.etherTypes());
 			for(std::set<unsigned int>::const_iterator t(wl.begin());t!=wl.end();++t)
 				_etWhitelist[*t / 8] |= (unsigned char)(1 << (*t % 8));
 
+			// Save most recent configuration to disk in networks.d
 			std::string confPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + idString() + ".conf");
 			if (!Utils::writeFile(confPath.c_str(),conf.toString())) {
 				LOG("error: unable to write network configuration file at: %s",confPath.c_str());
 			}
 		}
 	} catch ( ... ) {
+		// If conf is invalid, reset everything
 		_configuration = Config();
+
 		_myCertificate = CertificateOfMembership();
+		_mcRates = MulticastRates();
+		_staticAddresses.clear();
+		_isOpen = false;
+
 		_lastConfigUpdate = 0;
 		LOG("unexpected exception handling config for network %.16llx, retrying fetch...",(unsigned long long)_id);
 	}
@@ -209,9 +220,11 @@ void Network::setConfiguration(const Network::Config &conf)
 void Network::requestConfiguration()
 {
 	if (controller() == _r->identity.address()) {
+		// FIXME: Right now the netconf master cannot be a member of its own nets
 		LOG("unable to request network configuration for network %.16llx: I am the network master, cannot query self",(unsigned long long)_id);
 		return;
 	}
+
 	TRACE("requesting netconf for network %.16llx from netconf master %s",(unsigned long long)_id,controller().toString().c_str());
 	Packet outp(controller(),_r->identity.address(),Packet::VERB_NETWORK_CONFIG_REQUEST);
 	outp.append((uint64_t)_id);
@@ -222,7 +235,7 @@ void Network::requestConfiguration()
 void Network::addMembershipCertificate(const Address &peer,const CertificateOfMembership &cert)
 {
 	Mutex::Lock _l(_lock);
-	if (!_configuration.isOpen())
+	if (!_isOpen)
 		_membershipCertificates[peer] = cert;
 }
 
@@ -231,7 +244,7 @@ bool Network::isAllowed(const Address &peer) const
 	// Exceptions can occur if we do not yet have *our* configuration.
 	try {
 		Mutex::Lock _l(_lock);
-		if (_configuration.isOpen())
+		if (_isOpen)
 			return true;
 		std::map<Address,CertificateOfMembership>::const_iterator pc(_membershipCertificates.find(peer));
 		if (pc == _membershipCertificates.end())
@@ -249,9 +262,11 @@ void Network::clean()
 {
 	std::string mcdbPath(_r->homePath + ZT_PATH_SEPARATOR_S + "networks.d" + ZT_PATH_SEPARATOR_S + idString() + ".mcerts");
 
+	_multicaster.clean(Utils::now());
+
 	Mutex::Lock _l(_lock);
 
-	if ((!_id)||(_configuration.isOpen())) {
+	if ((!_id)||(_isOpen)) {
 		_membershipCertificates.clear();
 		Utils::rm(mcdbPath);
 	} else {

+ 11 - 48
node/Network.hpp

@@ -318,34 +318,6 @@ public:
 			return get("desc",std::string());
 		}
 
-		/**
-		 * @return Breadth for multicast propagation
-		 */
-		inline unsigned int multicastPropagationBreadth() const
-		{
-			const_iterator mcb(find("mcb"));
-			if (mcb == end())
-				return ZT_MULTICAST_DEFAULT_PROPAGATION_BREADTH;
-			unsigned int mcb2 = Utils::hexStrToUInt(mcb->second.c_str());
-			if (mcb2)
-				return mcb2;
-			return ZT_MULTICAST_DEFAULT_PROPAGATION_BREADTH;
-		}
-
-		/**
-		 * @return Depth for multicast propagation
-		 */
-		inline unsigned int multicastPropagationDepth() const
-		{
-			const_iterator mcd(find("mcd"));
-			if (mcd == end())
-				return ZT_MULTICAST_DEFAULT_PROPAGATION_DEPTH;
-			unsigned int mcd2 = Utils::hexStrToUInt(mcd->second.c_str());
-			if (mcd2)
-				return mcd2;
-			return ZT_MULTICAST_DEFAULT_PROPAGATION_DEPTH;
-		}
-
 		/**
 		 * @return Certificate of membership for this network, or empty cert if none
 		 */
@@ -462,6 +434,7 @@ private:
 	 * Causes all persistent disk presence to be erased on delete
 	 */
 	inline void destroyOnDelete()
+		throw()
 	{
 		_destroyOnDelete = true;
 	}
@@ -498,12 +471,8 @@ public:
 	inline bool isOpen() const
 		throw()
 	{
-		try {
-			Mutex::Lock _l(_lock);
-			return _configuration.isOpen();
-		} catch ( ... ) {
-			return false;
-		}
+		Mutex::Lock _l(_lock);
+		return _isOpen;
 	}
 
 	/**
@@ -616,21 +585,12 @@ public:
 	}
 
 	/**
-	 * @return Breadth for multicast rumor mill propagation
-	 */
-	inline unsigned int multicastPropagationBreadth() const
-		throw()
-	{
-		return _multicastPropagationBreadth;
-	}
-
-	/**
-	 * @return Depth for multicast rumor mill propagation
+	 * @return Multicaster for this network
 	 */
-	inline unsigned int multicastPropagationDepth() const
+	inline Multicaster &multicaster()
 		throw()
 	{
-		return _multicastPropagationDepth;
+		return _multicaster;
 	}
 
 private:
@@ -653,12 +613,15 @@ private:
 	Config _configuration;
 	CertificateOfMembership _myCertificate; // memoized from _configuration
 	MulticastRates _mcRates; // memoized from _configuration
-	unsigned int _multicastPropagationBreadth; // memoized from _configuration
-	unsigned int _multicastPropagationDepth; // memoized from _configuration
+	std::set<InetAddress> _staticAddresses; // memoized from _configuration
+	bool _isOpen; // memoized from _configuration
 
 	// Ethertype whitelist bit field, set from config, for really fast lookup
 	unsigned char _etWhitelist[65536 / 8];
 
+	// Multicast propagation database
+	Multicaster _multicaster;
+
 	uint64_t _id;
 	volatile uint64_t _lastConfigUpdate;
 	volatile bool _destroyOnDelete;

+ 50 - 60
node/Packet.hpp

@@ -814,75 +814,68 @@ public:
 	}
 
 	/**
-	 * Generate a message authenticationc code and set MAC field of packet
-	 * 
-	 * For encrypted packets, this must be called after encryption.
+	 * Armor packet for transport
 	 *
-	 * @param key 256-bit (32 byte) key
+	 * @param key 32-byte key
+	 * @param encryptPayload If true, encrypt packet payload, else just MAC
 	 */
-	inline void macSet(const void *key)
+	inline void armor(const void *key,bool encryptPayload)
 	{
+		unsigned char mangledKey[32];
+		unsigned char macKey[32];
 		unsigned char mac[16];
-		unsigned char key2[32];
-		_mangleKey((const unsigned char *)key,key2);
-		unsigned int macLen = (size() >= ZT_PACKET_IDX_VERB) ? (size() - ZT_PACKET_IDX_VERB) : 0;
-		Poly1305::compute(mac,field(ZT_PACKET_IDX_VERB,macLen),macLen,key2);
+		const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB;
+		unsigned char *const payload = field(ZT_PACKET_IDX_VERB,payloadLen);
+
+		// Set flag now, since it affects key mangle function
+		if (encryptPayload)
+			(*this)[ZT_PACKET_IDX_FLAGS] |= (char)ZT_PROTO_FLAG_ENCRYPTED;
+		else (*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_ENCRYPTED);
+
+		_mangleKey((const unsigned char *)key,mangledKey);
+		Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8));
+
+		// MAC key is always the first 32 bytes of the Salsa20 key stream
+		// This is the same technique DJB's NaCl library uses to use poly1305
+		memset(macKey,0,sizeof(macKey));
+		s20.encrypt(macKey,macKey,sizeof(macKey));
+
+		if (encryptPayload)
+			s20.encrypt(payload,payload,payloadLen);
+
+		Poly1305::compute(mac,payload,payloadLen,macKey);
 		memcpy(field(ZT_PACKET_IDX_MAC,8),mac,8);
 	}
 
 	/**
-	 * Check the MAC of this packet's payload
-	 * 
-	 * For encrypted packets, this must be checked before decryption.
+	 * Verify and (if encrypted) decrypt packet
 	 *
-	 * @param key 256-bit (32 byte) key
+	 * @param key 32-byte key
+	 * @return False if packet is invalid or failed MAC authenticity check
 	 */
-	inline bool macVerify(const void *key) const
+	inline bool dearmor(const void *key)
 	{
+		unsigned char mangledKey[32];
+		unsigned char macKey[32];
 		unsigned char mac[16];
-		unsigned char key2[32];
-		if (size() < ZT_PACKET_IDX_VERB)
-			return false; // incomplete packets fail
-		_mangleKey((const unsigned char *)key,key2);
-		unsigned int macLen = size() - ZT_PACKET_IDX_VERB;
-		Poly1305::compute(mac,field(ZT_PACKET_IDX_VERB,macLen),macLen,key2);
-		return Utils::secureEq(mac,field(ZT_PACKET_IDX_MAC,8),8);
-	}
+		const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB;
+		unsigned char *const payload = field(ZT_PACKET_IDX_VERB,payloadLen);
 
-	/**
-	 * Encrypt this packet
-	 * 
-	 * @param key 256-bit (32 byte) key
-	 */
-	inline void encrypt(const void *key)
-	{
-		(*this)[ZT_PACKET_IDX_FLAGS] |= ZT_PROTO_FLAG_ENCRYPTED;
-		unsigned char key2[32];
-		if (size() >= ZT_PACKET_IDX_VERB) {
-			_mangleKey((const unsigned char *)key,key2);
-			Salsa20 s20(key2,256,field(ZT_PACKET_IDX_IV,8));
-			unsigned int encLen = size() - ZT_PACKET_IDX_VERB;
-			unsigned char *const encBuf = field(ZT_PACKET_IDX_VERB,encLen);
-			s20.encrypt(encBuf,encBuf,encLen);
-		}
-	}
+		_mangleKey((const unsigned char *)key,mangledKey);
+		Salsa20 s20(mangledKey,256,field(ZT_PACKET_IDX_IV,8));
 
-	/**
-	 * Decrypt this packet
-	 * 
-	 * @param key 256-bit (32 byte) key
-	 */
-	inline void decrypt(const void *key)
-	{
-		unsigned char key2[32];
-		if (size() >= ZT_PACKET_IDX_VERB) {
-			_mangleKey((const unsigned char *)key,key2);
-			Salsa20 s20(key2,256,field(ZT_PACKET_IDX_IV,8));
-			unsigned int decLen = size() - ZT_PACKET_IDX_VERB;
-			unsigned char *const decBuf = field(ZT_PACKET_IDX_VERB,decLen);
-			s20.decrypt(decBuf,decBuf,decLen);
+		memset(macKey,0,sizeof(macKey));
+		s20.encrypt(macKey,macKey,sizeof(macKey));
+		Poly1305::compute(mac,payload,payloadLen,macKey);
+		if (!Utils::secureEq(mac,field(ZT_PACKET_IDX_MAC,8),8))
+			return false;
+
+		if (((*this)[ZT_PACKET_IDX_FLAGS] & (char)ZT_PROTO_FLAG_ENCRYPTED)) {
+			s20.decrypt(payload,payload,payloadLen);
+			(*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_ENCRYPTED);
 		}
-		(*this)[ZT_PACKET_IDX_FLAGS] &= (char)(~ZT_PROTO_FLAG_ENCRYPTED);
+
+		return true;
 	}
 
 	/**
@@ -932,7 +925,7 @@ public:
 					memcpy(field(ZT_PACKET_IDX_PAYLOAD,(unsigned int)ucl),buf,ucl);
 				} else return false;
 			}
-			(*this)[ZT_PACKET_IDX_VERB] &= ~ZT_PROTO_VERB_FLAG_COMPRESSED;
+			(*this)[ZT_PACKET_IDX_VERB] &= (char)(~ZT_PROTO_VERB_FLAG_COMPRESSED);
 		}
 		return true;
 	}
@@ -946,11 +939,8 @@ private:
 	 */
 	inline void _mangleKey(const unsigned char *in,unsigned char *out) const
 	{
-		// IV and source/destination addresses. Salsa uses the IV natively
-		// so this is redundant there, but not harmful. But Poly1305 depends
-		// on the key being mangled with the IV. Using the source and
-		// destination addresses bifurcates the key space into a different
-		// key space for each direction of the conversation.
+		// IV and source/destination addresses. Using the addresses divides the
+		// key space into two halves-- A->B and B->A (since order will change).
 		for(unsigned int i=0;i<18;++i) // 8 + (ZT_ADDRESS_LENGTH * 2) == 18
 			out[i] = in[i] ^ (unsigned char)(*this)[i];
 

+ 1 - 1
node/Peer.cpp

@@ -54,7 +54,7 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity)
 	_vRevision(0),
 	_dirty(true)
 {
-	if (!myIdentity.agree(peerIdentity,_keys,sizeof(_keys)))
+	if (!myIdentity.agree(peerIdentity,_key,sizeof(_key)))
 		throw std::runtime_error("new peer identity key agreement failed");
 }
 

+ 10 - 19
node/Peer.hpp

@@ -52,7 +52,7 @@
  * Max length of serialized peer record
  */
 #define ZT_PEER_MAX_SERIALIZED_LENGTH ( \
-	64 + \
+	32 + \
 	ZT_IDENTITY_MAX_BINARY_SERIALIZED_LENGTH + \
 	( ( \
 		(sizeof(uint64_t) * 4) + \
@@ -187,7 +187,7 @@ public:
 	}
 
 	/**
-	 * @return Time of most recent unicast frame (actual data transferred)
+	 * @return Time of most recent unicast frame received
 	 */
 	uint64_t lastUnicastFrame() const
 		throw()
@@ -196,7 +196,7 @@ public:
 	}
 
 	/**
-	 * @return Time of most recent multicast frame
+	 * @return Time of most recent multicast frame received
 	 */
 	uint64_t lastMulticastFrame() const
 		throw()
@@ -305,19 +305,10 @@ public:
 	/**
 	 * @return 256-bit encryption key
 	 */
-	inline const unsigned char *cryptKey() const
+	inline const unsigned char *key() const
 		throw()
 	{
-		return _keys; // crypt key is first 32-byte key
-	}
-
-	/**
-	 * @return 256-bit MAC (message authentication code) key
-	 */
-	inline const unsigned char *macKey() const
-		throw()
-	{
-		return (_keys + 32); // mac key is second 32-byte key
+		return _key;
 	}
 
 	/**
@@ -369,8 +360,8 @@ public:
 	inline void serialize(Buffer<C> &b)
 		throw(std::out_of_range)
 	{
-		b.append((unsigned char)2); // version
-		b.append(_keys,sizeof(_keys));
+		b.append((unsigned char)3); // version
+		b.append(_key,sizeof(_key));
 		_id.serialize(b,false);
 		_ipv4p.serialize(b);
 		_ipv6p.serialize(b);
@@ -384,10 +375,10 @@ public:
 	{
 		unsigned int p = startAt;
 
-		if (b[p++] != 2)
+		if (b[p++] != 3)
 			throw std::invalid_argument("Peer: deserialize(): version mismatch");
 
-		memcpy(_keys,b.field(p,sizeof(_keys)),sizeof(_keys)); p += sizeof(_keys);
+		memcpy(_key,b.field(p,sizeof(_key)),sizeof(_key)); p += sizeof(_key);
 		p += _id.deserialize(b,p);
 		p += _ipv4p.deserialize(b,p);
 		p += _ipv6p.deserialize(b,p);
@@ -517,7 +508,7 @@ private:
 		bool fixed; // do not learn address from received packets
 	};
 
-	unsigned char _keys[32 * 2]; // crypt key[32], mac key[32]
+	unsigned char _key[32]; // shared secret key agreed upon between identities
 	Identity _id;
 
 	WanPath _ipv4p;