Browse Source

Fix V4/V6 forwarding issue in root

Adam Ierymenko 6 years ago
parent
commit
2d7a97bb94
1 changed files with 86 additions and 51 deletions
  1. 86 51
      root/root.cpp

+ 86 - 51
root/root.cpp

@@ -1,28 +1,15 @@
 /*
 /*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2019  ZeroTier, Inc.  https://www.zerotier.com/
+ * Copyright (c)2019 ZeroTier, Inc.
  *
  *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
+ * Use of this software is governed by the Business Source License included
+ * in the LICENSE.TXT file in the project's root directory.
  *
  *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
+ * Change Date: 2023-01-01
  *
  *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * You can be released from the requirements of the license by purchasing
- * a commercial license. Buying such a license is mandatory as soon as you
- * develop commercial closed-source software that incorporates or links
- * directly against ZeroTier software without disclosing the source code
- * of your own application.
+ * On the date above, in accordance with the Business Source License, use
+ * of this software will be governed by version 2.0 of the Apache License.
  */
  */
+/****/
 
 
 #include "../node/Constants.hpp"
 #include "../node/Constants.hpp"
 
 
@@ -45,6 +32,8 @@
 #include <netinet/ip6.h>
 #include <netinet/ip6.h>
 #include <netinet/tcp.h>
 #include <netinet/tcp.h>
 
 
+#include "../ext/json/json.hpp"
+
 #include "../node/Packet.hpp"
 #include "../node/Packet.hpp"
 #include "../node/Utils.hpp"
 #include "../node/Utils.hpp"
 #include "../node/Address.hpp"
 #include "../node/Address.hpp"
@@ -68,6 +57,10 @@
 #include <mutex>
 #include <mutex>
 
 
 using namespace ZeroTier;
 using namespace ZeroTier;
+using json = nlohmann::json;
+
+//////////////////////////////////////////////////////////////////////////////
+//////////////////////////////////////////////////////////////////////////////
 
 
 struct IdentityHasher { ZT_ALWAYS_INLINE std::size_t operator()(const Identity &id) const { return (std::size_t)id.hashCode(); } };
 struct IdentityHasher { ZT_ALWAYS_INLINE std::size_t operator()(const Identity &id) const { return (std::size_t)id.hashCode(); } };
 struct AddressHasher { ZT_ALWAYS_INLINE std::size_t operator()(const Address &a) const { return (std::size_t)a.toInt(); } };
 struct AddressHasher { ZT_ALWAYS_INLINE std::size_t operator()(const Address &a) const { return (std::size_t)a.toInt(); } };
@@ -107,6 +100,7 @@ struct RootPeer
 
 
 static Identity self;
 static Identity self;
 static std::atomic_bool run;
 static std::atomic_bool run;
+static json config;
 
 
 static std::unordered_map< uint64_t,std::unordered_map< MulticastGroup,std::unordered_map< Address,int64_t,AddressHasher >,MulticastGroupHasher > > multicastSubscriptions;
 static std::unordered_map< uint64_t,std::unordered_map< MulticastGroup,std::unordered_map< Address,int64_t,AddressHasher >,MulticastGroupHasher > > multicastSubscriptions;
 static std::unordered_map< Identity,SharedPtr<RootPeer>,IdentityHasher > peersByIdentity;
 static std::unordered_map< Identity,SharedPtr<RootPeer>,IdentityHasher > peersByIdentity;
@@ -120,9 +114,10 @@ static std::mutex peersByVirtAddr_l;
 static std::mutex peersByPhysAddr_l;
 static std::mutex peersByPhysAddr_l;
 static std::mutex lastRendezvous_l;
 static std::mutex lastRendezvous_l;
 
 
+//////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
 
-static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
+static void handlePacket(const int v4s,const int v6s,const InetAddress *const ip,Packet &pkt)
 {
 {
 	char ipstr[128],ipstr2[128],astr[32],astr2[32],tmpstr[256];
 	char ipstr[128],ipstr2[128],astr[32],astr2[32],tmpstr[256];
 	const bool fragment = pkt[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR;
 	const bool fragment = pkt[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR;
@@ -191,9 +186,10 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
 			}
 			}
 		}
 		}
 
 
