Browse Source

Selectively move over changes from "edge" to "dev" excluding netcon.

Adam Ierymenko 9 years ago
parent
commit
436c1fac1d

+ 28 - 19
cluster-geo/cluster-geo/cluster-geo.js

@@ -19,8 +19,8 @@ if (!config.maxmind) {
 	console.error('FATAL: only MaxMind GeoIP2 is currently supported and is not configured in config.js');
 	process.exit(1);
 }
-var geo = require('geoip2ws')(config.maxmind);
 
+var geo = require('geoip2ws')(config.maxmind);
 var cache = require('levelup')(__dirname + '/cache.leveldb');
 
 function lookup(ip,callback)
@@ -32,31 +32,40 @@ function lookup(ip,callback)
 				if (cachedEntry) {
 					let ts = cachedEntry.ts;
 					let r = cachedEntry.r;
-					if ((ts)&&(r)) {
-						if ((Date.now() - ts) < CACHE_TTL) {
-							r._cached = true;
-							return callback(null,r);
-						}
+					if ((ts)&&((Date.now() - ts) < CACHE_TTL)) {
+						//console.error(ip+': cached!');
+						return callback(null,(r) ? r : null);
 					}
 				}
 			} catch (e) {}
 		}
 
-		geo(ip,function(err,result) {
-			if (err)
-				return callback(err,null);
-			if ((!result)||(!result.location))
-				return callback(new Error('null result'),null);
-
-			cache.put(ip,JSON.stringify({
-				ts: Date.now(),
-				r: result
-			}),function(err) {
-				if (err)
-					console.error('Error saving to cache: '+err);
-				return callback(null,result);
+		cache.put(ip,JSON.stringify({
+			ts: Date.now() - (CACHE_TTL - 30000), // set ts to expire in 30 seconds while the query is in progress
+			r: null
+		}),function(err) {
+
+			geo(ip,function(err,result) {
+				if (err) {
+					//console.error(err);
+					return callback(err,null);
+				}
+
+				if (!result)
+					result = null;
+
+				cache.put(ip,JSON.stringify({
+					ts: Date.now(),
+					r: result
+				}),function(err) {
+					if (err)
+						console.error('Error saving to cache: '+err);
+					return callback(null,result);
+				});
 			});
+
 		});
+
 	});
 };
 

+ 4 - 2
controller/SqliteNetworkController.cpp

@@ -72,7 +72,7 @@
 #define ZT_NETCONF_MIN_REQUEST_PERIOD 1000
 
 // Delay between backups in milliseconds
-#define ZT_NETCONF_BACKUP_PERIOD 60000
+#define ZT_NETCONF_BACKUP_PERIOD 120000
 
 namespace ZeroTier {
 
@@ -1719,7 +1719,9 @@ NetworkController::ResultCode SqliteNetworkController::_doNetworkConfigRequest(c
 				netconf[ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES] = activeBridges;
 		}
 
-		{
+		// Do not send relays to 1.1.0 since it had a serious bug in using them
+		// 1.1.0 will still work, it'll just fall back to roots instead of using network preferred relays
+		if (!((clientMajorVersion == 1)&&(clientMinorVersion == 1)&&(clientRevision == 0))) {
 			std::string relays;
 			sqlite3_reset(_sGetRelays);
 			sqlite3_bind_text(_sGetRelays,1,network.id,16,SQLITE_STATIC);

+ 5 - 5
ext/installfiles/windows/ZeroTier One.aip

@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
-<DOCUMENT Type="Advanced Installer" CreateVersion="10.9" version="12.5" Modules="enterprise" RootPath="." Language="en" Id="{DC564647-6BF0-4550-87F4-89C938D0159C}">
+<DOCUMENT Type="Advanced Installer" CreateVersion="10.9" version="12.5.1" Modules="enterprise" RootPath="." Language="en" Id="{DC564647-6BF0-4550-87F4-89C938D0159C}">
   <COMPONENT cid="caphyon.advinst.msicomp.ProjectOptionsComponent">
     <ROW Name="HiddenItems" Value="UpdaterComponent;SerValComponent;AutorunComponent;MultipleInstancesComponent;MsiJavaComponent;MsiRegsComponent;MsiExtComponent;MsiAssemblyComponent;MsiDriverPackagesComponent;AnalyticsComponent;ActSyncAppComponent;MsiMergeModsComponent;MsiThemeComponent;BackgroundImagesComponent;DictionaryComponent;MsiEnvComponent;ScheduledTasksComponent;CPLAppletComponent;GameUxComponent;UserAccountsComponent;MsiClassComponent;WebApplicationsComponent;MsiOdbcDataSrcComponent;SqlConnectionComponent;SharePointSlnComponent;SilverlightSlnComponent;MsiAppSearchComponent"/>
   </COMPONENT>
@@ -26,10 +26,10 @@
     <ROW Property="CTRLS" Value="2"/>
     <ROW Property="MSIFASTINSTALL" MultiBuildValue="DefaultBuild:2"/>
     <ROW Property="Manufacturer" Value="ZeroTier, Inc."/>
-    <ROW Property="ProductCode" Value="1033:{E517BA79-1770-4556-B7A4-622434A9982B} " Type="16"/>
+    <ROW Property="ProductCode" Value="1033:{8C736E22-3E6F-478D-B358-65DD687E9CF3} " Type="16"/>
     <ROW Property="ProductLanguage" Value="1033"/>
     <ROW Property="ProductName" Value="ZeroTier One"/>
-    <ROW Property="ProductVersion" Value="1.1.0" Type="32"/>
+    <ROW Property="ProductVersion" Value="1.1.2" Type="32"/>
     <ROW Property="REBOOT" MultiBuildValue="DefaultBuild:ReallySuppress"/>
     <ROW Property="RUNAPPLICATION" Value="1" Type="4"/>
     <ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND"/>
@@ -59,7 +59,7 @@
     <ROW Directory="x86_Dir" Directory_Parent="tapwindows_Dir" DefaultDir="x86"/>
   </COMPONENT>
   <COMPONENT cid="caphyon.advinst.msicomp.MsiCompsComponent">
-    <ROW Component="AI_CustomARPName" ComponentId="{CD637A90-1485-4337-ABA6-C58C97157356}" Directory_="APPDIR" Attributes="4" KeyPath="DisplayName" Options="1"/>
+    <ROW Component="AI_CustomARPName" ComponentId="{0F49E5E5-7D43-4204-A667-51FDF0BA9549}" Directory_="APPDIR" Attributes="4" KeyPath="DisplayName" Options="1"/>
     <ROW Component="AI_DisableModify" ComponentId="{020DCABD-5D56-49B9-AF48-F07F0B55E590}" Directory_="APPDIR" Attributes="4" KeyPath="NoModify" Options="1"/>
     <ROW Component="Newtonsoft.Json.dll" ComponentId="{0B2F229D-5425-42FB-9E28-F6D25AB2B4B5}" Directory_="APPDIR" Attributes="0" KeyPath="Newtonsoft.Json.dll"/>
     <ROW Component="ProductInformation" ComponentId="{DB078D04-EA8E-4A7C-9001-89BAD932F9D9}" Directory_="APPDIR" Attributes="4" KeyPath="Version"/>
@@ -338,7 +338,7 @@
     <ROW XmlAttribute="xsischemaLocation" XmlElement="swidsoftware_identification_tag" Name="xsi:schemaLocation" Flags="14" Order="3" Value="http://standards.iso.org/iso/19770/-2/2008/schema.xsd software_identification_tag.xsd"/>
   </COMPONENT>
   <COMPONENT cid="caphyon.advinst.msicomp.XmlElementComponent">
-    <ROW XmlElement="swidbuild" ParentElement="swidnumeric" Name="swid:build" Condition="1" Order="2" Flags="14" Text="0"/>
+    <ROW XmlElement="swidbuild" ParentElement="swidnumeric" Name="swid:build" Condition="1" Order="2" Flags="14" Text="2"/>
     <ROW XmlElement="swidentitlement_required_indicator" ParentElement="swidsoftware_identification_tag" Name="swid:entitlement_required_indicator" Condition="1" Order="0" Flags="14" Text="false"/>
     <ROW XmlElement="swidmajor" ParentElement="swidnumeric" Name="swid:major" Condition="1" Order="0" Flags="14" Text="1"/>
     <ROW XmlElement="swidminor" ParentElement="swidnumeric" Name="swid:minor" Condition="1" Order="1" Flags="14" Text="1"/>

+ 4 - 0
ext/libnatpmp/natpmp.c

@@ -39,8 +39,12 @@ POSSIBILITY OF SUCH DAMAGE.
 #include <winsock2.h>
 #include <ws2tcpip.h>
 #include <io.h>
+#ifndef EWOULDBLOCK
 #define EWOULDBLOCK WSAEWOULDBLOCK
+#endif
+#ifndef ECONNREFUSED
 #define ECONNREFUSED WSAECONNREFUSED
+#endif
 #include "wingettimeofday.h"
 #define gettimeofday natpmp_gettimeofday
 #else

+ 10 - 5
node/Constants.hpp

@@ -293,11 +293,6 @@
  */
 #define ZT_NAT_T_TACTICAL_ESCALATION_DELAY 1000
 
-/**
- * Minimum delay between attempts to confirm new paths to peers (to avoid HELLO flooding)
- */
-#define ZT_MIN_PATH_CONFIRMATION_INTERVAL 1000
-
 /**
  * How long (max) to remember network certificates of membership?
  *
@@ -358,4 +353,14 @@
  */
 #define ZT_TEST_NETWORK_ID 0xffffffffffffffffULL
 
+/* Ethernet frame types that might be relevant to us */
+#define ZT_ETHERTYPE_IPV4 0x0800
+#define ZT_ETHERTYPE_ARP 0x0806
+#define ZT_ETHERTYPE_RARP 0x8035
+#define ZT_ETHERTYPE_ATALK 0x809b
+#define ZT_ETHERTYPE_AARP 0x80f3
+#define ZT_ETHERTYPE_IPX_A 0x8137
+#define ZT_ETHERTYPE_IPX_B 0x8138
+#define ZT_ETHERTYPE_IPV6 0x86dd
+
 #endif

+ 8 - 4
node/DeferredPackets.cpp

@@ -37,6 +37,7 @@ DeferredPackets::DeferredPackets(const RuntimeEnvironment *renv) :
 	RR(renv),
 	_readPtr(0),
 	_writePtr(0),
+	_waiting(0),
 	_die(false)
 {
 }
@@ -45,8 +46,11 @@ DeferredPackets::~DeferredPackets()
 {
 	_q_m.lock();
 	_die = true;
-	_q_m.unlock();
-	_q_s.post();
+	while (_waiting > 0) {
+		_q_m.unlock();
+		_q_s.post();
+		_q_m.lock();
+	}
 }
 
 bool DeferredPackets::enqueue(IncomingPacket *pkt)
@@ -72,16 +76,16 @@ int DeferredPackets::process()
 	_q_m.lock();
 	if (_die) {
 		_q_m.unlock();
-		_q_s.post();
 		return -1;
 	}
 	while (_readPtr == _writePtr) {
+		++_waiting;
 		_q_m.unlock();
 		_q_s.wait();
 		_q_m.lock();
+		--_waiting;
 		if (_die) {
 			_q_m.unlock();
-			_q_s.post();
 			return -1;
 		}
 	}

+ 2 - 1
node/DeferredPackets.hpp

@@ -88,7 +88,8 @@ private:
 	const RuntimeEnvironment *const RR;
 	unsigned long _readPtr;
 	unsigned long _writePtr;
-	bool _die;
+ 	volatile int _waiting;
+	volatile bool _die;
 	Mutex _q_m;
 	BinarySemaphore _q_s;
 };

+ 9 - 4
node/IncomingPacket.cpp

@@ -348,7 +348,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,SharedPtr<Peer> &peer
 		RR->antiRec->logOutgoingZT(outp.data(),outp.size());
 		RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
 
-		peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision);
+		peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version
 		peer->received(RR,_localAddress,_remoteAddress,hops(),pid,Packet::VERB_HELLO,0,Packet::VERB_NOP);
 	} catch ( ... ) {
 		TRACE("dropped HELLO from %s(%s): unexpected exception",source().toString().c_str(),_remoteAddress.toString().c_str());
@@ -426,6 +426,9 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr<Peer> &p
 				}
 			}	break;
 
