Browse Source

Merge branch 'master' of http://git.int.zerotier.com/ZeroTier/ZeroTierOne

Grant Limberg 9 years ago
parent
commit
2afe3d89d0

+ 19 - 0
debian/changelog

@@ -1,3 +1,22 @@
+zerotier-one (1.1.12) unstable; urgency=medium
+
+  * See https://github.com/zerotier/ZeroTierOne for release notes.
+
+ -- Adam Ierymenko <[email protected]>  Tue, 12 Jul 2016 03:02:22 -0700
+
+zerotier-one (1.1.10) unstable; urgency=medium
+
+  * See https://github.com/zerotier/ZeroTierOne for release notes.
+  * ZeroTier Debian packages no longer depend on http-parser since its ABI is too unstable.
+
+ -- Adam Ierymenko <[email protected]>  Tue, 12 Jul 2016 12:29:00 -0700
+
+zerotier-one (1.1.8) unstable; urgency=low
+
+  * See https://github.com/zerotier/ZeroTierOne for release notes.
+
+ -- Adam Ierymenko <[email protected]>  Fri, 08 Jul 2016 01:56:00 -0700
+
 zerotier-one (1.1.6) unstable; urgency=medium
 zerotier-one (1.1.6) unstable; urgency=medium
 
 
   * First Debian release on ZeroTier, Inc. private apt repository.
   * First Debian release on ZeroTier, Inc. private apt repository.

+ 2 - 2
debian/control

@@ -3,14 +3,14 @@ Maintainer: Adam Ierymenko <[email protected]>
 Section: net
 Section: net
 Priority: optional
 Priority: optional
 Standards-Version: 3.9.6
 Standards-Version: 3.9.6
-Build-Depends: debhelper (>= 9), libhttp-parser-dev (>= 2.1), liblz4-dev, libnatpmp-dev, dh-systemd, ruby-ronn
+Build-Depends: debhelper (>= 9), liblz4-dev, libnatpmp-dev, dh-systemd, ruby-ronn
 Vcs-Git: git://github.com/zerotier/ZeroTierOne
 Vcs-Git: git://github.com/zerotier/ZeroTierOne
 Vcs-Browser: https://github.com/zerotier/ZeroTierOne
 Vcs-Browser: https://github.com/zerotier/ZeroTierOne
 Homepage: https://www.zerotier.com/
 Homepage: https://www.zerotier.com/
 
 
 Package: zerotier-one
 Package: zerotier-one
 Architecture: any
 Architecture: any
-Depends:  ${shlibs:Depends}, ${misc:Depends}, libhttp-parser2.1, liblz4-1, libnatpmp1, iproute2
+Depends:  ${shlibs:Depends}, ${misc:Depends}, liblz4-1, libnatpmp1, iproute2
 Homepage: https://www.zerotier.com/
 Homepage: https://www.zerotier.com/
 Description: ZeroTier network virtualization service
 Description: ZeroTier network virtualization service
  ZeroTier One lets you join ZeroTier virtual networks and
  ZeroTier One lets you join ZeroTier virtual networks and

+ 1 - 1
ext/installfiles/mac/ZeroTier One.pkgproj

@@ -759,7 +759,7 @@
 			<key>OVERWRITE_PERMISSIONS</key>
 			<key>OVERWRITE_PERMISSIONS</key>
 			<false/>
 			<false/>
 			<key>VERSION</key>
 			<key>VERSION</key>
-			<string>1.1.6</string>
+			<string>1.1.12</string>
 		</dict>
 		</dict>
 		<key>PROJECT_COMMENTS</key>
 		<key>PROJECT_COMMENTS</key>
 		<dict>
 		<dict>

+ 33 - 0
include/ZeroTierOne.h