-		// If we found the peer, update IP and/or time.
+		// If we found the peer, update IP and/or time and handle certain key packet types that the
+		// root must concern itself with.
 		if (peer) {
 		if (peer) {
-			InetAddress *const peerIp = (ip->ss_family == AF_INET) ? &(peer->ip4) : &(peer->ip6);
+			InetAddress *const peerIp = ip->isV4() ? &(peer->ip4) : &(peer->ip6);
 			if (*peerIp != ip) {
 			if (*peerIp != ip) {
 				std::lock_guard<std::mutex> pbp_l(peersByPhysAddr_l);
 				std::lock_guard<std::mutex> pbp_l(peersByPhysAddr_l);
 				if (*peerIp) {
 				if (*peerIp) {
@@ -226,7 +222,7 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
 						pkt.append((uint16_t)0);
 						pkt.append((uint16_t)0);
 						ip->serialize(pkt);
 						ip->serialize(pkt);
 						pkt.armor(peer->key,true);
 						pkt.armor(peer->key,true);
-						sendto(sock,pkt.data(),pkt.size(),0,(const struct sockaddr *)ip,(socklen_t)((ip->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)));
+						sendto(ip->isV4() ? v4s : v6s,pkt.data(),pkt.size(),0,(const struct sockaddr *)ip,(socklen_t)((ip->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)));
 						//printf("%s <- OK(HELLO)" ZT_EOL_S,ip->toString(ipstr));
 						//printf("%s <- OK(HELLO)" ZT_EOL_S,ip->toString(ipstr));
 					} catch ( ... ) {
 					} catch ( ... ) {
 						printf("* unexpected exception handling HELLO from %s" ZT_EOL_S,ip->toString(ipstr));
 						printf("* unexpected exception handling HELLO from %s" ZT_EOL_S,ip->toString(ipstr));
@@ -277,7 +273,7 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
 									for(;((l<gatherLimit)&&(g!=forGroup->second.end()));++l,++g)
 									for(;((l<gatherLimit)&&(g!=forGroup->second.end()));++l,++g)
 										g->first.appendTo(pkt);
 										g->first.appendTo(pkt);
 									if (l > 0) {
 									if (l > 0) {
-										sendto(sock,pkt.data(),pkt.size(),0,(const struct sockaddr *)ip,(socklen_t)((ip->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)));
+										sendto(ip->isV4() ? v4s : v6s,pkt.data(),pkt.size(),0,(const struct sockaddr *)ip,(socklen_t)((ip->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)));
 										//printf("%s gathered %u subscribers to %s/%.8lx on network %.16llx" ZT_EOL_S,ip->toString(ipstr),l,mg.mac().toString(tmpstr),(unsigned long)mg.adi(),(unsigned long long)nwid);
 										//printf("%s gathered %u subscribers to %s/%.8lx on network %.16llx" ZT_EOL_S,ip->toString(ipstr),l,mg.mac().toString(tmpstr),(unsigned long)mg.adi(),(unsigned long long)nwid);
 									}
 									}
 								}
 								}
@@ -337,9 +333,10 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
 		if (sources != peersByVirtAddr.end()) {
 		if (sources != peersByVirtAddr.end()) {
 			for(auto a=sources->second.begin();a!=sources->second.end();++a) {
 			for(auto a=sources->second.begin();a!=sources->second.end();++a) {
 				for(auto b=toAddrs.begin();b!=toAddrs.end();++b) {
 				for(auto b=toAddrs.begin();b!=toAddrs.end();++b) {
-					if (((*a)->ip6 == *ip)&&(b->second->ip6)) {
+					if (((*a)->ip6)&&(b->second->ip6)) {
 						//printf("* introducing %s(%s) to %s(%s)" ZT_EOL_S,ip->toString(ipstr),source.toString(astr),b->second->ip6.toString(ipstr2),dest.toString(astr2));
 						//printf("* introducing %s(%s) to %s(%s)" ZT_EOL_S,ip->toString(ipstr),source.toString(astr),b->second->ip6.toString(ipstr2),dest.toString(astr2));
 
 
+						// Introduce source to destination (V6)
 						Packet outp(source,self.address(),Packet::VERB_RENDEZVOUS);
 						Packet outp(source,self.address(),Packet::VERB_RENDEZVOUS);
 						outp.append((uint8_t)0);
 						outp.append((uint8_t)0);
 						dest.appendTo(outp);
 						dest.appendTo(outp);
@@ -347,8 +344,9 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
 						outp.append((uint8_t)16);
 						outp.append((uint8_t)16);
 						outp.append((const uint8_t *)b->second->ip6.rawIpData(),16);
 						outp.append((const uint8_t *)b->second->ip6.rawIpData(),16);
 						outp.armor((*a)->key,true);
 						outp.armor((*a)->key,true);
-						sendto(sock,pkt.data(),pkt.size(),0,(const struct sockaddr *)ip,(socklen_t)sizeof(struct sockaddr_in6));
+						sendto(v6s,pkt.data(),pkt.size(),0,(const struct sockaddr *)&((*a)->ip6),(socklen_t)sizeof(struct sockaddr_in6));
 
 
+						// Introduce destination to source (V6)
 						outp.reset(dest,self.address(),Packet::VERB_RENDEZVOUS);
 						outp.reset(dest,self.address(),Packet::VERB_RENDEZVOUS);
 						outp.append((uint8_t)0);
 						outp.append((uint8_t)0);
 						source.appendTo(outp);
 						source.appendTo(outp);
@@ -356,10 +354,11 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
 						outp.append((uint8_t)16);
 						outp.append((uint8_t)16);
 						outp.append((const uint8_t *)ip->rawIpData(),16);
 						outp.append((const uint8_t *)ip->rawIpData(),16);
 						outp.armor(b->second->key,true);
 						outp.armor(b->second->key,true);
-						sendto(sock,pkt.data(),pkt.size(),0,(const struct sockaddr *)&(b->second->ip6),(socklen_t)sizeof(struct sockaddr_in6));
-					} else if (((*a)->ip4 == *ip)&&(b->second->ip4)) {
+						sendto(v6s,pkt.data(),pkt.size(),0,(const struct sockaddr *)&(b->second->ip6),(socklen_t)sizeof(struct sockaddr_in6));
+					} else if (((*a)->ip4)&&(b->second->ip4)) {
 						//printf("* introducing %s(%s) to %s(%s)" ZT_EOL_S,ip->toString(ipstr),source.toString(astr),b->second->ip4.toString(ipstr2),dest.toString(astr2));
 						//printf("* introducing %s(%s) to %s(%s)" ZT_EOL_S,ip->toString(ipstr),source.toString(astr),b->second->ip4.toString(ipstr2),dest.toString(astr2));
 
 
+						// Introduce source to destination (V4)
 						Packet outp(source,self.address(),Packet::VERB_RENDEZVOUS);
 						Packet outp(source,self.address(),Packet::VERB_RENDEZVOUS);
 						outp.append((uint8_t)0);
 						outp.append((uint8_t)0);
 						dest.appendTo(outp);
 						dest.appendTo(outp);
@@ -367,8 +366,9 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
 						outp.append((uint8_t)4);
 						outp.append((uint8_t)4);
 						outp.append((const uint8_t *)b->second->ip4.rawIpData(),4);
 						outp.append((const uint8_t *)b->second->ip4.rawIpData(),4);
 						outp.armor((*a)->key,true);
 						outp.armor((*a)->key,true);
-						sendto(sock,pkt.data(),pkt.size(),0,(const struct sockaddr *)ip,(socklen_t)sizeof(struct sockaddr_in));
+						sendto(v4s,pkt.data(),pkt.size(),0,(const struct sockaddr *)&((*a)->ip4),(socklen_t)sizeof(struct sockaddr_in));
 
 
+						// Introduce destination to source (V4)
 						outp.reset(dest,self.address(),Packet::VERB_RENDEZVOUS);
 						outp.reset(dest,self.address(),Packet::VERB_RENDEZVOUS);
 						outp.append((uint8_t)0);
 						outp.append((uint8_t)0);
 						source.appendTo(outp);
 						source.appendTo(outp);
@@ -376,7 +376,7 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
 						outp.append((uint8_t)4);
 						outp.append((uint8_t)4);
 						outp.append((const uint8_t *)ip->rawIpData(),4);
 						outp.append((const uint8_t *)ip->rawIpData(),4);
 						outp.armor(b->second->key,true);
 						outp.armor(b->second->key,true);
-						sendto(sock,pkt.data(),pkt.size(),0,(const struct sockaddr *)&(b->second->ip4),(socklen_t)sizeof(struct sockaddr_in));
+						sendto(v4s,pkt.data(),pkt.size(),0,(const struct sockaddr *)&(b->second->ip4),(socklen_t)sizeof(struct sockaddr_in));
 					}
 					}
 				}
 				}
 			}
 			}
@@ -397,10 +397,11 @@ static void handlePacket(const int sock,const InetAddress *const ip,Packet &pkt)
 
 
 	for(auto i=toAddrs.begin();i!=toAddrs.end();++i) {
 	for(auto i=toAddrs.begin();i!=toAddrs.end();++i) {
 		//printf("%s -> %s for %s" ZT_EOL_S,ip->toString(ipstr),i->toString(ipstr2),dest().toString(astr));
 		//printf("%s -> %s for %s" ZT_EOL_S,ip->toString(ipstr),i->toString(ipstr2),dest().toString(astr));
-		sendto(sock,pkt.data(),pkt.size(),0,(const struct sockaddr *)i->first,(socklen_t)((i->first->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)));
+		sendto(i->first->isV4() ? v4s : v6s,pkt.data(),pkt.size(),0,(const struct sockaddr *)i->first,(socklen_t)((i->first->ss_family == AF_INET) ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)));
 	}
 	}
 }
 }
 
 
+//////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 //////////////////////////////////////////////////////////////////////////////
 
 
 static int bindSocket(struct sockaddr *bindAddr)
 static int bindSocket(struct sockaddr *bindAddr)
@@ -448,7 +449,7 @@ static int bindSocket(struct sockaddr *bindAddr)
 	return s;
 	return s;
 }
 }
 
 
-void shutdownSigHandler(int sig) { run = false; }
+static void shutdownSigHandler(int sig) { run = false; }
 
 
 int main(int argc,char **argv)
 int main(int argc,char **argv)
 {
 {
@@ -458,24 +459,58 @@ int main(int argc,char **argv)
 	signal(SIGPIPE,SIG_IGN);
 	signal(SIGPIPE,SIG_IGN);
 	signal(SIGUSR1,SIG_IGN);
 	signal(SIGUSR1,SIG_IGN);
 	signal(SIGUSR2,SIG_IGN);
 	signal(SIGUSR2,SIG_IGN);
+	signal(SIGCHLD,SIG_IGN);
 
 
-	if (argc < 2) {
-		printf("Usage: zerotier-root <identity.secret> [<port>]" ZT_EOL_S);
+	if (argc < 3) {
+		printf("Usage: zerotier-root <identity.secret> <config path>" ZT_EOL_S);
 		return 1;
 		return 1;
 	}
 	}
 
 
-	std::string myIdStr;
-	if (!OSUtils::readFile(argv[1],myIdStr)) {
-		printf("FATAL: cannot read identity.secret at %s" ZT_EOL_S,argv[1]);
-		return 1;
+	{
+		std::string myIdStr;
+		if (!OSUtils::readFile(argv[1],myIdStr)) {
+			printf("FATAL: cannot read identity.secret at %s" ZT_EOL_S,argv[1]);
+			return 1;
+		}
+		if (!self.fromString(myIdStr.c_str())) {
+			printf("FATAL: cannot read identity.secret at %s (invalid identity)" ZT_EOL_S,argv[1]);
+			return 1;
+		}
+		if (!self.hasPrivate()) {
+			printf("FATAL: cannot read identity.secret at %s (missing secret key)" ZT_EOL_S,argv[1]);
+			return 1;
+		}
 	}
 	}
-	if (!self.fromString(myIdStr.c_str())) {
-		printf("FATAL: cannot read identity.secret at %s (invalid identity)" ZT_EOL_S,argv[1]);
-		return 1;
+	{
+		std::string configStr;
+		if (!OSUtils::readFile(argv[2],configStr)) {
+			printf("FATAL: cannot read config file at %s" ZT_EOL_S,argv[2]);
+			return 1;
+		}
+		try {
+			config = json::parse(configStr);
+		} catch (std::exception &exc) {
+			printf("FATAL: config file at %s invalid: %s" ZT_EOL_S,argv[2],exc.what());
+			return 1;
+		} catch ( ... ) {
+			printf("FATAL: config file at %s invalid: unknown exception" ZT_EOL_S,argv[2]);
+			return 1;
+		}
+		if (!config.is_object()) {
+			printf("FATAL: config file at %s invalid: does not contain a JSON object" ZT_EOL_S,argv[2]);
+			return 1;
+		}
 	}
 	}
-	if (!self.hasPrivate()) {
-		printf("FATAL: cannot read identity.secret at %s (missing secret key)" ZT_EOL_S,argv[1]);
-		return 1;
+
+	int port = ZT_DEFAULT_PORT;
+	try {
+		int port = config["port"];
+		if ((port <= 0)||(port > 65535)) {
+			printf("FATAL: invalid port in config file %d" ZT_EOL_S,port);
+			return 1;
+		}
+	} catch ( ... ) {
+		port = ZT_DEFAULT_PORT;
 	}
 	}
 
 
 	unsigned int ncores = std::thread::hardware_concurrency();
 	unsigned int ncores = std::thread::hardware_concurrency();
@@ -490,7 +525,7 @@ int main(int argc,char **argv)
 		struct sockaddr_in6 in6;
 		struct sockaddr_in6 in6;
 		memset(&in6,0,sizeof(in6));
 		memset(&in6,0,sizeof(in6));
 		in6.sin6_family = AF_INET6;
 		in6.sin6_family = AF_INET6;
-		in6.sin6_port = htons(ZT_DEFAULT_PORT);
+		in6.sin6_port = htons((uint16_t)port);
 		const int s6 = bindSocket((struct sockaddr *)&in6);
 		const int s6 = bindSocket((struct sockaddr *)&in6);
 		if (s6 < 0) {
 		if (s6 < 0) {
 			std::cout << "ERROR: unable to bind to port " << ZT_DEFAULT_PORT << ZT_EOL_S;
 			std::cout << "ERROR: unable to bind to port " << ZT_DEFAULT_PORT << ZT_EOL_S;
@@ -500,7 +535,7 @@ int main(int argc,char **argv)
 		struct sockaddr_in in4;
 		struct sockaddr_in in4;
 		memset(&in4,0,sizeof(in4));
 		memset(&in4,0,sizeof(in4));
 		in4.sin_family = AF_INET;
 		in4.sin_family = AF_INET;
-		in4.sin_port = htons(ZT_DEFAULT_PORT);
+		in4.sin_port = htons((uint16_t)port);
 		const int s4 = bindSocket((struct sockaddr *)&in4);
 		const int s4 = bindSocket((struct sockaddr *)&in4);
 		if (s4 < 0) {
 		if (s4 < 0) {
 			std::cout << "ERROR: unable to bind to port " << ZT_DEFAULT_PORT << ZT_EOL_S;
 			std::cout << "ERROR: unable to bind to port " << ZT_DEFAULT_PORT << ZT_EOL_S;
@@ -510,7 +545,7 @@ int main(int argc,char **argv)
 		sockets.push_back(s6);
 		sockets.push_back(s6);
 		sockets.push_back(s4);
 		sockets.push_back(s4);
 
 
-		threads.push_back(std::thread([s6]() {
+		threads.push_back(std::thread([s4,s6]() {
 			struct sockaddr_in6 in6;
 			struct sockaddr_in6 in6;
 			Packet pkt;
 			Packet pkt;
 			memset(&in6,0,sizeof(in6));
 			memset(&in6,0,sizeof(in6));
@@ -521,7 +556,7 @@ int main(int argc,char **argv)
 					if (pl >= ZT_PROTO_MIN_FRAGMENT_LENGTH) {
 					if (pl >= ZT_PROTO_MIN_FRAGMENT_LENGTH) {
 						try {
 						try {
 							pkt.setSize((unsigned int)pl);
 							pkt.setSize((unsigned int)pl);
-							handlePacket(s6,reinterpret_cast<const InetAddress *>(&in6),pkt);
+							handlePacket(s4,s6,reinterpret_cast<const InetAddress *>(&in6),pkt);
 						} catch ( ... ) {
 						} catch ( ... ) {
 							char ipstr[128];
 							char ipstr[128];
 							printf("* unexpected exception handling packet from %s" ZT_EOL_S,reinterpret_cast<const InetAddress *>(&in6)->toString(ipstr));
 							printf("* unexpected exception handling packet from %s" ZT_EOL_S,reinterpret_cast<const InetAddress *>(&in6)->toString(ipstr));
@@ -533,7 +568,7 @@ int main(int argc,char **argv)
 			}
 			}
 		}));
 		}));
 
 
-		threads.push_back(std::thread([s4]() {
+		threads.push_back(std::thread([s4,s6]() {
 			struct sockaddr_in in4;
 			struct sockaddr_in in4;
 			Packet pkt;
 			Packet pkt;
 			memset(&in4,0,sizeof(in4));
 			memset(&in4,0,sizeof(in4));
@@ -544,7 +579,7 @@ int main(int argc,char **argv)
 					if (pl >= ZT_PROTO_MIN_FRAGMENT_LENGTH) {
 					if (pl >= ZT_PROTO_MIN_FRAGMENT_LENGTH) {
 						try {
 						try {
 							pkt.setSize((unsigned int)pl);
 							pkt.setSize((unsigned int)pl);
-							handlePacket(s4,reinterpret_cast<const InetAddress *>(&in4),pkt);
+							handlePacket(s4,s6,reinterpret_cast<const InetAddress *>(&in4),pkt);
 						} catch ( ... ) {
 						} catch ( ... ) {
 							char ipstr[128];
 							char ipstr[128];
 							printf("* unexpected exception handling packet from %s" ZT_EOL_S,reinterpret_cast<const InetAddress *>(&in4)->toString(ipstr));
 							printf("* unexpected exception handling packet from %s" ZT_EOL_S,reinterpret_cast<const InetAddress *>(&in4)->toString(ipstr));