+			//case Packet::VERB_ECHO: {
+			//}	break;
+
 			case Packet::VERB_MULTICAST_GATHER: {
 				const uint64_t nwid = at<uint64_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID);
 				const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_MAC,6),6),at<uint32_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_ADI));
@@ -638,7 +641,9 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,const SharedPtr<Peer>
 		Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
 		outp.append((unsigned char)Packet::VERB_ECHO);
 		outp.append((uint64_t)pid);
-		outp.append(field(ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD),size() - ZT_PACKET_IDX_PAYLOAD);
+		if (size() > ZT_PACKET_IDX_PAYLOAD)
+			outp.append(reinterpret_cast<const unsigned char *>(data()) + ZT_PACKET_IDX_PAYLOAD,size() - ZT_PACKET_IDX_PAYLOAD);
+		outp.armor(peer->key(),true);
 		RR->antiRec->logOutgoingZT(outp.data(),outp.size());
 		RR->node->putPacket(_localAddress,_remoteAddress,outp.data(),outp.size());
 		peer->received(RR,_localAddress,_remoteAddress,hops(),pid,Packet::VERB_ECHO,0,Packet::VERB_NOP);
@@ -947,7 +952,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
 			switch(addrType) {
 				case 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)) && (!peer->hasActivePathTo(now,a)) ) {
 						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->sendHELLO(RR,_localAddress,a,now);
@@ -958,7 +963,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
 				}	break;
 				case 6: {
 					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)) && (!peer->hasActivePathTo(now,a)) ) {
 						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->sendHELLO(RR,_localAddress,a,now);

+ 0 - 1
node/Packet.cpp

@@ -52,7 +52,6 @@ const char *Packet::verbString(Verb v)
 		case VERB_NETWORK_CONFIG_REFRESH: return "NETWORK_CONFIG_REFRESH";
 		case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER";
 		case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME";
-		case VERB_SET_EPHEMERAL_KEY: return "SET_EPHEMERAL_KEY";
 		case VERB_PUSH_DIRECT_PATHS: return "PUSH_DIRECT_PATHS";
 		case VERB_CIRCUIT_TEST: return "CIRCUIT_TEST";
 		case VERB_CIRCUIT_TEST_REPORT: return "CIRCUIT_TEST_REPORT";

+ 8 - 58
node/Packet.hpp

@@ -678,7 +678,14 @@ public:
 		 *   <[...] arbitrary payload to be echoed back>
 		 *
 		 * This generates OK with a copy of the transmitted payload. No ERROR
-		 * is generated. Response to ECHO requests is optional.
+		 * is generated. Response to ECHO requests is optional and ECHO may be
+		 * ignored if a node detects a possible flood.
+		 *
+		 * There is a de-facto standard for ECHO payload. No payload indicates an
+		 * ECHO used for path confirmation. Otherwise the first byte contains
+		 * flags, in which currently the only flag is 0x01 for a user-requested
+		 * echo. For user-requested echoes the result may be reported back through
+		 * the API. Otherwise the payload is for internal use.
 		 *
 		 * Support for fragmented echo packets is optional and their use is not
 		 * recommended.
@@ -844,63 +851,6 @@ public:
 		 */
 		VERB_MULTICAST_FRAME = 14,
 
-		/**
-		 * Ephemeral (PFS) key push: (UNFINISHED, NOT IMPLEMENTED YET)
-		 *   <[2] flags (unused and reserved, must be 0)>
-		 *   <[2] length of padding / extra field section>
-		 *   <[...] padding / extra field section>
-		 *   <[8] 64-bit PFS key set ID sender holds for recipient (0==none)>
-		 *   <[8] 64-bit PFS key set ID of this key set>
-		 *   [... begin PFS key record ...]
-		 *   <[1] flags>
-		 *   <[1] symmetric cipher ID>
-		 *   <[1] public key type ID>
-		 *   <[2] public key length in bytes>
-		 *   <[...] public key>
-		 *   [... additional records may follow up to max packet length ...]
-		 *
-		 * This message is sent to negotiate an ephemeral key. If the recipient's
-		 * current key pair for the sender does not match the one the sender
-		 * claims to have on file, it must respond with its own SET_EPHEMERAL_KEY.
-		 *
-		 * PFS key IDs are random and must not be zero, since zero indicates that
-		 * the sender does not have an ephemeral key on file for the recipient.
-		 *
-		 * One or more records may be sent. If multiple records are present,
-		 * the first record with common symmetric cipher, public key type,
-		 * and relevant flags must be used.
-		 *
-		 * The padding section may be filled with an arbitrary amount of random
-		 * or empty payload. This may be used as a countermeasure to prevent PFS
-		 * key pushes from being recognized by packet size vs. other packets in
-		 * the stream. This also provides potential space for additional fields
-		 * that might be indicated in the future by flags.
-		 *
-		 * Flags (all unspecified flags must be zero):
-		 *   0x01 - FIPS mode, only use record if FIPS compliant crypto in use
-		 *
-		 * Symmetric cipher IDs:
-		 *   0x01 - Salsa20/12 with Poly1305 authentication (ZT default)
-		 *   0x02 - AES256-GCM combined crypto and authentication
-		 *
-		 * Public key types:
-		 *   0x01 - Curve25519 ECDH with SHA-512 KDF
-		 *   0x02 - NIST P-256 ECDH with SHA-512 KDF
-		 *
-		 * Once both peers have a PFS key, they will attempt to send PFS key
-		 * encrypted messages with the PFS flag set using the negotiated
-		 * cipher/auth type.
-		 *
-		 * Note: most of these features such as FIPS and other cipher suites are
-		 * not implemented yet. They're just specified in the protocol for future
-		 * use to support e.g. FIPS requirements.
-		 *
-		 * OK response payload:
-		 *   <[8] PFS key set ID of received key set>
-		 *   <[1] index in record list of chosen key record>
-		 */
-		VERB_SET_EPHEMERAL_KEY = 15,
-
 		/**
 		 * Push of potential endpoints for direct communication:
 		 *   <[2] 16-bit number of paths>

+ 24 - 3
node/Path.hpp

@@ -47,6 +47,11 @@
  */
 #define ZT_PATH_FLAG_CLUSTER_SUBOPTIMAL 0x0001
 
+/**
+ * Maximum return value of preferenceRank()
+ */
+#define ZT_PATH_MAX_PREFERENCE_RANK ((ZT_INETADDRESS_MAX_SCOPE << 1) | 1)
+
 namespace ZeroTier {
 
 class RuntimeEnvironment;
@@ -149,9 +154,9 @@ public:
 	inline InetAddress::IpScope ipScope() const throw() { return _ipScope; }
 
 	/**
-	 * @return Preference rank, higher == better
+	 * @return Preference rank, higher == better (will be less than 255)
 	 */
-	inline int preferenceRank() const throw()
+	inline unsigned int preferenceRank() const throw()
 	{
 		// First, since the scope enum values in InetAddress.hpp are in order of
 		// use preference rank, we take that. Then we multiple by two, yielding
@@ -159,7 +164,20 @@ public:
 		// makes IPv6 addresses of a given scope outrank IPv4 addresses of the
 		// same scope -- e.g. 1 outranks 0. This makes us prefer IPv6, but not
 		// if the address scope/class is of a fundamentally lower rank.
-		return ( ((int)_ipScope * 2) + ((_addr.ss_family == AF_INET6) ? 1 : 0) );
+		return ( ((unsigned int)_ipScope << 1) | (unsigned int)(_addr.ss_family == AF_INET6) );
+	}
+
+	/**
+	 * @return This path's overall score (higher == better)
+	 */
+	inline uint64_t score() const throw()
+	{
+		/* We compute the score based on the "freshness" of the path (when we last
+		 * received something) scaled/corrected by the preference rank within the
+		 * ping keepalive window. That way higher ranking paths are preferred but
+		 * not to the point of overriding timeouts and choosing potentially dead
+		 * paths. */
+		return (_lastReceived + (preferenceRank() * (ZT_PEER_DIRECT_PING_DELAY / ZT_PATH_MAX_PREFERENCE_RANK)));
 	}
 
 	/**
@@ -248,6 +266,9 @@ public:
 		return (p - startAt);
 	}
 
+	inline bool operator==(const Path &p) const { return ((p._addr == _addr)&&(p._localAddress == _localAddress)); }
+	inline bool operator!=(const Path &p) const { return ((p._addr != _addr)||(p._localAddress != _localAddress)); }
+
 private:
 	uint64_t _lastSend;
 	uint64_t _lastReceived;

+ 27 - 68
node/Peer.cpp

@@ -53,7 +53,6 @@ Peer::Peer(const Identity &myIdentity,const Identity &peerIdentity)
 	_lastUnicastFrame(0),
 	_lastMulticastFrame(0),
 	_lastAnnouncedTo(0),
-	_lastPathConfirmationSent(0),
 	_lastDirectPathPushSent(0),
 	_lastDirectPathPushReceive(0),
 	_lastPathSort(0),
@@ -132,7 +131,6 @@ void Peer::received(
 
 	const uint64_t now = RR->node->now();
 	bool needMulticastGroupAnnounce = false;
-	bool pathIsConfirmed = false;
 
 	{	// begin _lock
 		Mutex::Lock _l(_lock);
@@ -149,6 +147,7 @@ void Peer::received(
 		}
 
 		if (hops == 0) {
+			bool pathIsConfirmed = false;
 			unsigned int np = _numPaths;
 			for(unsigned int p=0;p<np;++p) {
 				if ((_paths[p].address() == remoteAddr)&&(_paths[p].localAddress() == localAddr)) {
@@ -183,8 +182,6 @@ void Peer::received(
 						slot->setClusterSuboptimal(suboptimalPath);
 #endif
 						_numPaths = np;
-						pathIsConfirmed = true;
-						_sortPaths(now);
 					}
 
 #ifdef ZT_ENABLE_CLUSTER
@@ -194,13 +191,14 @@ void Peer::received(
 
 				} else {
 
-					/* If this path is not known, send a HELLO. We don't learn
-					 * paths without confirming that a bidirectional link is in
-					 * fact present, but any packet that decodes and authenticates
-					 * correctly is considered valid. */
-					if ((now - _lastPathConfirmationSent) >= ZT_MIN_PATH_CONFIRMATION_INTERVAL) {
-						_lastPathConfirmationSent = now;
-						TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),remoteAddr.toString().c_str());
+					TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),remoteAddr.toString().c_str());
+
+					if ( (_vProto >= 5) && ( !((_vMajor == 1)&&(_vMinor == 1)&&(_vRevision == 0)) ) ) {
+						// 1.1.1 and newer nodes support ECHO, which is smaller -- but 1.1.0 has a bug so use HELLO there too
+						Packet outp(_id.address(),RR->identity.address(),Packet::VERB_ECHO);
+						outp.armor(_key,true);
+						RR->node->putPacket(localAddr,remoteAddr,outp.data(),outp.size());
+					} else {
 						sendHELLO(RR,localAddr,remoteAddr,now);
 					}
 