@@ -116,6 +116,11 @@ extern "C" {
  */
  */
 #define ZT_MAX_PEER_NETWORK_PATHS 4
 #define ZT_MAX_PEER_NETWORK_PATHS 4
 
 
+/**
+ * Maximum number of trusted physical network paths
+ */
+#define ZT_MAX_TRUSTED_PATHS 16
+
 /**
 /**
  * Maximum number of hops in a ZeroTier circuit test
  * Maximum number of hops in a ZeroTier circuit test
  *
  *
@@ -887,6 +892,11 @@ typedef struct
 	 */
 	 */
 	uint64_t lastReceive;
 	uint64_t lastReceive;
 
 
+	/**
+	 * Is this a trusted path? If so this will be its nonzero ID.
+	 */
+	uint64_t trustedPathId;
+
 	/**
 	/**
 	 * Is path active?
 	 * Is path active?
 	 */
 	 */
@@ -1837,6 +1847,29 @@ void ZT_Node_clusterHandleIncomingMessage(ZT_Node *node,const void *msg,unsigned
  */
  */
 void ZT_Node_clusterStatus(ZT_Node *node,ZT_ClusterStatus *cs);
 void ZT_Node_clusterStatus(ZT_Node *node,ZT_ClusterStatus *cs);
 
 
+/**
+ * Set trusted paths
+ *
+ * A trusted path is a physical network (network/bits) over which both
+ * encryption and authentication can be skipped to improve performance.
+ * Each trusted path must have a non-zero unique ID that is the same across
+ * all participating nodes.
+ *
+ * We don't recommend using trusted paths at all unless you really *need*
+ * near-bare-metal performance. Even on a LAN authentication and encryption
+ * are never a bad thing, and anything that introduces an "escape hatch"
+ * for encryption should be treated with the utmost care.
+ *
+ * Calling with NULL pointers for networks and ids and a count of zero clears
+ * all trusted paths.
+ *
+ * @param node Node instance
+ * @param networks Array of [count] networks
+ * @param ids Array of [count] corresponding non-zero path IDs (zero path IDs are ignored)
+ * @param count Number of trusted paths-- values greater than ZT_MAX_TRUSTED_PATHS are clipped
+ */
+void ZT_Node_setTrustedPaths(ZT_Node *node,const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count);
+
 /**
 /**
  * Do things in the background until Node dies
  * Do things in the background until Node dies
  *
  *

+ 2 - 0
linux-build-farm/debian-jessie/x64/Dockerfile

@@ -7,4 +7,6 @@ RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev l
 RUN ln -sf /usr/bin/clang++-3.5 /usr/bin/clang++
 RUN ln -sf /usr/bin/clang++-3.5 /usr/bin/clang++
 RUN ln -sf /usr/bin/clang-3.5 /usr/bin/clang
 RUN ln -sf /usr/bin/clang-3.5 /usr/bin/clang
 
 
+RUN dpkg --purge libhttp-parser-dev
+
 ADD zt1-src.tar.gz /
 ADD zt1-src.tar.gz /

+ 2 - 0
linux-build-farm/debian-jessie/x86/Dockerfile

@@ -7,4 +7,6 @@ RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev l
 RUN ln -sf /usr/bin/clang++-3.5 /usr/bin/clang++
 RUN ln -sf /usr/bin/clang++-3.5 /usr/bin/clang++
 RUN ln -sf /usr/bin/clang-3.5 /usr/bin/clang
 RUN ln -sf /usr/bin/clang-3.5 /usr/bin/clang
 
 
+RUN dpkg --purge libhttp-parser-dev
+
 ADD zt1-src.tar.gz /
 ADD zt1-src.tar.gz /

+ 2 - 0
linux-build-farm/debian-stretch/x64/Dockerfile

@@ -7,4 +7,6 @@ RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev l
 #RUN ln -sf /usr/bin/clang++-3.5 /usr/bin/clang++
 #RUN ln -sf /usr/bin/clang++-3.5 /usr/bin/clang++
 #RUN ln -sf /usr/bin/clang-3.5 /usr/bin/clang
 #RUN ln -sf /usr/bin/clang-3.5 /usr/bin/clang
 
 
+RUN dpkg --purge libhttp-parser-dev
+
 ADD zt1-src.tar.gz /
 ADD zt1-src.tar.gz /

+ 2 - 0
linux-build-farm/debian-stretch/x86/Dockerfile

@@ -7,4 +7,6 @@ RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev l
 #RUN ln -sf /usr/bin/clang++-3.5 /usr/bin/clang++
 #RUN ln -sf /usr/bin/clang++-3.5 /usr/bin/clang++
 #RUN ln -sf /usr/bin/clang-3.5 /usr/bin/clang
 #RUN ln -sf /usr/bin/clang-3.5 /usr/bin/clang
 
 
+RUN dpkg --purge libhttp-parser-dev
+
 ADD zt1-src.tar.gz /
 ADD zt1-src.tar.gz /

+ 2 - 0
linux-build-farm/debian-wheezy/x64/Dockerfile

@@ -4,6 +4,8 @@ MAINTAINER Adam Ierymenko <[email protected]>
 RUN apt-get update
 RUN apt-get update
 RUN apt-get install -y build-essential debhelper ruby-ronn g++ make devscripts
 RUN apt-get install -y build-essential debhelper ruby-ronn g++ make devscripts
 
 
+RUN dpkg --purge libhttp-parser-dev
+
 ADD zt1-src.tar.gz /
 ADD zt1-src.tar.gz /
 
 
 RUN mv -f /ZeroTierOne/debian/control.wheezy /ZeroTierOne/debian/control
 RUN mv -f /ZeroTierOne/debian/control.wheezy /ZeroTierOne/debian/control

+ 2 - 0
linux-build-farm/debian-wheezy/x86/Dockerfile

@@ -7,6 +7,8 @@
 FROM zerotier/zt1-build-debian-wheezy-x86-base
 FROM zerotier/zt1-build-debian-wheezy-x86-base
 MAINTAINER Adam Ierymenko <[email protected]>
 MAINTAINER Adam Ierymenko <[email protected]>
 
 
+RUN dpkg --purge libhttp-parser-dev
+
 ADD zt1-src.tar.gz /
 ADD zt1-src.tar.gz /
 
 
 RUN mv -f /ZeroTierOne/debian/control.wheezy /ZeroTierOne/debian/control
 RUN mv -f /ZeroTierOne/debian/control.wheezy /ZeroTierOne/debian/control

+ 1 - 0
linux-build-farm/fedora-22/x64/Dockerfile

@@ -5,5 +5,6 @@ RUN yum update -y
 RUN yum install -y make rpmdevtools gcc-c++ rubygem-ronn json-parser-devel lz4-devel http-parser-devel libnatpmp-devel
 RUN yum install -y make rpmdevtools gcc-c++ rubygem-ronn json-parser-devel lz4-devel http-parser-devel libnatpmp-devel
 
 
 RUN rpm --erase http-parser-devel
 RUN rpm --erase http-parser-devel
+RUN yum install -y rubygem-ronn ruby
 
 
 ADD zt1-src.tar.gz /
 ADD zt1-src.tar.gz /

+ 1 - 0
linux-build-farm/fedora-22/x86/Dockerfile

@@ -14,5 +14,6 @@ MAINTAINER Adam Ierymenko <[email protected]>
 RUN echo 'i686-redhat-linux' >/etc/rpm/platform
 RUN echo 'i686-redhat-linux' >/etc/rpm/platform
 
 
 RUN rpm --erase http-parser-devel
 RUN rpm --erase http-parser-devel
+RUN yum install -y rubygem-ronn ruby
 
 
 ADD zt1-src.tar.gz /
 ADD zt1-src.tar.gz /

+ 29 - 0
linux-build-farm/make-rpm-repos.sh

@@ -31,5 +31,34 @@ for db in `find /tmp/zt-rpm-repo -mindepth 2 -maxdepth 2 -type d`; do
 	createrepo --database $db
 	createrepo --database $db
 done
 done
 
 
+# Stupid RHEL stuff
+cd /tmp/zt-rpm-repo/el
+ln -sf 6 6Client
+ln -sf 6 6Workstation
+ln -sf 6 6Server
+ln -sf 6 6.0
+ln -sf 6 6.1
+ln -sf 6 6.2
+ln -sf 6 6.3
+ln -sf 6 6.4
+ln -sf 6 6.5
+ln -sf 6 6.6
+ln -sf 6 6.7
+ln -sf 6 6.8
+ln -sf 6 6.9
+ln -sf 7 7Client
+ln -sf 7 7Workstation
+ln -sf 7 7Server
+ln -sf 7 7.0
+ln -sf 7 7.1
+ln -sf 7 7.2
+ln -sf 7 7.3
+ln -sf 7 7.4
+ln -sf 7 7.5
+ln -sf 7 7.6
+ln -sf 7 7.7
+ln -sf 7 7.8
+ln -sf 7 7.9
+
 echo
 echo
 echo Repo created in /tmp/zt-rpm-repo
 echo Repo created in /tmp/zt-rpm-repo

+ 2 - 0
linux-build-farm/ubuntu-trusty/x64/Dockerfile

@@ -7,4 +7,6 @@ RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev l
 RUN ln -sf /usr/bin/clang++-3.6 /usr/bin/clang++
 RUN ln -sf /usr/bin/clang++-3.6 /usr/bin/clang++
 RUN ln -sf /usr/bin/clang-3.6 /usr/bin/clang
 RUN ln -sf /usr/bin/clang-3.6 /usr/bin/clang
 
 
+RUN dpkg --purge libhttp-parser-dev
+
 ADD zt1-src.tar.gz /
 ADD zt1-src.tar.gz /

+ 2 - 0
linux-build-farm/ubuntu-trusty/x86/Dockerfile

@@ -7,4 +7,6 @@ RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev l
 RUN ln -sf /usr/bin/clang++-3.6 /usr/bin/clang++
 RUN ln -sf /usr/bin/clang++-3.6 /usr/bin/clang++
 RUN ln -sf /usr/bin/clang-3.6 /usr/bin/clang
 RUN ln -sf /usr/bin/clang-3.6 /usr/bin/clang
 
 
+RUN dpkg --purge libhttp-parser-dev
+
 ADD zt1-src.tar.gz /
 ADD zt1-src.tar.gz /

+ 2 - 0
linux-build-farm/ubuntu-wily/x64/Dockerfile

@@ -7,4 +7,6 @@ RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev l
 RUN ln -sf /usr/bin/clang++-3.7 /usr/bin/clang++
 RUN ln -sf /usr/bin/clang++-3.7 /usr/bin/clang++
 RUN ln -sf /usr/bin/clang-3.7 /usr/bin/clang
 RUN ln -sf /usr/bin/clang-3.7 /usr/bin/clang
 
 
+RUN dpkg --purge libhttp-parser-dev
+
 ADD zt1-src.tar.gz /
 ADD zt1-src.tar.gz /

+ 2 - 0
linux-build-farm/ubuntu-wily/x86/Dockerfile

@@ -7,4 +7,6 @@ RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev l
 RUN ln -sf /usr/bin/clang++-3.7 /usr/bin/clang++
 RUN ln -sf /usr/bin/clang++-3.7 /usr/bin/clang++
 RUN ln -sf /usr/bin/clang-3.7 /usr/bin/clang
 RUN ln -sf /usr/bin/clang-3.7 /usr/bin/clang
 
 
+RUN dpkg --purge libhttp-parser-dev
+
 ADD zt1-src.tar.gz /
 ADD zt1-src.tar.gz /

+ 2 - 0
linux-build-farm/ubuntu-xenial/x64/Dockerfile

@@ -9,4 +9,6 @@ RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev l
 
 
 RUN rm -f /usr/bin/clang++ /usr/bin/clang
 RUN rm -f /usr/bin/clang++ /usr/bin/clang
 
 
+RUN dpkg --purge libhttp-parser-dev
+
 ADD zt1-src.tar.gz /
 ADD zt1-src.tar.gz /

+ 2 - 0
linux-build-farm/ubuntu-xenial/x86/Dockerfile

@@ -9,4 +9,6 @@ RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev l
 
 
 RUN rm -f /usr/bin/clang++ /usr/bin/clang
 RUN rm -f /usr/bin/clang++ /usr/bin/clang
 
 
+RUN dpkg --purge libhttp-parser-dev
+
 ADD zt1-src.tar.gz /
 ADD zt1-src.tar.gz /

+ 24 - 6
node/IncomingPacket.cpp

@@ -42,9 +42,24 @@ namespace ZeroTier {
 
 
 bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,bool deferred)
 bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,bool deferred)
 {
 {
-	const Address sourceAddress(source());
 	try {
 	try {
-		if ((cipher() == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) {
+		const Address sourceAddress(source());
+
+		// Check for trusted paths or unencrypted HELLOs (HELLO is the only packet sent in the clear)
+		const unsigned int c = cipher();
+		bool trusted = false;
+		if (c == ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH) {
+			// If this is marked as a packet via a trusted path, check source address and path ID.
+			// Obviously if no trusted paths are configured this always returns false and such
+			// packets are dropped on the floor.
+			if (RR->topology->shouldInboundPathBeTrusted(_remoteAddress,trustedPathId())) {
+				trusted = true;
+				TRACE("TRUSTED PATH packet approved from %s(%s), trusted path ID %llx",sourceAddress.toString().c_str(),_remoteAddress.toString().c_str(),trustedPathId());
+			} else {
+				TRACE("dropped packet from %s(%s), cipher set to trusted path mode but path %llx@%s is not trusted!",sourceAddress.toString().c_str(),_remoteAddress.toString().c_str(),trustedPathId(),_remoteAddress.toString().c_str());
+				return true;
+			}
+		} else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) {
 			// Unencrypted HELLOs require some potentially expensive verification, so
 			// Unencrypted HELLOs require some potentially expensive verification, so
 			// do this in the background if background processing is enabled.
 			// do this in the background if background processing is enabled.
 			if ((RR->dpEnabled > 0)&&(!deferred)) {
 			if ((RR->dpEnabled > 0)&&(!deferred)) {
@@ -61,12 +76,15 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,bool deferred)
 
 
 		SharedPtr<Peer> peer(RR->topology->getPeer(sourceAddress));
 		SharedPtr<Peer> peer(RR->topology->getPeer(sourceAddress));
 		if (peer) {
 		if (peer) {
-			if (!dearmor(peer->key())) {
-				TRACE("dropped packet from %s(%s), MAC authentication failed (size: %u)",peer->address().toString().c_str(),_remoteAddress.toString().c_str(),size());
-				return true;
+			if (!trusted) {
+				if (!dearmor(peer->key())) {
+					TRACE("dropped packet from %s(%s), MAC authentication failed (size: %u)",sourceAddress.toString().c_str(),_remoteAddress.toString().c_str(),size());
+					return true;
+				}
 			}
 			}
+
 			if (!uncompress()) {
 			if (!uncompress()) {
-				TRACE("dropped packet from %s(%s), compressed data invalid",peer->address().toString().c_str(),_remoteAddress.toString().c_str());
+				TRACE("dropped packet from %s(%s), compressed data invalid",sourceAddress.toString().c_str(),_remoteAddress.toString().c_str());
 				return true;
 				return true;
 			}
 			}
 
 

+ 13 - 0
node/Node.cpp

@@ -447,6 +447,7 @@ ZT_PeerList *Node::peers() const
 			p->paths[p->pathCount].lastReceive = path->lastReceived();
 			p->paths[p->pathCount].lastReceive = path->lastReceived();
 			p->paths[p->pathCount].active = path->active(_now) ? 1 : 0;
 			p->paths[p->pathCount].active = path->active(_now) ? 1 : 0;
 			p->paths[p->pathCount].preferred = ((bestPath)&&(*path == *bestPath)) ? 1 : 0;
 			p->paths[p->pathCount].preferred = ((bestPath)&&(*path == *bestPath)) ? 1 : 0;
+			p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust(path->address());
 			++p->pathCount;
 			++p->pathCount;
 		}
 		}
 	}
 	}
@@ -745,6 +746,11 @@ void Node::postCircuitTestReport(const ZT_CircuitTestReport *report)
 		(reinterpret_cast<void (*)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)>((*i)->_internalPtr))(reinterpret_cast<ZT_Node *>(this),*i,report);
 		(reinterpret_cast<void (*)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)>((*i)->_internalPtr))(reinterpret_cast<ZT_Node *>(this),*i,report);
 }
 }
 
 
+void Node::setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count)
+{
+	RR->topology->setTrustedPaths(reinterpret_cast<const InetAddress *>(networks),ids,count);
+}
+
 } // namespace ZeroTier
 } // namespace ZeroTier
 
 
 /****************************************************************************/
 /****************************************************************************/
@@ -1014,6 +1020,13 @@ void ZT_Node_clusterStatus(ZT_Node *node,ZT_ClusterStatus *cs)
 	} catch ( ... ) {}
 	} catch ( ... ) {}
 }
 }
 
 