@@ -314,21 +312,7 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,Path *path,uint64_t now,
 						continue;
 				}
 
-				uint8_t flags = 0;
-				/* TODO: path trust is not implemented yet
-				switch(p->trust()) {
-					default:
-						break;
-					case Path::TRUST_PRIVACY:
-						flags |= 0x04; // no encryption
-						break;
-					case Path::TRUST_ULTIMATE:
-						flags |= (0x04 | 0x08); // no encryption, no authentication (redundant but go ahead and set both)
-						break;
-				}
-				*/
-
-				outp.append(flags);
+				outp.append((uint8_t)0); // no flags
 				outp.append((uint16_t)0); // no extensions
 				outp.append(addressType);
 				outp.append((uint8_t)((addressType == 4) ? 6 : 18));
@@ -363,7 +347,6 @@ bool Peer::resetWithinScope(const RuntimeEnvironment *RR,InetAddress::IpScope sc
 		++x;
 	}
 	_numPaths = y;
-	_sortPaths(now);
 	return (y < np);
 }
 
@@ -502,58 +485,34 @@ void Peer::clean(const RuntimeEnvironment *RR,uint64_t now)
 	}
 }
 
-struct _SortPathsByQuality
-{
-	uint64_t _now;
-	_SortPathsByQuality(const uint64_t now) : _now(now) {}
-	inline bool operator()(const Path &a,const Path &b) const
-	{
-		const uint64_t qa = (
-			((uint64_t)a.active(_now) << 63) |
-			(((uint64_t)(a.preferenceRank() & 0xfff)) << 51) |
-			((uint64_t)a.lastReceived() & 0x7ffffffffffffULL) );
-		const uint64_t qb = (
-			((uint64_t)b.active(_now) << 63) |
-			(((uint64_t)(b.preferenceRank() & 0xfff)) << 51) |
-			((uint64_t)b.lastReceived() & 0x7ffffffffffffULL) );
-		return (qb < qa); // invert sense to sort in descending order
-	}
-};
-void Peer::_sortPaths(const uint64_t now)
-{
-	// assumes _lock is locked
-	_lastPathSort = now;
-	std::sort(&(_paths[0]),&(_paths[_numPaths]),_SortPathsByQuality(now));
-}
-
 Path *Peer::_getBestPath(const uint64_t now)
 {
 	// assumes _lock is locked
-	if ((now - _lastPathSort) >= ZT_PEER_PATH_SORT_INTERVAL)
-		_sortPaths(now);
-	if (_paths[0].active(now)) {
-		return &(_paths[0]);
-	} else {
-		_sortPaths(now);
-		if (_paths[0].active(now))
-			return &(_paths[0]);
+	Path *bestPath = (Path *)0;
+	uint64_t bestPathScore = 0;
+	for(unsigned int i=0;i<_numPaths;++i) {
+		const uint64_t score = _paths[i].score();
+		if ((score >= bestPathScore)&&(_paths[i].active(now))) {
+			bestPathScore = score;
+			bestPath = &(_paths[i]);
+		}
 	}
-	return (Path *)0;
+	return bestPath;
 }
 
 Path *Peer::_getBestPath(const uint64_t now,int inetAddressFamily)
 {
 	// assumes _lock is locked
-	if ((now - _lastPathSort) >= ZT_PEER_PATH_SORT_INTERVAL)
-		_sortPaths(now);
-	for(int k=0;k<2;++k) { // try once, and if it fails sort and try one more time
-		for(unsigned int i=0;i<_numPaths;++i) {
-			if ((_paths[i].active(now))&&((int)_paths[i].address().ss_family == inetAddressFamily))
-				return &(_paths[i]);
+	Path *bestPath = (Path *)0;
+	uint64_t bestPathScore = 0;
+	for(unsigned int i=0;i<_numPaths;++i) {
+		const uint64_t score = _paths[i].score();
+		if (((int)_paths[i].address().ss_family == inetAddressFamily)&&(score >= bestPathScore)&&(_paths[i].active(now))) {
+			bestPathScore = score;
+			bestPath = &(_paths[i]);
 		}
-		_sortPaths(now);
 	}
-	return (Path *)0;
+	return bestPath;
 }
 
 } // namespace ZeroTier

+ 22 - 29
node/Peer.hpp

@@ -152,7 +152,7 @@ public:
 	 */
 	inline Path *send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now)
 	{
-		Path *bestPath = getBestPath(now);
+		Path *const bestPath = getBestPath(now);
 		if (bestPath) {
 			if (bestPath->send(RR,data,len,now))
 				return bestPath;
@@ -185,7 +185,7 @@ public:
 	bool doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now,int inetAddressFamily);
 
 	/**
-	 * Push direct paths if we haven't done so in [rate limit] milliseconds
+	 * Push direct paths back to self if we haven't done so in the configured timeout
 	 *
 	 * @param RR Runtime environment
 	 * @param path Remote path to use to send the push
@@ -232,7 +232,7 @@ public:
 	inline uint64_t lastAnnouncedTo() const throw() { return _lastAnnouncedTo; }
 
 	/**
-	 * @return True if this peer is actively sending real network frames
+	 * @return True if this peer has sent us real network traffic recently
 	 */
 	inline uint64_t activelyTransferringFrames(uint64_t now) const throw() { return ((now - lastFrame()) < ZT_PEER_ACTIVITY_TIMEOUT); }
 
@@ -283,7 +283,7 @@ public:
 	inline bool hasActiveDirectPath(uint64_t now) const
 	{
 		Mutex::Lock _l(_lock);
-		for(unsigned int p=0,np=_numPaths;p<np;++p) {
+		for(unsigned int p=0;p<_numPaths;++p) {
 			if (_paths[p].active(now))
 				return true;
 		}
@@ -306,6 +306,21 @@ public:
 	}
 #endif
 
+	/**
+	 * @param now Current time
+	 * @param addr Remote address
+	 * @return True if peer currently has an active direct path to addr
+	 */
+	inline bool hasActivePathTo(uint64_t now,const InetAddress &addr) const
+	{
+		Mutex::Lock _l(_lock);
+		for(unsigned int p=0;p<_numPaths;++p) {
+			if ((_paths[p].active(now))&&(_paths[p].address() == addr))
+				return true;
+		}
+		return false;
+	}
+
 	/**
 	 * Reset paths within a given scope
 	 *
@@ -341,6 +356,7 @@ public:
 	inline unsigned int remoteVersionMajor() const throw() { return _vMajor; }
 	inline unsigned int remoteVersionMinor() const throw() { return _vMinor; }
 	inline unsigned int remoteVersionRevision() const throw() { return _vRevision; }
+
 	inline bool remoteVersionKnown() const throw() { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); }
 
 	/**
@@ -386,25 +402,6 @@ public:
 	 */
 	void clean(const RuntimeEnvironment *RR,uint64_t now);
 
-	/**
-	 * Remove all paths with this remote address
-	 *
-	 * @param addr Remote address to remove
-	 */
-	inline void removePathByAddress(const InetAddress &addr)
-	{
-		Mutex::Lock _l(_lock);
-		unsigned int np = _numPaths;
-		unsigned int x = 0;
-		unsigned int y = 0;
-		while (x < np) {
-			if (_paths[x].address() != addr)
-				_paths[y++] = _paths[x];
-			++x;
-		}
-		_numPaths = y;
-	}
-
 	/**
 	 * Update direct path push stats and return true if we should respond
 	 *
@@ -454,7 +451,7 @@ public:
 		const unsigned int recSizePos = b.size();
 		b.addSize(4); // space for uint32_t field length
 
-		b.append((uint16_t)0); // version of serialized Peer data
+		b.append((uint16_t)1); // version of serialized Peer data
 
 		_id.serialize(b,false);
 
@@ -463,7 +460,6 @@ public:
 		b.append((uint64_t)_lastUnicastFrame);
 		b.append((uint64_t)_lastMulticastFrame);
 		b.append((uint64_t)_lastAnnouncedTo);
-		b.append((uint64_t)_lastPathConfirmationSent);
 		b.append((uint64_t)_lastDirectPathPushSent);
 		b.append((uint64_t)_lastDirectPathPushReceive);
 		b.append((uint64_t)_lastPathSort);
@@ -518,7 +514,7 @@ public:
 		const unsigned int recSize = b.template at<uint32_t>(p); p += 4;
 		if ((p + recSize) > b.size())
 			return SharedPtr<Peer>(); // size invalid
-		if (b.template at<uint16_t>(p) != 0)
+		if (b.template at<uint16_t>(p) != 1)
 			return SharedPtr<Peer>(); // version mismatch
 		p += 2;
 
@@ -534,7 +530,6 @@ public:
 		np->_lastUnicastFrame = b.template at<uint64_t>(p); p += 8;
 		np->_lastMulticastFrame = b.template at<uint64_t>(p); p += 8;
 		np->_lastAnnouncedTo = b.template at<uint64_t>(p); p += 8;
-		np->_lastPathConfirmationSent = b.template at<uint64_t>(p); p += 8;
 		np->_lastDirectPathPushSent = b.template at<uint64_t>(p); p += 8;
 		np->_lastDirectPathPushReceive = b.template at<uint64_t>(p); p += 8;
 		np->_lastPathSort = b.template at<uint64_t>(p); p += 8;
@@ -574,7 +569,6 @@ public:
 	}
 
 private:
-	void _sortPaths(const uint64_t now);
 	Path *_getBestPath(const uint64_t now);
 	Path *_getBestPath(const uint64_t now,int inetAddressFamily);
 
@@ -585,7 +579,6 @@ private:
 	uint64_t _lastUnicastFrame;
 	uint64_t _lastMulticastFrame;
 	uint64_t _lastAnnouncedTo;
-	uint64_t _lastPathConfirmationSent;
 	uint64_t _lastDirectPathPushSent;
 	uint64_t _lastDirectPathPushReceive;
 	uint64_t _lastPathSort;

+ 1 - 0
node/RuntimeEnvironment.hpp

@@ -66,6 +66,7 @@ public:
 #ifdef ZT_ENABLE_CLUSTER
 		,cluster((Cluster *)0)
 #endif
+		,dpEnabled(0)
 	{
 	}
 

+ 1 - 1
node/Switch.cpp

@@ -96,7 +96,7 @@ void Switch::onRemotePacket(const InetAddress &localAddr,const InetAddress &from
 				if ((now - _lastBeaconResponse) >= 2500) { // limit rate of responses
 					_lastBeaconResponse = now;
 					Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP);
-					outp.armor(peer->key(),false);
+					outp.armor(peer->key(),true);
 					RR->node->putPacket(localAddr,fromAddr,outp.data(),outp.size());
 				}
 			}

+ 0 - 10
node/Switch.hpp

@@ -47,16 +47,6 @@
 #include "IncomingPacket.hpp"
 #include "Hashtable.hpp"
 
-/* Ethernet frame types that might be relevant to us */
-#define ZT_ETHERTYPE_IPV4 0x0800
-#define ZT_ETHERTYPE_ARP 0x0806
-#define ZT_ETHERTYPE_RARP 0x8035
-#define ZT_ETHERTYPE_ATALK 0x809b
-#define ZT_ETHERTYPE_AARP 0x80f3
-#define ZT_ETHERTYPE_IPX_A 0x8137
-#define ZT_ETHERTYPE_IPX_B 0x8138
-#define ZT_ETHERTYPE_IPV6 0x86dd
-
 namespace ZeroTier {
 
 class RuntimeEnvironment;

File diff suppressed because it is too large
+ 0 - 0
node/Topology.cpp


+ 25 - 21
node/Utils.cpp

@@ -29,6 +29,7 @@
 #include <string.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <time.h>
 #include <sys/stat.h>
 
 #include "Constants.hpp"
@@ -149,44 +150,50 @@ unsigned int Utils::unhex(const char *hex,unsigned int maxlen,void *buf,unsigned
 
 void Utils::getSecureRandom(void *buf,unsigned int bytes)
 {
-#ifdef __WINDOWS__
-
-	static HCRYPTPROV cryptProvider = NULL;
 	static Mutex globalLock;
 	static Salsa20 s20;
+	static bool s20Initialized = false;
 
 	Mutex::Lock _l(globalLock);
 
+	/* Just for posterity we Salsa20 encrypt the result of whatever system
+	 * CSPRNG we use. There have been several bugs at the OS or OS distribution
+	 * level in the past that resulted in systematically weak or predictable
+	 * keys due to random seeding problems. This mitigates that by grabbing
+	 * a bit of extra entropy and further randomizing the result, and comes
+	 * at almost no cost and with no real downside if the random source is
+	 * good. */
+	if (!s20Initialized) {
+		s20Initialized = true;
+		uint64_t s20Key[4];
+		s20Key[0] = (uint64_t)time(0); // system clock
+		s20Key[1] = (uint64_t)buf; // address of buf
+		s20Key[2] = (uint64_t)s20Key; // address of s20Key[]
+		s20Key[3] = (uint64_t)&s20; // address of s20
+		s20.init(s20Key,256,s20Key);
+	}
+
+#ifdef __WINDOWS__
+
+	static HCRYPTPROV cryptProvider = NULL;
+
 	if (cryptProvider == NULL) {
 		if (!CryptAcquireContextA(&cryptProvider,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) {
 			fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() unable to obtain WinCrypt context!\r\n");
 			exit(1);
 			return;
 		}
-		char s20key[32];
-		if (!CryptGenRandom(cryptProvider,(DWORD)sizeof(s20key),(BYTE *)s20key)) {
-			fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n");
-			exit(1);
-		}
-		s20.init(s20key,256,s20key);
 	}
-
 	if (!CryptGenRandom(cryptProvider,(DWORD)bytes,(BYTE *)buf)) {
 		fprintf(stderr,"FATAL ERROR: Utils::getSecureRandom() CryptGenRandom failed!\r\n");
 		exit(1);
 	}
-	s20.encrypt12(buf,buf,bytes);
 
 #else // not __WINDOWS__
 
-#ifdef __UNIX_LIKE__
-
 	static char randomBuf[131072];
 	static unsigned int randomPtr = sizeof(randomBuf);
 	static int devURandomFd = -1;
-	static Mutex globalLock;
-
-	Mutex::Lock _l(globalLock);
 
 	if (devURandomFd <= 0) {
 		devURandomFd = ::open("/dev/urandom",O_RDONLY);
@@ -215,12 +222,9 @@ void Utils::getSecureRandom(void *buf,unsigned int bytes)
 		((char *)buf)[i] = randomBuf[randomPtr++];
 	}
 
-#else // not __UNIX_LIKE__
+#endif // __WINDOWS__ or not
 
-#error No getSecureRandom() implementation available.
-
-#endif // __UNIX_LIKE__
-#endif // __WINDOWS__
+	s20.encrypt12(buf,buf,bytes);
 }
 
 std::vector<std::string> Utils::split(const char *s,const char *const sep,const char *esc,const char *quot)

+ 8 - 6
one.cpp

@@ -366,8 +366,8 @@ static int cli(int argc,char **argv)
 												const char *paddr = (const char *)0;
 												int64_t lastSend = 0;
 												int64_t lastReceive = 0;
-												bool fixed = false;
-												bool active = false; // fixed/active/inactive
+												bool preferred = false;
+												bool active = false;
 												for(unsigned int kk=0;kk<jpath->u.object.length;++kk) {
 													if ((!strcmp(jpath->u.object.values[kk].name,"address"))&&(jpath->u.object.values[kk].value->type == json_string))
 														paddr = jpath->u.object.values[kk].value->u.string.ptr;
@@ -375,12 +375,12 @@ static int cli(int argc,char **argv)
 														lastSend = jpath->u.object.values[kk].value->u.integer;
 													else if ((!strcmp(jpath->u.object.values[kk].name,"lastReceive"))&&(jpath->u.object.values[kk].value->type == json_integer))
 														lastReceive = jpath->u.object.values[kk].value->u.integer;
-													else if ((!strcmp(jpath->u.object.values[kk].name,"fixed"))&&(jpath->u.object.values[kk].value->type == json_boolean))
-														fixed = (jpath->u.object.values[kk].value->u.boolean != 0);
+													else if ((!strcmp(jpath->u.object.values[kk].name,"preferred"))&&(jpath->u.object.values[kk].value->type == json_boolean))
+														preferred = (jpath->u.object.values[kk].value->u.boolean != 0);
 													else if ((!strcmp(jpath->u.object.values[kk].name,"active"))&&(jpath->u.object.values[kk].value->type == json_boolean))
 														active = (jpath->u.object.values[kk].value->u.boolean != 0);
 												}
-												if ((paddr)&&((active)||(fixed))) {
+												if ((paddr)&&(active)) {
 													int64_t now = (int64_t)OSUtils::now();
 													if (lastSend > 0)
 														lastSend = now - lastSend;
@@ -391,7 +391,7 @@ static int cli(int argc,char **argv)
 														paddr,
 														lastSend,
 														lastReceive,
-														(fixed ? "fixed" : (active ? "active" : "inactive")));
+														(preferred ? "preferred" : "active"));
 													if (paths.length())
 														paths.push_back(',');
 													paths.append(pathtmp);
@@ -1096,10 +1096,12 @@ int main(int argc,char **argv)
 	}
 
 #ifdef __UNIX_LIKE__
+#ifndef ZT_ONE_NO_ROOT_CHECK
 	if ((!skipRootCheck)&&(getuid() != 0)) {
 		fprintf(stderr,"%s: must be run as root (uid 0)"ZT_EOL_S,argv[0]);
 		return 1;
 	}
+#endif // !ZT_ONE_NO_ROOT_CHECK
 	if (runAsDaemon) {
 		long p = (long)fork();
 		if (p < 0) {

+ 10 - 1
osdep/Phy.hpp

@@ -244,6 +244,12 @@ public:
 	 */
 	static inline ZT_PHY_SOCKFD_TYPE getDescriptor(PhySocket *s) throw() { return reinterpret_cast<PhySocketImpl *>(s)->sock; }
 
+	/**
+	 * @param s Socket object
+	 * @return Pointer to user object
+	 */
+	static inline void** getuptr(PhySocket *s) throw() { return &(reinterpret_cast<PhySocketImpl *>(s)->uptr); }
+
 	/**
 	 * Cause poll() to stop waiting immediately
 	 *
@@ -376,7 +382,10 @@ public:
 			f = 0; setsockopt(s,IPPROTO_IP,IP_MTU_DISCOVER,&f,sizeof(f));
 #endif
 #ifdef SO_NO_CHECK
-			if (_noCheck) {
+			// For now at least we only set SO_NO_CHECK on IPv4 sockets since some
+			// IPv6 stacks incorrectly discard zero checksum packets. May remove
+			// this restriction later once broken stuff dies more.
+			if ((localAddress->sa_family == AF_INET)&&(_noCheck)) {
 				f = 1; setsockopt(s,SOL_SOCKET,SO_NO_CHECK,(void *)&f,sizeof(f));
 			}
 #endif

+ 4 - 0
osdep/PortMapper.cpp

@@ -40,10 +40,14 @@
 #include "OSUtils.hpp"
 #include "PortMapper.hpp"
 
+// These must be defined to get rid of dynamic export stuff in libminiupnpc and libnatpmp
 #ifdef __WINDOWS__
 #ifndef MINIUPNP_STATICLIB
 #define MINIUPNP_STATICLIB
 #endif
+#ifndef STATICLIB
+#define STATICLIB
+#endif
 #endif
 
 #include "../ext/miniupnpc/miniupnpc.h"

+ 17 - 7
service/OneService.cpp

@@ -92,22 +92,32 @@ class SqliteNetworkController;
 #endif
 
 // Include the right tap device driver for this platform -- add new platforms here
+#ifdef ZT_SERVICE_NETCON
+
+// In network containers builds, use the virtual netcon endpoint instead of a tun/tap port driver
+#include "../netcon/NetconEthernetTap.hpp"
+namespace ZeroTier { typedef NetconEthernetTap EthernetTap; }
+
+#else // not ZT_SERVICE_NETCON so pick a tap driver
+
 #ifdef __APPLE__
 #include "../osdep/OSXEthernetTap.hpp"
 namespace ZeroTier { typedef OSXEthernetTap EthernetTap; }
-#endif
+#endif // __APPLE__
 #ifdef __LINUX__
 #include "../osdep/LinuxEthernetTap.hpp"
 namespace ZeroTier { typedef LinuxEthernetTap EthernetTap; }
-#endif
+#endif // __LINUX__
 #ifdef __WINDOWS__
 #include "../osdep/WindowsEthernetTap.hpp"
 namespace ZeroTier { typedef WindowsEthernetTap EthernetTap; }
-#endif
+#endif // __WINDOWS__
 #ifdef __FreeBSD__
 #include "../osdep/BSDEthernetTap.hpp"
 namespace ZeroTier { typedef BSDEthernetTap EthernetTap; }
-#endif
+#endif // __FreeBSD__
+
+#endif // ZT_SERVICE_NETCON
 
 // Sanity limits for HTTP
 #define ZT_MAX_HTTP_MESSAGE_SIZE (1024 * 1024 * 64)
@@ -117,7 +127,7 @@ namespace ZeroTier { typedef BSDEthernetTap EthernetTap; }
 #define ZT_IF_METRIC 32768
 
 // How often to check for new multicast subscriptions on a tap device
-#define ZT_TAP_CHECK_MULTICAST_INTERVAL 30000
+#define ZT_TAP_CHECK_MULTICAST_INTERVAL 5000
 
 // Path under ZT1 home for controller database if controller is enabled
 #define ZT_CONTROLLER_DB_PATH "controller.db"
@@ -595,7 +605,7 @@ public:
 				_v4UpnpLocalAddress = InetAddress(0,mapperPort);
 				_v4UpnpUdpSocket = _phy.udpBind((const struct sockaddr *)&_v4UpnpLocalAddress,reinterpret_cast<void *>(&_v4UpnpLocalAddress),ZT_UDP_DESIRED_BUF_SIZE);
 				if (_v4UpnpUdpSocket) {
-					Utils::snprintf(uniqueName,sizeof(uniqueName),"ZeroTier/%.16llx",_node->address());
+					Utils::snprintf(uniqueName,sizeof(uniqueName),"ZeroTier/%.10llx",_node->address());
 					_portMapper = new PortMapper(mapperPort,uniqueName);
 					break;
 				}
@@ -1116,11 +1126,11 @@ public:
 		}
 	}
 
+	inline void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) {}
 	inline void phyOnUnixAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN) {}
 	inline void phyOnUnixClose(PhySocket *sock,void **uptr) {}
 	inline void phyOnUnixData(PhySocket *sock,void **uptr,void *data,unsigned long len) {}
 	inline void phyOnUnixWritable(PhySocket *sock,void **uptr) {}
-	inline void phyOnFileDescriptorActivity(PhySocket *sock,void **uptr,bool readable,bool writable) {}
 
 	inline int nodeVirtualNetworkConfigFunction(uint64_t nwid,enum ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nwc)
 	{

+ 1 - 1
version.h

@@ -41,6 +41,6 @@
 /**
  * Revision
  */
-#define ZEROTIER_ONE_VERSION_REVISION 0
+#define ZEROTIER_ONE_VERSION_REVISION 2
 
 #endif

+ 12 - 6
windows/ZeroTierOne/ZeroTierOne.vcxproj

@@ -21,6 +21,9 @@
   <ItemGroup>
     <ClCompile Include="..\..\ext\http-parser\http_parser.c" />
     <ClCompile Include="..\..\ext\json-parser\json.c" />
+    <ClCompile Include="..\..\ext\libnatpmp\getgateway.c" />
+    <ClCompile Include="..\..\ext\libnatpmp\natpmp.c" />
+    <ClCompile Include="..\..\ext\libnatpmp\wingettimeofday.c" />
     <ClCompile Include="..\..\ext\lz4\lz4.c" />
     <ClCompile Include="..\..\ext\miniupnpc\connecthostport.c" />
     <ClCompile Include="..\..\ext\miniupnpc\igd_desc_parse.c" />
@@ -64,7 +67,7 @@
     <ClCompile Include="..\..\osdep\BackgroundResolver.cpp" />
     <ClCompile Include="..\..\osdep\Http.cpp" />
     <ClCompile Include="..\..\osdep\OSUtils.cpp" />
-    <ClCompile Include="..\..\osdep\UPNPClient.cpp" />
+    <ClCompile Include="..\..\osdep\PortMapper.cpp" />
     <ClCompile Include="..\..\osdep\WindowsEthernetTap.cpp" />
     <ClCompile Include="..\..\service\ControlPlane.cpp" />
     <ClCompile Include="..\..\service\OneService.cpp" />
@@ -91,6 +94,9 @@
     <ClInclude Include="..\..\ext\bin\miniupnpc\include\miniupnpc\upnpreplyparse.h" />
     <ClInclude Include="..\..\ext\http-parser\http_parser.h" />
     <ClInclude Include="..\..\ext\json-parser\json.h" />
+    <ClInclude Include="..\..\ext\libnatpmp\getgateway.h" />
+    <ClInclude Include="..\..\ext\libnatpmp\natpmp.h" />
+    <ClInclude Include="..\..\ext\libnatpmp\wingettimeofday.h" />
     <ClInclude Include="..\..\ext\lz4\lz4.h" />
     <ClInclude Include="..\..\ext\miniupnpc\codelength.h" />
     <ClInclude Include="..\..\ext\miniupnpc\connecthostport.h" />
@@ -154,8 +160,8 @@
     <ClInclude Include="..\..\osdep\Http.hpp" />
     <ClInclude Include="..\..\osdep\OSUtils.hpp" />
     <ClInclude Include="..\..\osdep\Phy.hpp" />
+    <ClInclude Include="..\..\osdep\PortMapper.hpp" />
     <ClInclude Include="..\..\osdep\Thread.hpp" />
-    <ClInclude Include="..\..\osdep\UPNPClient.hpp" />
     <ClInclude Include="..\..\osdep\WindowsEthernetTap.hpp" />
     <ClInclude Include="..\..\service\ControlPlane.hpp" />
     <ClInclude Include="..\..\service\ControlPlaneSubsystem.hpp" />
@@ -243,7 +249,7 @@
       <SDLCheck>true</SDLCheck>
       <AdditionalIncludeDirectories>
       </AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>NOMINMAX;ZT_TRACE;ZT_USE_MINIUPNPC;MINIUPNP_STATICLIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>NOMINMAX;STATICLIB;WIN32;ZT_TRACE;ZT_USE_MINIUPNPC;MINIUPNP_STATICLIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
     </ClCompile>
     <Link>
       <GenerateDebugInformation>true</GenerateDebugInformation>
@@ -258,7 +264,7 @@
       <SDLCheck>true</SDLCheck>
       <AdditionalIncludeDirectories>
       </AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>NOMINMAX;ZT_TRACE;ZT_USE_MINIUPNPC;MINIUPNP_STATICLIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>NOMINMAX;STATICLIB;WIN32;ZT_TRACE;ZT_USE_MINIUPNPC;MINIUPNP_STATICLIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <MultiProcessorCompilation>false</MultiProcessorCompilation>
     </ClCompile>
     <Link>
@@ -276,7 +282,7 @@
       <SDLCheck>true</SDLCheck>
       <AdditionalIncludeDirectories>
       </AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;ZT_USE_MINIUPNPC;MINIUPNP_STATICLIB;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>STATICLIB;ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;ZT_USE_MINIUPNPC;MINIUPNP_STATICLIB;WIN32;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <EnableEnhancedInstructionSet>NoExtensions</EnableEnhancedInstructionSet>
       <StringPooling>true</StringPooling>
@@ -301,7 +307,7 @@
       <SDLCheck>true</SDLCheck>
       <AdditionalIncludeDirectories>
       </AdditionalIncludeDirectories>
-      <PreprocessorDefinitions>ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;ZT_USE_MINIUPNPC;MINIUPNP_STATICLIB;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      <PreprocessorDefinitions>STATICLIB;ZT_OFFICIAL_RELEASE;ZT_AUTO_UPDATE;ZT_SALSA20_SSE;ZT_USE_MINIUPNPC;MINIUPNP_STATICLIB;WIN32;NOMINMAX;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
       <EnableEnhancedInstructionSet>NotSet</EnableEnhancedInstructionSet>
       <StringPooling>true</StringPooling>

+ 30 - 6
windows/ZeroTierOne/ZeroTierOne.vcxproj.filters

@@ -85,6 +85,12 @@
     <Filter Include="Source Files\ext\miniupnpc">
       <UniqueIdentifier>{56cc3ab8-3336-4a22-9471-c267ee46cd54}</UniqueIdentifier>
     </Filter>
+    <Filter Include="Header Files\ext\libnatpmp">
+      <UniqueIdentifier>{d7292d0d-72a0-4ed6-b717-21debb120737}</UniqueIdentifier>
+    </Filter>
+    <Filter Include="Source Files\ext\libnatpmp">
+      <UniqueIdentifier>{409ec37e-ff36-4c13-b18d-52d6052e0ca2}</UniqueIdentifier>
+    </Filter>
   </ItemGroup>
   <ItemGroup>
     <ClCompile Include="..\..\service\ControlPlane.cpp">
@@ -186,9 +192,6 @@
     <ClCompile Include="..\..\osdep\BackgroundResolver.cpp">
       <Filter>Source Files\osdep</Filter>
     </ClCompile>
-    <ClCompile Include="..\..\osdep\UPNPClient.cpp">
-      <Filter>Source Files\osdep</Filter>
-    </ClCompile>
     <ClCompile Include="..\..\node\Path.cpp">
       <Filter>Source Files\node</Filter>
     </ClCompile>
@@ -237,6 +240,18 @@
     <ClCompile Include="..\..\ext\miniupnpc\upnpreplyparse.c">
       <Filter>Source Files\ext\miniupnpc</Filter>
     </ClCompile>
+    <ClCompile Include="..\..\osdep\PortMapper.cpp">
+      <Filter>Source Files\osdep</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\ext\libnatpmp\getgateway.c">
+      <Filter>Source Files\ext\libnatpmp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\ext\libnatpmp\natpmp.c">
+      <Filter>Source Files\ext\libnatpmp</Filter>
+    </ClCompile>
+    <ClCompile Include="..\..\ext\libnatpmp\wingettimeofday.c">
+      <Filter>Source Files\ext\libnatpmp</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="resource.h">
@@ -401,9 +416,6 @@
     <ClInclude Include="..\..\osdep\BackgroundResolver.hpp">
       <Filter>Header Files\osdep</Filter>
     </ClInclude>
-    <ClInclude Include="..\..\osdep\UPNPClient.hpp">
-      <Filter>Header Files\osdep</Filter>
-    </ClInclude>
     <ClInclude Include="..\..\ext\bin\miniupnpc\include\miniupnpc\codelength.h">
       <Filter>Header Files\ext\bin\miniupnpc\include</Filter>
     </ClInclude>
@@ -515,6 +527,18 @@
     <ClInclude Include="..\..\ext\miniupnpc\upnpreplyparse.h">
       <Filter>Header Files\ext\miniupnpc</Filter>
     </ClInclude>
+    <ClInclude Include="..\..\osdep\PortMapper.hpp">
+      <Filter>Header Files\osdep</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\ext\libnatpmp\getgateway.h">
+      <Filter>Header Files\ext\libnatpmp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\ext\libnatpmp\natpmp.h">
+      <Filter>Header Files\ext\libnatpmp</Filter>
+    </ClInclude>
+    <ClInclude Include="..\..\ext\libnatpmp\wingettimeofday.h">
+      <Filter>Header Files\ext\libnatpmp</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="ZeroTierOne.rc">

BIN
world/earth-2015-12-17.bin


+ 3 - 7
world/mkworld.cpp

@@ -109,7 +109,7 @@ int main(int argc,char **argv)
 	std::vector<World::Root> roots;
 
 	const uint64_t id = ZT_WORLD_ID_EARTH;
-	const uint64_t ts = 1448048819338ULL; // November 20th, 2015 ~11:47AM
+	const uint64_t ts = 1450381818269ULL; // December 17th, 2015
 
 	// Alice
 	roots.push_back(World::Root());
@@ -143,15 +143,11 @@ int main(int argc,char **argv)
 	roots.back().stableEndpoints.push_back(InetAddress("159.203.2.154/9993")); // Toronto
 	roots.back().stableEndpoints.push_back(InetAddress("2604:a880:cad:d0::26:7001/9993")); // Toronto
 
-	// old US-SFO -- we will keep these around for a little while
+	// old US-SFO, which is being kept alive for now
 	roots.push_back(World::Root());
 	roots.back().identity = Identity("7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa");
 	roots.back().stableEndpoints.push_back(InetAddress("198.199.97.220/9993"));
-
-	// old US-NYC -- we will keep these around for a little while
-	roots.push_back(World::Root());
-	roots.back().identity = Identity("8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5");
-	roots.back().stableEndpoints.push_back(InetAddress("162.243.77.111/9993"));
+	roots.back().stableEndpoints.push_back(InetAddress("2604:a880:1:20::c5:f001/9993"));
 
 	// END WORLD DEFINITION
 	// =========================================================================

Some files were not shown because too many files changed in this diff