+void ZT_Node_setTrustedPaths(ZT_Node *node,const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count)
+{
+	try {
+		reinterpret_cast<ZeroTier::Node *>(node)->setTrustedPaths(networks,ids,count);
+	} catch ( ... ) {}
+}
+
 void ZT_Node_backgroundThreadMain(ZT_Node *node)
 void ZT_Node_backgroundThreadMain(ZT_Node *node)
 {
 {
 	try {
 	try {

+ 1 - 12
node/Node.hpp

@@ -248,26 +248,15 @@ public:
 	 */
 	 */
 	inline int configureVirtualNetworkPort(uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _virtualNetworkConfigFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,nwid,nuptr,op,nc); }
 	inline int configureVirtualNetworkPort(uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { return _virtualNetworkConfigFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,nwid,nuptr,op,nc); }
 
 
-	/**
-	 * @return True if we appear to be online
-	 */
 	inline bool online() const throw() { return _online; }
 	inline bool online() const throw() { return _online; }
 
 
 #ifdef ZT_TRACE
 #ifdef ZT_TRACE
 	void postTrace(const char *module,unsigned int line,const char *fmt,...);
 	void postTrace(const char *module,unsigned int line,const char *fmt,...);
 #endif
 #endif
 
 
-	/**
-	 * @return Next 64-bit random number (not for cryptographic use)
-	 */
 	uint64_t prng();
 	uint64_t prng();
-
-	/**
-	 * Post a circuit test report to any listeners for a given test ID
-	 *
-	 * @param report Report (includes test ID)
-	 */
 	void postCircuitTestReport(const ZT_CircuitTestReport *report);
 	void postCircuitTestReport(const ZT_CircuitTestReport *report);
+	void setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count);
 
 
 private:
 private:
 	inline SharedPtr<Network> _network(uint64_t nwid) const
 	inline SharedPtr<Network> _network(uint64_t nwid) const

+ 42 - 8
node/Packet.hpp

@@ -57,11 +57,13 @@
  *   + Supports in-band world (root server definition) updates
  *   + Supports in-band world (root server definition) updates
  *   + Clustering! (Though this will work with protocol v4 clients.)
  *   + Clustering! (Though this will work with protocol v4 clients.)
  *   + Otherwise backward compatible with protocol v4
  *   + Otherwise backward compatible with protocol v4
- * 6 - 1.1.5 ... CURRENT
+ * 6 - 1.1.5 ... 1.1.10
  *   + Deprecate old dictionary-based network config format
  *   + Deprecate old dictionary-based network config format
  *   + Introduce new binary serialized network config and meta-data
  *   + Introduce new binary serialized network config and meta-data
+ * 7 - 1.1.10 -- CURRENT
+ *   + Introduce trusted paths for local SDN use
  */
  */
-#define ZT_PROTO_VERSION 6
+#define ZT_PROTO_VERSION 7
 
 
 /**
 /**
  * Minimum supported protocol version
  * Minimum supported protocol version
@@ -100,10 +102,21 @@
 #define ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 1
 #define ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 1
 
 
 /**
 /**
- * DEPRECATED payload encrypted flag, will be removed for re-use soon.
+ * Cipher suite: NONE
  *
  *
- * This has been replaced by the three-bit cipher suite selection field where
- * a value of 0 indicates unencrypted (but authenticated) messages.
+ * This differs from POLY1305/NONE in that *no* crypto is done, not even
+ * authentication. This is for trusted local LAN interconnects for internal
+ * SDN use within a data center.
+ *
+ * For this mode the MAC field becomes a trusted path ID and must match the
+ * configured ID of a trusted path or the packet is discarded.
+ */
+#define ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH 2
+
+/**
+ * DEPRECATED payload encrypted flag, may be re-used in the future.
+ *
+ * This has been replaced by the three-bit cipher suite selection field.
  */
  */
 #define ZT_PROTO_FLAG_ENCRYPTED 0x80
 #define ZT_PROTO_FLAG_ENCRYPTED 0x80
 
 
@@ -337,7 +350,7 @@ namespace ZeroTier {
  *   <[5] destination ZT address>
  *   <[5] destination ZT address>
  *   <[5] source ZT address>
  *   <[5] source ZT address>
  *   <[1] flags/cipher/hops>
  *   <[1] flags/cipher/hops>
- *   <[8] 64-bit MAC>
+ *   <[8] 64-bit MAC (or trusted path ID in trusted path mode)>
  *   [... -- begin encryption envelope -- ...]
  *   [... -- begin encryption envelope -- ...]
  *   <[1] encrypted flags (MS 3 bits) and verb (LS 5 bits)>
  *   <[1] encrypted flags (MS 3 bits) and verb (LS 5 bits)>
  *   [... verb-specific payload ...]
  *   [... verb-specific payload ...]
@@ -1218,7 +1231,6 @@ public:
 	 */
 	 */
 	inline unsigned int cipher() const
 	inline unsigned int cipher() const
 	{
 	{
-		// Note: this uses the new cipher spec field, which is incompatible with <1.0.0 peers
 		return (((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x38) >> 3);
 		return (((unsigned int)(*this)[ZT_PACKET_IDX_FLAGS] & 0x38) >> 3);
 	}
 	}
 
 
@@ -1229,12 +1241,30 @@ public:
 	{
 	{
 		unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS];
 		unsigned char &b = (*this)[ZT_PACKET_IDX_FLAGS];
 		b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH
 		b = (b & 0xc7) | (unsigned char)((c << 3) & 0x38); // bits: FFCCCHHH
-		// DEPRECATED "encrypted" flag -- used by pre-1.0.3 peers
+		// Set DEPRECATED "encrypted" flag -- used by pre-1.0.3 peers
 		if (c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)
 		if (c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)
 			b |= ZT_PROTO_FLAG_ENCRYPTED;
 			b |= ZT_PROTO_FLAG_ENCRYPTED;
 		else b &= (~ZT_PROTO_FLAG_ENCRYPTED);
 		else b &= (~ZT_PROTO_FLAG_ENCRYPTED);
 	}
 	}
 
 
+	/**
+	 * Get the trusted path ID for this packet (only meaningful if cipher is trusted path)
+	 *
+	 * @return Trusted path ID (from MAC field)
+	 */
+	inline uint64_t trustedPathId() const { return at<uint64_t>(ZT_PACKET_IDX_MAC); }
+
+	/**
+	 * Set this packet's trusted path ID and set the cipher spec to trusted path
+	 *
+	 * @param tpid Trusted path ID
+	 */
+	inline void setTrusted(const uint64_t tpid)
+	{
+		setCipher(ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH);
+		setAt(ZT_PACKET_IDX_MAC,tpid);
+	}
+
 	/**
 	/**
 	 * Get this packet's unique ID (the IV field interpreted as uint64_t)
 	 * Get this packet's unique ID (the IV field interpreted as uint64_t)
 	 *
 	 *
@@ -1278,6 +1308,10 @@ public:
 	/**
 	/**
 	 * Verify and (if encrypted) decrypt packet
 	 * Verify and (if encrypted) decrypt packet
 	 *
 	 *
+	 * This does not handle trusted path mode packets and will return false
+	 * for these. These are handled in IncomingPacket if the sending physical
+	 * address and MAC field match a trusted path.
+	 *
 	 * @param key 32-byte key
 	 * @param key 32-byte key
 	 * @return False if packet is invalid or failed MAC authenticity check
 	 * @return False if packet is invalid or failed MAC authenticity check
 	 */
 	 */

+ 6 - 1
node/Switch.cpp

@@ -849,7 +849,12 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid)
 		unsigned int chunkSize = std::min(tmp.size(),(unsigned int)ZT_UDP_DEFAULT_PAYLOAD_MTU);
 		unsigned int chunkSize = std::min(tmp.size(),(unsigned int)ZT_UDP_DEFAULT_PAYLOAD_MTU);
 		tmp.setFragmented(chunkSize < tmp.size());
 		tmp.setFragmented(chunkSize < tmp.size());
 
 
-		tmp.armor(peer->key(),encrypt);
+		const uint64_t trustedPathId = RR->topology->getOutboundPathTrust(viaPath->address());
+		if (trustedPathId) {
+			tmp.setTrusted(trustedPathId);
+		} else {
+			tmp.armor(peer->key(),encrypt);
+		}
 
 
 		if (viaPath->send(RR,tmp.data(),chunkSize,now)) {
 		if (viaPath->send(RR,tmp.data(),chunkSize,now)) {
 			if (chunkSize < tmp.size()) {
 			if (chunkSize < tmp.size()) {

+ 53 - 0
node/Topology.hpp

@@ -28,6 +28,7 @@
 #include <utility>
 #include <utility>
 
 
 #include "Constants.hpp"
 #include "Constants.hpp"
+#include "../include/ZeroTierOne.h"
 
 
 #include "Address.hpp"
 #include "Address.hpp"
 #include "Identity.hpp"
 #include "Identity.hpp"
@@ -252,12 +253,64 @@ public:
 	 */
 	 */
 	inline bool amRoot() const throw() { return _amRoot; }
 	inline bool amRoot() const throw() { return _amRoot; }
 
 
+	/**
+	 * Get the outbound trusted path ID for a physical address, or 0 if none
+	 *
+	 * @param physicalAddress Physical address to which we are sending the packet
+	 * @return Trusted path ID or 0 if none (0 is not a valid trusted path ID)
+	 */
+	inline uint64_t getOutboundPathTrust(const InetAddress &physicalAddress)
+	{
+		for(unsigned int i=0;i<_trustedPathCount;++i) {
+			if (_trustedPathNetworks[i].containsAddress(physicalAddress))
+				return _trustedPathIds[i];
+		}
+		return 0;
+	}
+
+	/**
+	 * Check whether in incoming trusted path marked packet is valid
+	 *
+	 * @param physicalAddress Originating physical address
+	 * @param trustedPathId Trusted path ID from packet (from MAC field)
+	 */
+	inline bool shouldInboundPathBeTrusted(const InetAddress &physicalAddress,const uint64_t trustedPathId)
+	{
+		for(unsigned int i=0;i<_trustedPathCount;++i) {
+			if ((_trustedPathIds[i] == trustedPathId)&&(_trustedPathNetworks[i].containsAddress(physicalAddress)))
+				return true;
+		}
+		return false;
+	}
+
+	/**
+	 * Set trusted paths in this topology
+	 *
+	 * @param networks Array of networks (prefix/netmask bits)
+	 * @param ids Array of trusted path IDs
+	 * @param count Number of trusted paths (if larger than ZT_MAX_TRUSTED_PATHS overflow is ignored)
+	 */
+	inline void setTrustedPaths(const InetAddress *networks,const uint64_t *ids,unsigned int count)
+	{
+		if (count > ZT_MAX_TRUSTED_PATHS)
+			count = ZT_MAX_TRUSTED_PATHS;
+		Mutex::Lock _l(_lock);
+		for(unsigned int i=0;i<count;++i) {
+			_trustedPathIds[i] = ids[i];
+			_trustedPathNetworks[i] = networks[i];
+		}
+		_trustedPathCount = count;
+	}
+
 private:
 private:
 	Identity _getIdentity(const Address &zta);
 	Identity _getIdentity(const Address &zta);
 	void _setWorld(const World &newWorld);
 	void _setWorld(const World &newWorld);
 
 
 	const RuntimeEnvironment *const RR;
 	const RuntimeEnvironment *const RR;
 
 
+	uint64_t _trustedPathIds[ZT_MAX_TRUSTED_PATHS];
+	InetAddress _trustedPathNetworks[ZT_MAX_TRUSTED_PATHS];
+	unsigned int _trustedPathCount;
 	World _world;
 	World _world;
 	Hashtable< Address,SharedPtr<Peer> > _peers;
 	Hashtable< Address,SharedPtr<Peer> > _peers;
 	std::vector< Address > _rootAddresses;
 	std::vector< Address > _rootAddresses;

+ 3 - 1
osdep/ManagedRoute.cpp

@@ -57,6 +57,8 @@
 #define ZT_LINUX_IP_COMMAND "/sbin/ip"
 #define ZT_LINUX_IP_COMMAND "/sbin/ip"
 #define ZT_LINUX_IP_COMMAND_2 "/usr/sbin/ip"
 #define ZT_LINUX_IP_COMMAND_2 "/usr/sbin/ip"
 
 
+// NOTE: BSD is mostly tested on Apple/Mac but is likely to work on other BSD too
+
 namespace ZeroTier {
 namespace ZeroTier {
 
 
 namespace {
 namespace {
@@ -413,7 +415,7 @@ bool ManagedRoute::sync()
 		// Shadow system route if it exists, also delete any obsolete shadows
 		// Shadow system route if it exists, also delete any obsolete shadows
 		// and replace them with the new state. sync() is called periodically to
 		// and replace them with the new state. sync() is called periodically to
 		// allow us to do that if underlying connectivity changes.
 		// allow us to do that if underlying connectivity changes.
-		if ((_systemVia != newSystemVia)||(!strcmp(_systemDevice,newSystemDevice))) {
+		if ( ((_systemVia != newSystemVia)||(strcmp(_systemDevice,newSystemDevice))) && (strcmp(_device,newSystemDevice)) ) {
 			if ((_systemVia)&&(_systemDevice[0])) {
 			if ((_systemVia)&&(_systemDevice[0])) {
 				_routeCmd("delete",leftt,_systemVia,_systemDevice,(const char *)0);
 				_routeCmd("delete",leftt,_systemVia,_systemDevice,(const char *)0);
 				_routeCmd("delete",rightt,_systemVia,_systemDevice,(const char *)0);
 				_routeCmd("delete",rightt,_systemVia,_systemDevice,(const char *)0);

+ 2 - 2
osdep/ManagedRoute.hpp

@@ -54,8 +54,8 @@ public:
 	 * "device name."
 	 * "device name."
 	 *
 	 *
 	 * @param target Route target (e.g. 0.0.0.0/0 for default)
 	 * @param target Route target (e.g. 0.0.0.0/0 for default)
-	 * @param via Route next L3 hop or NULL InetAddress if local
-	 * @param device Device name/ID if 'via' is null and route is local, otherwise ignored
+	 * @param via Route next L3 hop or NULL InetAddress if local in which case it will be routed via device
+	 * @param device Name or hex LUID of ZeroTier device (e.g. zt#)
 	 * @return True if route was successfully set
 	 * @return True if route was successfully set
 	 */
 	 */
 	inline bool set(const InetAddress &target,const InetAddress &via,const char *device)
 	inline bool set(const InetAddress &target,const InetAddress &via,const char *device)

+ 2 - 2
osdep/OSXEthernetTap.cpp

@@ -474,7 +474,7 @@ bool OSXEthernetTap::addIp(const InetAddress &ip)
 
 
 	long cpid = (long)vfork();
 	long cpid = (long)vfork();
 	if (cpid == 0) {
 	if (cpid == 0) {
-		::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),ip.isV4() ? "inet" : "inet6",ip.toString().c_str(),"alias",(const char *)0);
+		::execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),(ip.ss_family == AF_INET6) ? "inet6" : "inet",ip.toString().c_str(),"alias",(const char *)0);
 		::_exit(-1);
 		::_exit(-1);
 	} else if (cpid > 0) {
 	} else if (cpid > 0) {
 		int exitcode = -1;
 		int exitcode = -1;
@@ -494,7 +494,7 @@ bool OSXEthernetTap::removeIp(const InetAddress &ip)
 		if (*i == ip) {
 		if (*i == ip) {
 			long cpid = (long)vfork();
 			long cpid = (long)vfork();
 			if (cpid == 0) {
 			if (cpid == 0) {
-				execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"inet",ip.toIpString().c_str(),"-alias",(const char *)0);
+				execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),(ip.ss_family == AF_INET6) ? "inet6" : "inet",ip.toIpString().c_str(),"-alias",(const char *)0);
 				_exit(-1);
 				_exit(-1);
 			} else if (cpid > 0) {
 			} else if (cpid > 0) {
 				int exitcode = -1;
 				int exitcode = -1;

+ 3 - 1
service/ControlPlane.cpp

@@ -190,13 +190,15 @@ static std::string _jsonEnumerate(unsigned int depth,const ZT_PeerPhysicalPath *
 			"%s\t\"lastSend\": %llu,\n"
 			"%s\t\"lastSend\": %llu,\n"
 			"%s\t\"lastReceive\": %llu,\n"
 			"%s\t\"lastReceive\": %llu,\n"
 			"%s\t\"active\": %s,\n"
 			"%s\t\"active\": %s,\n"
-			"%s\t\"preferred\": %s\n"
+			"%s\t\"preferred\": %s,\n"
+			"%s\t\"trustedPathId\": %llu\n"
 			"%s}",
 			"%s}",
 			prefix,_jsonEscape(reinterpret_cast<const InetAddress *>(&(pp[i].address))->toString()).c_str(),
 			prefix,_jsonEscape(reinterpret_cast<const InetAddress *>(&(pp[i].address))->toString()).c_str(),
 			prefix,pp[i].lastSend,
 			prefix,pp[i].lastSend,
 			prefix,pp[i].lastReceive,
 			prefix,pp[i].lastReceive,
 			prefix,(pp[i].active == 0) ? "false" : "true",
 			prefix,(pp[i].active == 0) ? "false" : "true",
 			prefix,(pp[i].preferred == 0) ? "false" : "true",
 			prefix,(pp[i].preferred == 0) ? "false" : "true",
+			prefix,pp[i].trustedPathId,
 			prefix);
 			prefix);
 		buf.append(json);
 		buf.append(json);
 	}
 	}

+ 55 - 11
service/OneService.cpp

@@ -759,6 +759,38 @@ public:
 			for(int i=0;i<3;++i)
 			for(int i=0;i<3;++i)
 				_portsBE[i] = Utils::hton((uint16_t)_ports[i]);
 				_portsBE[i] = Utils::hton((uint16_t)_ports[i]);
 
 
+			{
+				FILE *trustpaths = fopen((_homePath + ZT_PATH_SEPARATOR_S + "trustedpaths").c_str(),"r");
+				uint64_t ids[ZT_MAX_TRUSTED_PATHS];
+				InetAddress addresses[ZT_MAX_TRUSTED_PATHS];
+				if (trustpaths) {
+					char buf[1024];
+					unsigned int count = 0;
+					while ((fgets(buf,sizeof(buf),trustpaths))&&(count < ZT_MAX_TRUSTED_PATHS)) {
+						int fno = 0;
+						char *saveptr = (char *)0;
+						uint64_t trustedPathId = 0;
+						InetAddress trustedPathNetwork;
+						for(char *f=Utils::stok(buf,"=\r\n \t",&saveptr);(f);f=Utils::stok((char *)0,"=\r\n \t",&saveptr)) {
+							if (fno == 0) {
+								trustedPathId = Utils::hexStrToU64(f);
+							} else if (fno == 1) {
+								trustedPathNetwork = InetAddress(f);
+							} else break;
+							++fno;
+						}
+						if ( (trustedPathId != 0) && ((trustedPathNetwork.ss_family == AF_INET)||(trustedPathNetwork.ss_family == AF_INET6)) && (trustedPathNetwork.ipScope() != InetAddress::IP_SCOPE_GLOBAL) && (trustedPathNetwork.netmaskBits() > 0) ) {
+							ids[count] = trustedPathId;
+							addresses[count] = trustedPathNetwork;
+							++count;
+						}
+					}
+					fclose(trustpaths);
+					if (count)
+						_node->setTrustedPaths(reinterpret_cast<const struct sockaddr_storage *>(addresses),ids,count);
+				}
+			}
+
 #ifdef ZT_ENABLE_NETWORK_CONTROLLER
 #ifdef ZT_ENABLE_NETWORK_CONTROLLER
 			_controller = new SqliteNetworkController(_node,(_homePath + ZT_PATH_SEPARATOR_S + ZT_CONTROLLER_DB_PATH).c_str(),(_homePath + ZT_PATH_SEPARATOR_S + "circuitTestResults.d").c_str());
 			_controller = new SqliteNetworkController(_node,(_homePath + ZT_PATH_SEPARATOR_S + ZT_CONTROLLER_DB_PATH).c_str(),(_homePath + ZT_PATH_SEPARATOR_S + "circuitTestResults.d").c_str());
 			_node->setNetconfMaster((void *)_controller);
 			_node->setNetconfMaster((void *)_controller);
@@ -1041,13 +1073,13 @@ public:
 	// Begin private implementation methods
 	// Begin private implementation methods
 
 
 	// Checks if a managed IP or route target is allowed
 	// Checks if a managed IP or route target is allowed
-	bool checkIfManagedIsAllowed(const NetworkState &n,const InetAddress &addr)
+	bool checkIfManagedIsAllowed(const NetworkState &n,const InetAddress &target)
 	{
 	{
 		if (!n.settings.allowManaged)
 		if (!n.settings.allowManaged)
 			return false;
 			return false;
-		if (addr.isDefaultRoute())
+		if (target.isDefaultRoute())
 			return n.settings.allowDefault;
 			return n.settings.allowDefault;
-		switch(addr.ipScope()) {
+		switch(target.ipScope()) {
 			case InetAddress::IP_SCOPE_NONE:
 			case InetAddress::IP_SCOPE_NONE:
 			case InetAddress::IP_SCOPE_MULTICAST:
 			case InetAddress::IP_SCOPE_MULTICAST:
 			case InetAddress::IP_SCOPE_LOOPBACK:
 			case InetAddress::IP_SCOPE_LOOPBACK:
@@ -1060,6 +1092,16 @@ public:
 		}
 		}
 	}
 	}
 
 
+	// Match only an IP from a vector of IPs -- used in syncManagedStuff()
+	bool matchIpOnly(const std::vector<InetAddress> &ips,const InetAddress &ip) const
+	{
+		for(std::vector<InetAddress>::const_iterator i(ips.begin());i!=ips.end();++i) {
+			if (i->ipsEqual(ip))
+				return true;
+		}
+		return false;
+	}
+
 	// Apply or update managed IPs for a configured network (be sure n.tap exists)
 	// Apply or update managed IPs for a configured network (be sure n.tap exists)
 	void syncManagedStuff(NetworkState &n,bool syncIps,bool syncRoutes)
 	void syncManagedStuff(NetworkState &n,bool syncIps,bool syncRoutes)
 	{
 	{
@@ -1075,18 +1117,18 @@ public:
 			std::sort(newManagedIps.begin(),newManagedIps.end());
 			std::sort(newManagedIps.begin(),newManagedIps.end());
 			newManagedIps.erase(std::unique(newManagedIps.begin(),newManagedIps.end()),newManagedIps.end());
 			newManagedIps.erase(std::unique(newManagedIps.begin(),newManagedIps.end()),newManagedIps.end());
 
 
-			for(std::vector<InetAddress>::iterator ip(newManagedIps.begin());ip!=newManagedIps.end();++ip) {
-				if (std::find(n.managedIps.begin(),n.managedIps.end(),*ip) == n.managedIps.end()) {
-					if (!n.tap->addIp(*ip))
-						fprintf(stderr,"ERROR: unable to add ip address %s"ZT_EOL_S, ip->toString().c_str());
-				}
-			}
 			for(std::vector<InetAddress>::iterator ip(n.managedIps.begin());ip!=n.managedIps.end();++ip) {
 			for(std::vector<InetAddress>::iterator ip(n.managedIps.begin());ip!=n.managedIps.end();++ip) {
 				if (std::find(newManagedIps.begin(),newManagedIps.end(),*ip) == newManagedIps.end()) {
 				if (std::find(newManagedIps.begin(),newManagedIps.end(),*ip) == newManagedIps.end()) {
 					if (!n.tap->removeIp(*ip))
 					if (!n.tap->removeIp(*ip))
 						fprintf(stderr,"ERROR: unable to remove ip address %s"ZT_EOL_S, ip->toString().c_str());
 						fprintf(stderr,"ERROR: unable to remove ip address %s"ZT_EOL_S, ip->toString().c_str());
 				}
 				}
 			}
 			}
+			for(std::vector<InetAddress>::iterator ip(newManagedIps.begin());ip!=newManagedIps.end();++ip) {
+				if (std::find(n.managedIps.begin(),n.managedIps.end(),*ip) == n.managedIps.end()) {
+					if (!n.tap->addIp(*ip))
+						fprintf(stderr,"ERROR: unable to add ip address %s"ZT_EOL_S, ip->toString().c_str());
+				}
+			}
 
 
 			n.managedIps.swap(newManagedIps);
 			n.managedIps.swap(newManagedIps);
 		}
 		}
@@ -1099,10 +1141,12 @@ public:
 			Utils::scopy(tapdev,sizeof(tapdev),n.tap->deviceName().c_str());
 			Utils::scopy(tapdev,sizeof(tapdev),n.tap->deviceName().c_str());
 #endif
 #endif
 
 
+			std::vector<InetAddress> myIps(n.tap->ips());
+
 			// Nuke applied routes that are no longer in n.config.routes[] and/or are not allowed
 			// Nuke applied routes that are no longer in n.config.routes[] and/or are not allowed
 			for(std::list<ManagedRoute>::iterator mr(n.managedRoutes.begin());mr!=n.managedRoutes.end();) {
 			for(std::list<ManagedRoute>::iterator mr(n.managedRoutes.begin());mr!=n.managedRoutes.end();) {
 				bool haveRoute = false;
 				bool haveRoute = false;
-				if (checkIfManagedIsAllowed(n,mr->target())) {
+				if ( (checkIfManagedIsAllowed(n,mr->target())) && ((mr->via().ss_family != mr->target().ss_family)||(!matchIpOnly(myIps,mr->via()))) ) {
 					for(unsigned int i=0;i<n.config.routeCount;++i) {
 					for(unsigned int i=0;i<n.config.routeCount;++i) {
 						const InetAddress *const target = reinterpret_cast<const InetAddress *>(&(n.config.routes[i].target));
 						const InetAddress *const target = reinterpret_cast<const InetAddress *>(&(n.config.routes[i].target));
 						const InetAddress *const via = reinterpret_cast<const InetAddress *>(&(n.config.routes[i].via));
 						const InetAddress *const via = reinterpret_cast<const InetAddress *>(&(n.config.routes[i].via));
@@ -1124,7 +1168,7 @@ public:
 				const InetAddress *const target = reinterpret_cast<const InetAddress *>(&(n.config.routes[i].target));
 				const InetAddress *const target = reinterpret_cast<const InetAddress *>(&(n.config.routes[i].target));
 				const InetAddress *const via = reinterpret_cast<const InetAddress *>(&(n.config.routes[i].via));
 				const InetAddress *const via = reinterpret_cast<const InetAddress *>(&(n.config.routes[i].via));
 
 
-				if (!checkIfManagedIsAllowed(n,*target))
+				if ( (!checkIfManagedIsAllowed(n,*target)) || ((via->ss_family == target->ss_family)&&(matchIpOnly(myIps,*via))) )
 					continue;
 					continue;
 
 
 				bool haveRoute = false;
 				bool haveRoute = false;

+ 1 - 1
version.h

@@ -32,6 +32,6 @@
 /**
 /**
  * Revision
  * Revision
  */
  */
-#define ZEROTIER_ONE_VERSION_REVISION 8
+#define ZEROTIER_ONE_VERSION_REVISION 12
 
 
 #endif
 #endif

+ 7 - 1
zerotier-one.spec

@@ -1,5 +1,5 @@
 Name:           zerotier-one
 Name:           zerotier-one
-Version:        1.1.6
+Version:        1.1.12
 Release:        0.1%{?dist}
 Release:        0.1%{?dist}
 Summary:        ZeroTier One network virtualization service
 Summary:        ZeroTier One network virtualization service
 
 
@@ -149,6 +149,12 @@ esac
 %endif
 %endif
 
 
 %changelog
 %changelog
+* Tue Jul 12 2016 Adam Ierymenko <[email protected]> - 1.1.10-0.1
+- see https://github.com/zerotier/ZeroTierOne for release notes
+
+* Fri Jul 08 2016 Adam Ierymenko <[email protected]> - 1.1.8-0.1
+- see https://github.com/zerotier/ZeroTierOne for release notes
+
 * Sat Jun 25 2016 Adam Ierymenko <[email protected]> - 1.1.6-0.1
 * Sat Jun 25 2016 Adam Ierymenko <[email protected]> - 1.1.6-0.1
 - now builds on CentOS 6 as well as newer distros, and some cleanup
 - now builds on CentOS 6 as well as newer distros, and some cleanup