Преглед изворни кода

Whole heap more cleanup and refactoring...

Adam Ierymenko пре 10 година
родитељ
комит
36eab4f1a9
14 измењених фајлова са 561 додато и 756 уклоњено
  1. 0 0
      attic/Socket.hpp
  2. 0 0
      attic/SocketManager.hpp
  3. 43 23
      include/ZeroTierOne.h
  4. 9 31
      node/Constants.hpp
  5. 113 207
      node/InetAddress.cpp
  6. 129 141
      node/InetAddress.hpp
  7. 7 0
      node/MAC.hpp
  8. 30 0
      node/Node.cpp
  9. 206 0
      node/Node.hpp
  10. 0 137
      node/NodeConfig.cpp
  11. 0 181
      node/NodeConfig.hpp
  12. 2 35
      node/RuntimeEnvironment.hpp
  13. 0 1
      objects.mk
  14. 22 0
      osdep/SoftwareUpdater.hpp

+ 0 - 0
node/Socket.hpp → attic/Socket.hpp


+ 0 - 0
node/SocketManager.hpp → attic/SocketManager.hpp


+ 43 - 23
include/ZeroTierOne.h

@@ -35,21 +35,33 @@
 
 #include <stdint.h>
 
-#ifndef ZT_SOCKADDR_STORAGE
 #if defined(_WIN32) || defined(_WIN64)
 #include <WinSock2.h>
 #include <WS2tcpip.h>
 #include <Windows.h>
 #else /* not Windows */
+#include <arpa/inet.h>
 #include <netinet/in.h>
 #endif /* Windows or not */
-#define ZT_SOCKADDR_STORAGE struct sockaddr_storage
-#endif /* !ZT_SOCKADDR_STORAGE */
 
 #ifdef __cplusplus
 extern "C" {
 #endif
 
+/****************************************************************************/
+/* Core constants                                                           */
+/****************************************************************************/
+
+/**
+ * Maximum frame MTU
+ */
+#define ZT1_MAX_MTU 2800
+
+/**
+ * Maximum length of a wire message packet in bytes
+ */
+#define ZT1_MAX_WIRE_MESSAGE_LENGTH 1500
+
 /****************************************************************************/
 /* Structures and other types                                               */
 /****************************************************************************/
@@ -149,9 +161,9 @@ typedef struct
 typedef struct
 {
 	/**
-	 * Remote socket address
+	 * Socket address
 	 */
-	ZT_SOCKADDR_STORAGE remoteAddress;
+	struct sockaddr_storage address;
 
 	/**
 	 * Link desperation -- higher equals "worse" or "slower"
@@ -191,7 +203,7 @@ typedef struct
 	/**
 	 * Packet data
 	 */
-	const void *packetData;
+	const char packetData[ZT1_MAX_WIRE_MESSAGE_LENGTH];
 
 	/**
 	 * Length of packet
@@ -207,7 +219,7 @@ typedef struct
 	/**
 	 * ZeroTier network ID of virtual LAN port
 	 */
-	uint64_t networkId;
+	uint64_t nwid;
 
 	/**
 	 * Source MAC address
@@ -232,7 +244,7 @@ typedef struct
 	/**
 	 * Ethernet frame data
 	 */
-	const void *frameData;
+	const char frameData[ZT1_MAX_MTU];
 
 	/**
 	 * Ethernet frame length
@@ -290,7 +302,7 @@ typedef struct
 	/**
 	 * 64-bit ZeroTier network ID
 	 */
-	uint64_t networkId;
+	uint64_t nwid;
 
 	/**
 	 * Ethernet MAC (40 bits) that should be assigned to port
@@ -346,7 +358,7 @@ typedef struct
 	 * This is only used for ZeroTier-managed address assignments sent by the
 	 * virtual network's configuration master.
 	 */
-	const ZT_SOCKADDR_STORAGE *assignedAddresses;
+	const struct sockaddr_storage *assignedAddresses;
 
 	/**
 	 * Number of assigned addresses
@@ -376,7 +388,7 @@ typedef struct
 	/**
 	 * Address of endpoint
 	 */
-	ZT_SOCKADDR_STORAGE address;
+	struct sockaddr_storage address;
 
 	/**
 	 * Time since last send in milliseconds or -1 for never
@@ -466,7 +478,7 @@ typedef struct
 	/**
 	 * Array of network paths to peer
 	 */
-	struct ZT1_PeerPhysicalPath *paths;
+	ZT1_PeerPhysicalPath *paths;
 
 	/**
 	 * Number of paths (size of paths[])
@@ -561,7 +573,7 @@ typedef int (*ZT1_DataStorePutFunction)(ZT1_Node *,const char *,const void *,uns
  * @param node Result: pointer is set to new node instance on success
  * @param dataStoreGetFunction Function called to get objects from persistent storage
  * @param dataStorePutFunction Function called to put objects in persistent storage
- * @param portConfigCallback Function to be called when virtual LANs are created, deleted, or their config parameters change
+ * @param networkConfigCallback Function to be called when virtual LANs are created, deleted, or their config parameters change
  * @param statusCallback Function to receive status updates and non-fatal error notices
  * @return OK (0) or error code if a fatal error condition has occurred
  */
@@ -569,7 +581,7 @@ enum ZT1_ResultCode ZT1_Node_new(
 	ZT1_Node **node,
 	ZT1_DataStoreGetFunction *dataStoreGetFunction,
 	ZT1_DataStorePutFunction *dataStorePutFunction,
-	ZT1_VirtualPortConfigCallback *portConfigCallback,
+	ZT1_VirtualNetworkConfigCallback *networkConfigCallback,
 	ZT1_StatusCallback *statusCallback);
 
 /**
@@ -609,11 +621,11 @@ enum ZT1_ResultCode ZT1_Node_run(
 	uint64_t now,
 	const ZT1_WireMessage *inputWireMessages,
 	unsigned int inputWireMessageCount,
-	const ZT1_VirtualLanFrame *inputLanFrames,
-	unsigned int inputLanFrameCount,
+	const ZT1_VirtualNetworkFrame *inputFrames,
+	unsigned int inputFrameCount,
 	const ZT1_WireMessage **outputWireMessages,
 	unsigned int *outputWireMessageCount,
-	const ZT1_VirtualLanFrame **outputLanFrames,
+	const ZT1_VirtualNetworkFrame **outputFrames,
 	unsigned int *outputLanFrameCount,
 	unsigned long *maxNextInterval);
 
@@ -624,10 +636,10 @@ enum ZT1_ResultCode ZT1_Node_run(
  * or these may be deffered if a netconf is not available yet.
  *
  * @param node Node instance
- * @param networkId 64-bit ZeroTIer network ID
+ * @param nwid 64-bit ZeroTIer network ID
  * @return OK (0) or error code if a fatal error condition has occurred
  */
-enum ZT1_ResultCode ZT1_Node_join(ZT1_Node *node,uint64_t networkId);
+enum ZT1_ResultCode ZT1_Node_join(ZT1_Node *node,uint64_t nwid);
 
 /**
  * Leave a network
@@ -637,19 +649,18 @@ enum ZT1_ResultCode ZT1_Node_join(ZT1_Node *node,uint64_t networkId);
  * the port is now deleted.
  *
  * @param node Node instance
- * @param networkId 64-bit network ID
+ * @param nwid 64-bit network ID
  * @return OK (0) or error code if a fatal error condition has occurred
  */
-enum ZT1_ResultCode ZT1_Node_leave(ZT1_Node *node,uint64_t networkId);
+enum ZT1_ResultCode ZT1_Node_leave(ZT1_Node *node,uint64_t nwid);
 
 /**
  * Get the status of this node
  *
  * @param node Node instance
  * @param status Buffer to fill with current node status
- * @return OK (0) or error code if a fatal error condition has occurred
  */
-enum ZT1_ResultCode ZT1_Node_status(ZT1_Node *node,ZT1_NodeStatus *status);
+void ZT1_Node_status(ZT1_Node *node,ZT1_NodeStatus *status);
 
 /**
  * Get a list of known peer nodes
@@ -710,6 +721,15 @@ enum ZT1_ResultCode ZT1_Node_setNetconfMaster(
 	ZT1_Node *node,
 	void *networkConfigMasterInstance);
 
+/**
+ * Get ZeroTier One version
+ *
+ * @param major Result: major version
+ * @param minor Result: minor version
+ * @param revision Result: revision
+ */
+void ZT1_version(int *major,int *minor,int *revision);
+
 #ifdef __cplusplus
 }
 #endif

+ 9 - 31
node/Constants.hpp

@@ -300,14 +300,19 @@
 #define ZT_STARTUP_AGGRO (ZT_PING_UNANSWERED_AFTER * 2)
 
 /**
- * Maximum delay between runs of the main loop in Node.cpp
+ * How long since last message from an authoritative upstream peer before we increment our desperation level?
  */
-#define ZT_MAX_SERVICE_LOOP_INTERVAL ZT_STARTUP_AGGRO
+#define ZT_DESPERATION_INCREMENT (ZT_STARTUP_AGGRO * 2)
+
+/**
+ * "Spam" packets to lower desperation links every Nth packet
+ */
+#define ZT_DESPERATION_SPAM_EVERY 10
 
 /**
- * Try TCP tunnels if nothing received for this long
+ * Maximum delay between runs of the main loop in Node.cpp
  */
-#define ZT_TCP_TUNNEL_FAILOVER_TIMEOUT (ZT_STARTUP_AGGRO * 5)
+#define ZT_MAX_SERVICE_LOOP_INTERVAL ZT_STARTUP_AGGRO
 
 /**
  * Timeout for overall peer activity (measured from last receive)
@@ -319,11 +324,6 @@
  */
 #define ZT_PEER_PATH_ACTIVITY_TIMEOUT ZT_PEER_ACTIVITY_TIMEOUT
 
-/**
- * Close TCP sockets if unused for this long (SocketManager)
- */
-#define ZT_TCP_TUNNEL_ACTIVITY_TIMEOUT ZT_PEER_ACTIVITY_TIMEOUT
-
 /**
  * Stop relaying via peers that have not responded to direct sends
  *
@@ -374,28 +374,6 @@
  */
 #define ZT_MIN_BEACON_RESPONSE_INTERVAL (ZT_BEACON_INTERVAL / 32)
 
-/**
- * Minimum interval between attempts to do a software update
- */
-#define ZT_UPDATE_MIN_INTERVAL 120000
-
-/**
- * Maximum interval between checks for new versions
- */
-#define ZT_UPDATE_MAX_INTERVAL 7200000
-
-/**
- * Software update HTTP timeout in seconds
- */
-#define ZT_UPDATE_HTTP_TIMEOUT 120
-
-/**
- * Delay between fetches of the root topology update URL
- *
- * 86400000 = check once every 24 hours (this doesn't change often)
- */
-#define ZT_UPDATE_ROOT_TOPOLOGY_CHECK_INTERVAL 86400000
-
 /**
  * Sanity limit on maximum bridge routes
  *

+ 113 - 207
node/InetAddress.cpp

@@ -45,24 +45,29 @@ const InetAddress InetAddress::DEFAULT6((const void *)0,16,0);
 void InetAddress::set(const std::string &ip,unsigned int port)
 	throw()
 {
-	memset(&_sa,0,sizeof(_sa));
 	if (ip.find(':') != std::string::npos) {
-		_sa.sin6.sin6_family = AF_INET6;
-		_sa.sin6.sin6_port = Utils::hton((uint16_t)port);
-		if (inet_pton(AF_INET6,ip.c_str(),(void *)&(_sa.sin6.sin6_addr.s6_addr)) <= 0)
-			_sa.saddr.sa_family = 0;
+		struct sockaddr_in6 sin6;
+		memset(&sin6,0,sizeof(sin6));
+		sin6.sin6_family = AF_INET6;
+		sin6.sin6_port = Utils::hton((uint16_t)port);
+		if (inet_pton(AF_INET6,ip.c_str(),(void *)&(sin6.sin6_addr.s6_addr)) <= 0)
+			memset(this,0,sizeof(InetAddress));
+		else *this = sin6;
 	} else {
-		_sa.sin.sin_family = AF_INET;
-		_sa.sin.sin_port = Utils::hton((uint16_t)port);
-			if (inet_pton(AF_INET,ip.c_str(),(void *)&(_sa.sin.sin_addr.s_addr)) <= 0)
-			_sa.saddr.sa_family = 0;
+		struct sockaddr_in sin;
+		memset(&sin,0,sizeof(sin));
+		sin.sin_family = AF_INET;
+		sin.sin_port = Utils::hton((uint16_t)port);
+		if (inet_pton(AF_INET,ip.c_str(),(void *)&(sin.sin_addr.s_addr)) <= 0)
+			memset(this,0,sizeof(InetAddress));
+		else *this = sin;
 	}
 }
 
 void InetAddress::set(const void *ipBytes,unsigned int ipLen,unsigned int port)
 	throw()
 {
-	memset(&_sa,0,sizeof(_sa));
+	memset(this,0,sizeof(InetAddress));
 	if (ipLen == 4) {
 		setV4();
 		if (ipBytes)
@@ -79,59 +84,87 @@ void InetAddress::set(const void *ipBytes,unsigned int ipLen,unsigned int port)
 bool InetAddress::isLinkLocal() const
 	throw()
 {
-	if (_sa.saddr.sa_family == AF_INET)
-		return ((Utils::ntoh((uint32_t)_sa.sin.sin_addr.s_addr) & 0xffff0000) == 0xa9fe0000);
-	else if (_sa.saddr.sa_family == AF_INET6) {
-		if (_sa.sin6.sin6_addr.s6_addr[0] != 0xfe) return false;
-		if (_sa.sin6.sin6_addr.s6_addr[1] != 0x80) return false;
-		if (_sa.sin6.sin6_addr.s6_addr[2] != 0x00) return false;
-		if (_sa.sin6.sin6_addr.s6_addr[3] != 0x00) return false;
-		if (_sa.sin6.sin6_addr.s6_addr[4] != 0x00) return false;
-		if (_sa.sin6.sin6_addr.s6_addr[5] != 0x00) return false;
-		if (_sa.sin6.sin6_addr.s6_addr[6] != 0x00) return false;
-		if (_sa.sin6.sin6_addr.s6_addr[7] != 0x00) return false;
-		return true;
+	static const unsigned char v6llPrefix[8] = { 0xfe,0x80,0x00,0x00,0x00,0x00,0x00,0x00 };
+	switch(ss_family) {
+		case AF_INET:
+			return ((Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr) & 0xffff0000) == 0xa9fe0000);
+		case AF_INET6:
+			return (memcmp(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,v6llPrefix,8) == 0);
 	}
 	return false;
 }
 
-bool InetAddress::isDefaultRoute() const
-	throw()
+std::string InetAddress::toString() const
 {
-	if (_sa.saddr.sa_family == AF_INET)
-		return ((_sa.sin.sin_addr.s_addr == 0)&&(_sa.sin.sin_port == 0));
-	else if (_sa.saddr.sa_family == AF_INET6)
-		return ((Utils::isZero(_sa.sin6.sin6_addr.s6_addr,16))&&(_sa.sin6.sin6_port == 0));
-	return false;
+	char buf[128];
+	switch(ss_family) {
+		case AF_INET:
+			Utils::snprintf(buf,sizeof(buf),"%d.%d.%d.%d/%d",
+					(int)(reinterpret_cast<const unsigned char *>(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr)))[0],
+					(int)(reinterpret_cast<const unsigned char *>(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr)))[1],
+					(int)(reinterpret_cast<const unsigned char *>(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr)))[2],
+					(int)(reinterpret_cast<const unsigned char *>(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr)))[3],
+					(int)Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in *>(this)->sin_port))
+				);
+			return std::string(buf);
+		case AF_INET6:
+			Utils::snprintf(buf,sizeof(buf),"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%d",
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[0]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[1]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[2]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[3]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[4]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[5]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[6]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[7]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[8]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[9]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[10]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[11]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[12]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[13]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[14]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[15]),
+					(int)Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port))
+				);
+			return std::string(buf);
+	}
+	return std::string();
 }
 
-std::string InetAddress::toString() const
+std::string InetAddress::toIpString() const
 {
-	char buf[128],buf2[128];
-
-	switch(_sa.saddr.sa_family) {
+	char buf[128];
+	switch(ss_family) {
 		case AF_INET:
-#ifdef __WINDOWS__
-			if (inet_ntop(AF_INET,(PVOID)&(_sa.sin.sin_addr.s_addr),buf,sizeof(buf))) {
-#else
-			if (inet_ntop(AF_INET,(const void *)&(_sa.sin.sin_addr.s_addr),buf,sizeof(buf))) {
-#endif
-				Utils::snprintf(buf2,sizeof(buf2),"%s/%u",buf,(unsigned int)ntohs(_sa.sin.sin_port));
-				return std::string(buf2);
-			}
-			break;
+			Utils::snprintf(buf,sizeof(buf),"%d.%d.%d.%d",
+					(int)(reinterpret_cast<const unsigned char *>(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr)))[0],
+					(int)(reinterpret_cast<const unsigned char *>(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr)))[1],
+					(int)(reinterpret_cast<const unsigned char *>(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr)))[2],
+					(int)(reinterpret_cast<const unsigned char *>(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr)))[3]
+				);
+			return std::string(buf);
 		case AF_INET6:
-#ifdef __WINDOWS__
-			if (inet_ntop(AF_INET6,(PVOID)&(_sa.sin6.sin6_addr.s6_addr),buf,sizeof(buf))) {
-#else
-			if (inet_ntop(AF_INET6,(const void *)&(_sa.sin6.sin6_addr.s6_addr),buf,sizeof(buf))) {
-#endif
-				Utils::snprintf(buf2,sizeof(buf2),"%s/%u",buf,(unsigned int)ntohs(_sa.sin6.sin6_port));
-				return std::string(buf2);
-			}
-			break;
+			Utils::snprintf(buf,sizeof(buf),"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x",
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[0]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[1]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[2]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[3]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[4]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[5]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[6]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[7]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[8]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[9]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[10]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[11]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[12]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[13]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[14]),
+					(int)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr[15])
+				);
+			return std::string(buf);
 	}
-
 	return std::string();
 }
 
@@ -148,48 +181,22 @@ void InetAddress::fromString(const std::string &ipSlashPort)
 	}
 }
 
-std::string InetAddress::toIpString() const
-{
-	char buf[128];
-	switch(_sa.saddr.sa_family) {
-		case AF_INET:
-#ifdef __WINDOWS__
-			if (inet_ntop(AF_INET,(PVOID)&(_sa.sin.sin_addr.s_addr),buf,sizeof(buf)))
-				return std::string(buf);
-#else
-			if (inet_ntop(AF_INET,(const void *)&(_sa.sin.sin_addr.s_addr),buf,sizeof(buf)))
-				return std::string(buf);
-#endif
-			break;
-		case AF_INET6:
-#ifdef __WINDOWS__
-			if (inet_ntop(AF_INET6,(PVOID)&(_sa.sin6.sin6_addr.s6_addr),buf,sizeof(buf)))
-				return std::string(buf);
-#else
-			if (inet_ntop(AF_INET6,(const void *)&(_sa.sin6.sin6_addr.s6_addr),buf,sizeof(buf)))
-				return std::string(buf);
-#endif
-			break;
-	}
-	return std::string();
-}
-
 InetAddress InetAddress::netmask() const
 	throw()
 {
 	InetAddress r(*this);
-	switch(_sa.saddr.sa_family) {
+	switch(r.ss_family) {
 		case AF_INET:
-			r._sa.sin.sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
+			reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffff << (32 - netmaskBits())));
 			break;
 		case AF_INET6: {
-			unsigned char *bf = (unsigned char *)r._sa.sin6.sin6_addr.s6_addr;
+			unsigned char *bf = reinterpret_cast<unsigned char *>(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr);
 			signed int bitsLeft = (signed int)netmaskBits();
 			for(unsigned int i=0;i<16;++i) {
 				if (bitsLeft > 0) {
-					bf[i] = (unsigned char)((bitsLeft >= 8) ? 0xff : (0xff << (8 - bitsLeft)));
+					bf[i] |= (unsigned char)((bitsLeft >= 8) ? 0x00 : (0xff >> bitsLeft));
 					bitsLeft -= 8;
-				} else bf[i] = (unsigned char)0;
+				}
 			}
 		}	break;
 	}
@@ -200,12 +207,12 @@ InetAddress InetAddress::broadcast() const
 	throw()
 {
 	InetAddress r(*this);
-	switch(_sa.saddr.sa_family) {
+	switch(r.ss_family) {
 		case AF_INET:
-			r._sa.sin.sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffff >> netmaskBits()));
+			reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffff >> netmaskBits()));
 			break;
 		case AF_INET6: {
-			unsigned char *bf = (unsigned char *)r._sa.sin6.sin6_addr.s6_addr;
+			unsigned char *bf = reinterpret_cast<unsigned char *>(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr);
 			signed int bitsLeft = (signed int)netmaskBits();
 			for(unsigned int i=0;i<16;++i) {
 				if (bitsLeft > 0) {
@@ -218,130 +225,29 @@ InetAddress InetAddress::broadcast() const
 	return r;
 }
 
-bool InetAddress::sameNetworkAs(const InetAddress &ipnet) const
-	throw()
-{
-	if (_sa.saddr.sa_family != ipnet._sa.saddr.sa_family)
-		return false;
-
-	unsigned int bits = netmaskBits();
-	if (bits != ipnet.netmaskBits())
-		return false;
-	if (!bits)
-		return true;
-	switch(_sa.saddr.sa_family) {
-		case AF_INET:
-			if (bits >= 32) bits = 32;
-			break;
-		case AF_INET6:
-			if (bits >= 128) bits = 128;
-			break;
-		default:
-			return false;
-	}
-
-	const uint8_t *a = (const uint8_t *)rawIpData();
-	const uint8_t *b = (const uint8_t *)ipnet.rawIpData();
-	while (bits >= 8) {
-		if (*(a++) != *(b++))
-			return false;
-		bits -= 8;
-	}
-	bits = 8 - bits;
-	return ((*a >> bits) == (*b >> bits));
-}
-
-bool InetAddress::within(const InetAddress &ipnet) const
-	throw()
-{
-	if (_sa.saddr.sa_family != ipnet._sa.saddr.sa_family)
-		return false;
-
-	unsigned int bits = ipnet.netmaskBits();
-	switch(_sa.saddr.sa_family) {
-		case AF_INET:
-			if (bits > 32) return false;
-			break;
-		case AF_INET6:
-			if (bits > 128) return false;
-			break;
-		default: return false;
-	}
-
-	const uint8_t *a = (const uint8_t *)rawIpData();
-	const uint8_t *b = (const uint8_t *)ipnet.rawIpData();
-	while (bits >= 8) {
-		if (*(a++) != *(b++))
-			return false;
-		bits -= 8;
-	}
-	if (bits) {
-		uint8_t mask = ((0xff << (8 - bits)) & 0xff);
-		return ((*a & mask) == (*b & mask));
-	} else return true;
-}
-
-bool InetAddress::operator==(const InetAddress &a) const
-	throw()
-{
-	if (_sa.saddr.sa_family == AF_INET) {
-		if (a._sa.saddr.sa_family == AF_INET)
-			return ((_sa.sin.sin_addr.s_addr == a._sa.sin.sin_addr.s_addr)&&(_sa.sin.sin_port == a._sa.sin.sin_port));
-		return false;
-	} else if (_sa.saddr.sa_family == AF_INET6) {
-		if (a._sa.saddr.sa_family == AF_INET6) {
-			if (_sa.sin6.sin6_port == a._sa.sin6.sin6_port)
-				return (!memcmp(_sa.sin6.sin6_addr.s6_addr,a._sa.sin6.sin6_addr.s6_addr,sizeof(_sa.sin6.sin6_addr.s6_addr)));
-		}
-		return false;
-	} else return (memcmp(&_sa,&a._sa,sizeof(_sa)) == 0);
-}
-
-bool InetAddress::operator<(const InetAddress &a) const
-	throw()
-{
-	if (_sa.saddr.sa_family < a._sa.saddr.sa_family)
-		return true;
-	else if (_sa.saddr.sa_family == a._sa.saddr.sa_family) {
-		if (_sa.saddr.sa_family == AF_INET) {
-			unsigned long x = Utils::ntoh((uint32_t)_sa.sin.sin_addr.s_addr);
-			unsigned long y = Utils::ntoh((uint32_t)a._sa.sin.sin_addr.s_addr);
-			if (x == y)
-				return (Utils::ntoh((uint16_t)_sa.sin.sin_port) < Utils::ntoh((uint16_t)a._sa.sin.sin_port));
-			else return (x < y);
-		} else if (_sa.saddr.sa_family == AF_INET6) {
-			int cmp = (int)memcmp(_sa.sin6.sin6_addr.s6_addr,a._sa.sin6.sin6_addr.s6_addr,16);
-			if (cmp == 0)
-				return (Utils::ntoh((uint16_t)_sa.sin6.sin6_port) < Utils::ntoh((uint16_t)a._sa.sin6.sin6_port));
-			else return (cmp < 0);
-		} else return (memcmp(&_sa,&a._sa,sizeof(_sa)) < 0);
-	}
-	return false;
-}
-
 InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac)
 	throw()
 {
-	InetAddress ip;
-	ip._sa.saddr.sa_family = AF_INET6;
-	ip._sa.sin6.sin6_addr.s6_addr[0] = 0xfe;
-	ip._sa.sin6.sin6_addr.s6_addr[1] = 0x80;
-	ip._sa.sin6.sin6_addr.s6_addr[2] = 0x00;
-	ip._sa.sin6.sin6_addr.s6_addr[3] = 0x00;
-	ip._sa.sin6.sin6_addr.s6_addr[4] = 0x00;
-	ip._sa.sin6.sin6_addr.s6_addr[5] = 0x00;
-	ip._sa.sin6.sin6_addr.s6_addr[6] = 0x00;
-	ip._sa.sin6.sin6_addr.s6_addr[7] = 0x00;
-	ip._sa.sin6.sin6_addr.s6_addr[8] = mac[0] & 0xfd;
-	ip._sa.sin6.sin6_addr.s6_addr[9] = mac[1];
-	ip._sa.sin6.sin6_addr.s6_addr[10] = mac[2];
-	ip._sa.sin6.sin6_addr.s6_addr[11] = 0xff;
-	ip._sa.sin6.sin6_addr.s6_addr[12] = 0xfe;
-	ip._sa.sin6.sin6_addr.s6_addr[13] = mac[3];
-	ip._sa.sin6.sin6_addr.s6_addr[14] = mac[4];
-	ip._sa.sin6.sin6_addr.s6_addr[15] = mac[5];
-	ip._sa.sin6.sin6_port = Utils::hton((uint16_t)64);
-	return ip;
+	struct sockaddr_in6 sin6;
+	sin6.sin6_family = AF_INET6;
+	sin6.sin6_addr.s6_addr[0] = 0xfe;
+	sin6.sin6_addr.s6_addr[1] = 0x80;
+	sin6.sin6_addr.s6_addr[2] = 0x00;
+	sin6.sin6_addr.s6_addr[3] = 0x00;
+	sin6.sin6_addr.s6_addr[4] = 0x00;
+	sin6.sin6_addr.s6_addr[5] = 0x00;
+	sin6.sin6_addr.s6_addr[6] = 0x00;
+	sin6.sin6_addr.s6_addr[7] = 0x00;
+	sin6.sin6_addr.s6_addr[8] = mac[0] & 0xfd;
+	sin6.sin6_addr.s6_addr[9] = mac[1];
+	sin6.sin6_addr.s6_addr[10] = mac[2];
+	sin6.sin6_addr.s6_addr[11] = 0xff;
+	sin6.sin6_addr.s6_addr[12] = 0xfe;
+	sin6.sin6_addr.s6_addr[13] = mac[3];
+	sin6.sin6_addr.s6_addr[14] = mac[4];
+	sin6.sin6_addr.s6_addr[15] = mac[5];
+	sin6.sin6_port = Utils::hton((uint16_t)64);
+	return InetAddress(sin6);
 }
 
 } // namespace ZeroTier

+ 129 - 141
node/InetAddress.hpp

@@ -35,39 +35,20 @@
 #include <string>
 
 #include "Constants.hpp"
+#include "../include/ZeroTierOne.h"
 #include "Utils.hpp"
 #include "MAC.hpp"
 
-#ifdef __WINDOWS__
-#include <WinSock2.h>
-#include <WS2tcpip.h>
-#include <Windows.h>
-#else
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <sys/socket.h>
-#endif
-
 namespace ZeroTier {
 
 /**
- * Wrapper for sockaddr structures for IPV4 and IPV6
+ * Extends sockaddr_storage with friendly C++ methods
  *
- * Note: this class is raw memcpy'able, which is used in a couple places.
+ * This adds no new fields, so it can be memcpy'd and assigned to/from
+ * raw sockaddr_storage structures. This is used in a few places.
  */
-class InetAddress
+struct InetAddress : public sockaddr_storage
 {
-public:
-	/**
-	 * Address type
-	 */
-	enum AddressType
-	{
-		TYPE_NULL = 0,
-		TYPE_IPV4 = AF_INET,
-		TYPE_IPV6 = AF_INET6
-	};
-
 	/**
 	 * Loopback IPv4 address (no port)
 	 */
@@ -88,9 +69,16 @@ public:
 	 */
 	static const InetAddress DEFAULT6;
 
-	InetAddress() throw() { memset(&_sa,0,sizeof(_sa)); }
-	InetAddress(const InetAddress &a) throw() { memcpy(&_sa,&a._sa,sizeof(_sa)); }
-	InetAddress(const struct sockaddr *sa) throw() { this->set(sa); }
+	InetAddress() throw() { memset(this,0,sizeof(InetAddress)); }
+	InetAddress(const InetAddress &a) throw() { memcpy(this,&a,sizeof(InetAddress)); }
+	InetAddress(const struct sockaddr_storage &ss) throw() { *this = ss; }
+	InetAddress(const struct sockaddr_storage *ss) throw() { *this = ss; }
+	InetAddress(const struct sockaddr &sa) throw() { *this = sa; }
+	InetAddress(const struct sockaddr *sa) throw() { *this = sa; }
+	InetAddress(const struct sockaddr_in &sa) throw() { *this = sa; }
+	InetAddress(const struct sockaddr_in *sa) throw() { *this = sa; }
+	InetAddress(const struct sockaddr_in6 &sa) throw() { *this = sa; }
+	InetAddress(const struct sockaddr_in6 *sa) throw() { *this = sa; }
 	InetAddress(const void *ipBytes,unsigned int ipLen,unsigned int port) throw() { this->set(ipBytes,ipLen,port); }
 	InetAddress(const uint32_t ipv4,unsigned int port) throw() { this->set(&ipv4,4,port); }
 	InetAddress(const std::string &ip,unsigned int port) throw() { this->set(ip,port); }
@@ -100,23 +88,84 @@ public:
 	inline InetAddress &operator=(const InetAddress &a)
 		throw()
 	{
-		memcpy(&_sa,&a._sa,sizeof(_sa));
+		memcpy(this,&a,sizeof(InetAddress));
 		return *this;
 	}
 
-	/**
-	 * Set from an OS-level sockaddr structure
-	 *
-	 * @param sa Socket address (V4 or V6)
-	 */
-	inline void set(const struct sockaddr *sa)
+	inline InetAddress &operator=(const struct sockaddr_storage &ss)
+		throw()
+	{
+		memcpy(this,&ss,sizeof(InetAddress));
+		return *this;
+	}
+
+	inline InetAddress &operator=(const struct sockaddr_storage *ss)
+		throw()
+	{
+		memcpy(this,ss,sizeof(InetAddress));
+		return *this;
+	}
+
+	inline InetAddress &operator=(const struct sockaddr_in &sa)
+		throw()
+	{
+		memset(this,0,sizeof(InetAddress));
+		memcpy(this,&sa,sizeof(struct sockaddr_in));
+		return *this;
+	}
+
+	inline InetAddress &operator=(const struct sockaddr_in *sa)
+		throw()
+	{
+		memset(this,0,sizeof(InetAddress));
+		memcpy(this,sa,sizeof(struct sockaddr_in));
+		return *this;
+	}
+
+	inline InetAddress &operator=(const struct sockaddr_in6 &sa)
+		throw()
+	{
+		memset(this,0,sizeof(InetAddress));
+		memcpy(this,&sa,sizeof(struct sockaddr_in6));
+		return *this;
+	}
+
+	inline InetAddress &operator=(const struct sockaddr_in6 *sa)
+		throw()
+	{
+		memset(this,0,sizeof(InetAddress));
+		memcpy(this,sa,sizeof(struct sockaddr_in6));
+		return *this;
+	}
+
+	inline InetAddress &operator=(const struct sockaddr &sa)
 		throw()
 	{
+		memset(this,0,sizeof(InetAddress));
+		switch(sa.sa_family) {
+			case AF_INET:
+				memcpy(this,&sa,sizeof(struct sockaddr_in));
+				break;
+			case AF_INET6:
+				memcpy(this,&sa,sizeof(struct sockaddr_in6));
+				break;
+		}
+		return *this;
+	}
+
+	inline InetAddress &operator=(const struct sockaddr *sa)
+		throw()
+	{
+		memset(this,0,sizeof(InetAddress));
 		switch(sa->sa_family) {
-			case AF_INET: memcpy(&_sa.sin,sa,sizeof(struct sockaddr_in)); break;
-			case AF_INET6: memcpy(&_sa.sin6,sa,sizeof(struct sockaddr_in6)); break;
-			default: memset(&_sa,0,sizeof(_sa)); break;
+			case AF_INET:
+				memcpy(this,sa,sizeof(struct sockaddr_in));
+				break;
+			case AF_INET6:
+				memcpy(this,sa,sizeof(struct sockaddr_in6));
+				break;
 		}
+		return *this;
 	}
 
 	/**
@@ -146,10 +195,14 @@ public:
 	inline void setPort(unsigned int port)
 		throw()
 	{
-		if (_sa.saddr.sa_family == AF_INET)
-			_sa.sin.sin_port = Utils::hton((uint16_t)port);
-		else if (_sa.saddr.sa_family == AF_INET6)
-			_sa.sin6.sin6_port = Utils::hton((uint16_t)port);
+		switch(ss_family) {
+			case AF_INET:
+				reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton((uint16_t)port);
+				break;
+			case AF_INET6:
+				reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_port = Utils::hton((uint16_t)port);
+				break;
+		}
 	}
 
 	/**
@@ -158,20 +211,10 @@ public:
 	bool isLinkLocal() const
 		throw();
 
-	/**
-	 * @return True if this ip/netmask would represent a default route (e.g. 0.0.0.0/0)
-	 */
-	bool isDefaultRoute() const
-		throw();
-
 	/**
 	 * @return True if this is a loopback address
 	 */
-	inline bool isLoopback() const
-		throw()
-	{
-		return ((*this == LO4)||(*this == LO6));
-	}
+	inline bool isLoopback() const throw() { return ((*this == LO4)||(*this == LO6)); }
 
 	/**
 	 * @return ASCII IP/port format representation
@@ -179,14 +222,14 @@ public:
 	std::string toString() const;
 
 	/**
-	 * @param ipSlashPort ASCII IP/port format notation
+	 * @return IP portion only, in ASCII string format
 	 */
-	void fromString(const std::string &ipSlashPort);
+	std::string toIpString() const;
 
 	/**
-	 * @return IP portion only, in ASCII string format
+	 * @param ipSlashPort ASCII IP/port format notation
 	 */
-	std::string toIpString() const;
+	void fromString(const std::string &ipSlashPort);
 
 	/**
 	 * @return Port or 0 if no port component defined
@@ -194,9 +237,9 @@ public:
 	inline unsigned int port() const
 		throw()
 	{
-		switch(_sa.saddr.sa_family) {
-			case AF_INET: return Utils::ntoh((uint16_t)_sa.sin.sin_port);
-			case AF_INET6: return Utils::ntoh((uint16_t)_sa.sin6.sin6_port);
+		switch(ss_family) {
+			case AF_INET: return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in *>(this)->sin_port));
+			case AF_INET6: return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port));
 			default: return 0;
 		}
 	}
@@ -229,33 +272,22 @@ public:
 	/**
 	 * @return True if this is an IPv4 address
 	 */
-	inline bool isV4() const throw() { return (_sa.saddr.sa_family == AF_INET); }
+	inline bool isV4() const throw() { return (ss_family == AF_INET); }
 
 	/**
 	 * @return True if this is an IPv6 address
 	 */
-	inline bool isV6() const throw() { return (_sa.saddr.sa_family == AF_INET6); }
-
-	/**
-	 * @return Address type or TYPE_NULL if not defined
-	 */
-	inline AddressType type() const throw() { return (AddressType)_sa.saddr.sa_family; }
+	inline bool isV6() const throw() { return (ss_family == AF_INET6); }
 
 	/**
 	 * Force type to IPv4
 	 */
-	inline void setV4() throw() { _sa.saddr.sa_family = AF_INET; }
+	inline void setV4() throw() { ss_family = AF_INET; }
 
 	/**
 	 * Force type to IPv6
 	 */
-	inline void setV6() throw() { _sa.saddr.sa_family = AF_INET6; }
-
-	/**
-	 * @return Raw sockaddr structure
-	 */
-	inline struct sockaddr *saddr() throw() { return &(_sa.saddr); }
-	inline const struct sockaddr *saddr() const throw() { return &(_sa.saddr); }
+	inline void setV6() throw() { ss_family = AF_INET6; }
 
 	/**
 	 * @return Length of sockaddr_in if IPv4, sockaddr_in6 if IPv6
@@ -263,99 +295,62 @@ public:
 	inline unsigned int saddrLen() const
 		throw()
 	{
-		switch(_sa.saddr.sa_family) {
+		switch(ss_family) {
 			case AF_INET: return sizeof(struct sockaddr_in);
 			case AF_INET6: return sizeof(struct sockaddr_in6);
 			default: return 0;
 		}
 	}
 
-	/**
-	 * @return Checksum of this address (not portable, so don't use for long-term storage purposes)
-	 */
-	inline uint64_t hashCode() const
-	{
-		switch(_sa.saddr.sa_family) {
-			case AF_INET:
-				return ((uint64_t)_sa.sin.sin_port + (uint64_t)(_sa.sin.sin_addr.s_addr));
-			case AF_INET6:
-				return ((uint64_t)_sa.sin6.sin6_port + ( ((const uint64_t *)_sa.sin6.sin6_addr.s6_addr)[0] ^ ((const uint64_t *)_sa.sin6.sin6_addr.s6_addr)[1] ));
-		}
-		return 0;
-	}
-
-	/**
-	 * @return Combined length of internal structure, room for either V4 or V6
-	 */
-	inline unsigned int saddrSpaceLen() const throw() { return sizeof(_sa); }
-
 	/**
 	 * @return Raw sockaddr_in structure (valid if IPv4)
 	 */
-	inline const struct sockaddr_in *saddr4() const throw() { return &(_sa.sin); }
+	inline const struct sockaddr_in *saddr4() const throw() { return reinterpret_cast<const struct sockaddr_in *>(this); }
 
 	/**
 	 * @return Raw sockaddr_in6 structure (valid if IPv6)
 	 */
-	inline const struct sockaddr_in6 *saddr6() const throw() { return &(_sa.sin6); }
+	inline const struct sockaddr_in6 *saddr6() const throw() { return reinterpret_cast<const struct sockaddr_in6 *>(this); }
 
 	/**
-	 * @return Raw IP address (4 bytes for IPv4, 16 bytes for IPv6)
+	 * @return pointer to raw IP address bytes
 	 */
-	inline void *rawIpData() throw() { return ((_sa.saddr.sa_family == AF_INET) ? (void *)(&(_sa.sin.sin_addr.s_addr)) : (void *)_sa.sin6.sin6_addr.s6_addr); }
-	inline const void *rawIpData() const throw() { return ((_sa.saddr.sa_family == AF_INET) ? (void *)(&(_sa.sin.sin_addr.s_addr)) : (void *)_sa.sin6.sin6_addr.s6_addr); }
-
-	/**
-	 * Compare only the IP portions of addresses, ignoring port/netmask
-	 *
-	 * @param a Address to compare
-	 * @return True if both addresses are of the same (valid) type and their IPs match
-	 */
-	inline bool ipsEqual(const InetAddress &a) const
+	inline const void *rawIpData() const
 		throw()
 	{
-		if (_sa.saddr.sa_family == a._sa.saddr.sa_family) {
-			switch(_sa.saddr.sa_family) {
-				case AF_INET:
-					return (_sa.sin.sin_addr.s_addr == a._sa.sin.sin_addr.s_addr);
-				case AF_INET6:
-					return (!memcmp(_sa.sin6.sin6_addr.s6_addr,a._sa.sin6.sin6_addr.s6_addr,16));
-			}
+		switch(ss_family) {
+			case AF_INET: return (const void *)&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
+			case AF_INET6: return (const void *)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
+			default: return 0;
 		}
-		return false;
 	}
 
 	/**
-	 * Compare IP/netmask with another IP/netmask
-	 *
-	 * @param ipnet IP/netmask to compare with
-	 * @return True if [netmask] bits match
+	 * @return pointer to raw IP address bytes
 	 */
-	bool sameNetworkAs(const InetAddress &ipnet) const
-		throw();
-
-	/**
-	 * Determine whether this address is within an ip/netmask
-	 *
-	 * @param ipnet IP/netmask
-	 * @return True if this address is within this network
-	 */
-	bool within(const InetAddress &ipnet) const
-		throw();
+	inline void *rawIpData()
+		throw()
+	{
+		switch(ss_family) {
+			case AF_INET: return (void *)&(reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr);
+			case AF_INET6: return (void *)(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
+			default: return 0;
+		}
+	}
 
 	/**
 	 * Set to null/zero
 	 */
-	inline void zero() throw() { memset(&_sa,0,sizeof(_sa)); }
+	inline void zero() throw() { memset(this,0,sizeof(InetAddress)); }
 
 	/**
 	 * @return True if address family is non-zero
 	 */
-	inline operator bool() const throw() { return ((_sa.saddr.sa_family == AF_INET)||(_sa.saddr.sa_family == AF_INET6)); }
+	inline operator bool() const throw() { return (ss_family != 0); }
 
-	bool operator==(const InetAddress &a) const throw();
+	inline bool operator==(const InetAddress &a) const throw() { return (memcmp(this,&a,sizeof(InetAddress)) == 0); }
 	inline bool operator!=(const InetAddress &a) const throw() { return !(*this == a); }
-	bool operator<(const InetAddress &a) const throw();
+	inline bool operator<(const InetAddress &a) const throw() { return (memcmp(this,&a,sizeof(InetAddress)) < 0); }
 	inline bool operator>(const InetAddress &a) const throw() { return (a < *this); }
 	inline bool operator<=(const InetAddress &a) const throw() { return !(a < *this); }
 	inline bool operator>=(const InetAddress &a) const throw() { return !(*this < a); }
@@ -366,13 +361,6 @@ public:
 	 */
 	static InetAddress makeIpv6LinkLocal(const MAC &mac)
 		throw();
-
-private:
-	union {
-		struct sockaddr saddr;
-		struct sockaddr_in sin;
-		struct sockaddr_in6 sin6;
-	} _sa;
 };
 
 } // namespace ZeroTier

+ 7 - 0
node/MAC.hpp

@@ -71,6 +71,13 @@ public:
 
 	MAC(const Address &ztaddr,uint64_t nwid) throw() { fromAddress(ztaddr,nwid); }
 
+	MAC(const uint64_t m) throw() : _m(m & 0xffffffffffffULL) {}
+
+	/**
+	 * @return MAC in 64-bit integer
+	 */
+	inline uint64_t toInt() const throw() { return _m; }
+
 	/**
 	 * Set MAC to zero
 	 */

+ 30 - 0
node/Node.cpp

@@ -0,0 +1,30 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015  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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#include "Node.hpp"
+#include "RuntimeEnvironment.hpp"
+

+ 206 - 0
node/Node.hpp

@@ -0,0 +1,206 @@
+/*
+ * ZeroTier One - Network Virtualization Everywhere
+ * Copyright (C) 2011-2015  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.
+ *
+ * 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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#ifndef ZT_NODE_HPP
+#define ZT_NODE_HPP
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <map>
+
+#include "Constants.hpp"
+
+#include "../include/ZeroTierOne.h"
+
+#include "InetAddress.hpp"
+#include "Mutex.hpp"
+#include "MAC.hpp"
+
+namespace ZeroTier {
+
+class RuntimeEnvironment;
+
+/**
+ * Implementation of Node object as defined in CAPI
+ *
+ * The pointer returned by ZT1_Node_new() is an instance of this class.
+ */
+class Node
+{
+public:
+	Node(
+		ZT1_DataStoreGetFunction *dataStoreGetFunction,
+		ZT1_DataStorePutFunction *dataStorePutFunction,
+		ZT1_VirtualNetworkConfigCallback *networkConfigCallback,
+		ZT1_StatusCallback *statusCallback);
+
+	~Node();
+
+	// Public API Functions ----------------------------------------------------
+
+	ZT1_ResultCode run(
+		uint64_t now,
+		const ZT1_WireMessage *inputWireMessages,
+		unsigned int inputWireMessageCount,
+		const ZT1_VirtualLanFrame *inputLanFrames,
+		unsigned int inputLanFrameCount,
+		const ZT1_WireMessage **outputWireMessages,
+		unsigned int *outputWireMessageCount,
+		const ZT1_VirtualNetworkFrame **outputFrames,
+		unsigned int *outputLanFrameCount,
+		unsigned long *maxNextInterval);
+
+	ZT1_ResultCode join(uint64_t nwid);
+
+	ZT1_ResultCode leave(uint64_t nwid);
+
+	void status(ZT1_NodeStatus *status);
+
+	ZT1_PeerList *peers();
+
+	ZT1_VirtualNetworkConfig *networkConfig(uint64_t nwid);
+
+	ZT1_VirtualNetworkList *listNetworks();
+
+	void freeQueryResult(void *qr);
+
+	ZT1_ResultCode setNetconfMaster(
+		ZT1_Node *node,
+		void *networkConfigMasterInstance);
+
+	// Internal functions ------------------------------------------------------
+
+	/**
+	 * @return Time as of last call to run()
+	 */
+	inline uint64_t now() const throw() { return _now; }
+
+	/**
+	 * @return Current level of desperation
+	 */
+	inline int desperation() const throw() { return (int)((_now - _timeOfLastPrivilgedPacket) / ZT_DESPERATION_INCREMENT); }
+
+	/**
+	 * Enqueue a ZeroTier message to be sent
+	 *
+	 * @param addr Destination address
+	 * @param data Packet data
+	 * @param len Packet length
+	 */
+	inline void putPacket(const InetAddress &addr,const void *data,unsigned int len)
+	{
+		Mutex::Lock _l(_outputWireMessages_m);
+		if (_outputWireMessageCount >= _outputWireMessageCapacity) {
+			ZT1_WireMessage *old = _outputWireMessages;
+			_outputWireMessages = new ZT1_WireMessage[_outputWireMessageCapacity *= 2];
+			memcpy(_outputWireMessages,old,sizeof(ZT1_WireMessage) * _outputWireMessageCount);
+			delete [] old;
+		}
+		ZT1_WireMessage &wm = _outputWireMessages[_outputWireMessageCount++];
+		memcpy(&(wm.address),&addr,sizeof(ZT_SOCKADDR_STORAGE));
+		wm.desperation = this->desperation();
+		wm.spam = (int)((++_spamCounter % ZT_DESPERATION_SPAM_EVERY) == 0);
+		memcpy(wm.packetData,data,len);
+		wm.packetLength = len;
+	}
+
+	/**
+	 * Enqueue a frame to be injected into a tap device (port)
+	 *
+	 * @param nwid Network ID
+	 * @param source Source MAC
+	 * @param dest Destination MAC
+	 * @param etherType 16-bit ethernet type
+	 * @param vlanId VLAN ID or 0 if none
+	 * @param data Frame data
+	 * @param len Frame length
+	 */
+	inline void putFrame(uint64_t nwid,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
+	{
+		Mutex::Lock _l(_outputFrames_m);
+		if (_outputFrameCount >= _outputFrameCapacity) {
+			ZT1_VirtualNetworkFrame *old = _outputFrames;
+			_outputFrames = new ZT1_VirtualNetworkFrame[_outputFrameCapacity *= 2];
+			memcpy(_outputFrames,old,sizeof(ZT1_VirtualNetworkFrame) * _outputFrameCount);
+			delete [] old;
+		}
+		ZT1_VirtualNetworkFrame &f = _outputFrames[_outputFrameCount++];
+		f.nwid = nwid;
+		f.sourceMac = source.toInt();
+		f.destMac = dest.toInt();
+		f.etherType = etherType;
+		f.vlanId = vlanId;
+		memcpy(f.frameData,data,len);
+		f.frameLength = len;
+	}
+
+	/**
+	 * @param nwid Network ID
+	 * @return Network instance
+	 */
+	inline SharedPtr<Network> network(uint64_t nwid)
+	{
+		Mutex::Lock _l(_networks_m);
+		std::map< uint64_t,Network >::iterator nw(_networks.find(nwid));
+		return ((nw == _networks.end()) ? SharedPtr<Network>() : nw->second);
+	}
+
+private:
+	RuntimeEnvironment *RR;
+
+	ZT1_WireMessage *_outputWireMessages;
+	unsigned long _outputWireMessageCount;
+	unsigned long _outputWireMessageCapacity;
+	Mutex _outputWireMessages_m;
+
+	ZT1_VirtualNetworkFrame *_outputFrames;
+	unsigned long _outputFrameCount;
+	unsigned long _outputFrameCapacity;
+	Mutex _outputFrames_m;
+
+	ZT1_DataStoreGetFunction *_dataStoreGetFunction,
+	ZT1_DataStorePutFunction *_dataStorePutFunction,
+	ZT1_VirtualPortConfigCallback *_portConfigCallback,
+	ZT1_StatusCallback *_statusCallback);
+
+	//Dictionary _localConfig; // persisted as local.conf
+	//Mutex _localConfig_m;
+
+	std::map< uint64_t,SharedPtr<Network> > _networks;
+	Mutex _networks_m;
+
+	uint64_t _now; // time of last run()
+	uint64_t _timeOfLastPacketReceived;
+	uint64_t _timeOfLastPrivilgedPacket;
+	unsigned int _spamCounter; // used to "spam" every Nth packet
+};
+
+} // namespace ZeroTier
+
+#endif

+ 0 - 137
node/NodeConfig.cpp

@@ -1,137 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015  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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdint.h>
-
-#include <memory>
-#include <string>
-#include <map>
-#include <set>
-
-#include "Constants.hpp"
-
-#include "NodeConfig.hpp"
-#include "RuntimeEnvironment.hpp"
-#include "Defaults.hpp"
-#include "Utils.hpp"
-#include "Logger.hpp"
-#include "Topology.hpp"
-#include "Packet.hpp"
-#include "InetAddress.hpp"
-#include "Peer.hpp"
-#include "Node.hpp"
-#include "SoftwareUpdater.hpp"
-
-namespace ZeroTier {
-
-NodeConfig::NodeConfig(const RuntimeEnvironment *renv) :
-	RR(renv)
-{
-	{
-		Mutex::Lock _l(_localConfig_m);
-		_readLocalConfig();
-	}
-
-	std::string networksFolder(RR->homePath + ZT_PATH_SEPARATOR_S + "networks.d");
-	std::map<std::string,bool> networksDotD(Utils::listDirectory(networksFolder.c_str()));
-	std::vector<uint64_t> configuredNets;
-	for(std::map<std::string,bool>::iterator d(networksDotD.begin());d!=networksDotD.end();++d) {
-		if (!d->second) {
-			std::string::size_type dot = d->first.rfind(".conf");
-			if (dot != std::string::npos) {
-				uint64_t nwid = Utils::hexStrToU64(d->first.substr(0,dot).c_str());
-				if ((nwid > 0)&&(std::find(configuredNets.begin(),configuredNets.end(),nwid) == configuredNets.end()))
-					configuredNets.push_back(nwid);
-			}
-		}
-	}
-
-	for(std::vector<uint64_t>::iterator n(configuredNets.begin());n!=configuredNets.end();++n) {
-		try {
-			_networks[*n] = Network::newInstance(RR,this,*n);
-		} catch (std::exception &exc) {
-			LOG("unable to create network %.16llx: %s",(unsigned long long)*n,exc.what());
-		} catch ( ... ) {
-			LOG("unable to create network %.16llx: (unknown exception)",(unsigned long long)*n);
-		}
-	}
-}
-
-NodeConfig::~NodeConfig()
-{
-	_writeLocalConfig();
-}
-
-void NodeConfig::putLocalConfig(const std::string &key,const char *value)
-{
-	Mutex::Lock _l(_localConfig_m);
-	_localConfig[key] = value;
-	_writeLocalConfig();
-}
-
-void NodeConfig::putLocalConfig(const std::string &key,const std::string &value)
-{
-	Mutex::Lock _l(_localConfig_m);
-	_localConfig[key] = value;
-	_writeLocalConfig();
-}
-
-std::string NodeConfig::getLocalConfig(const std::string &key) const
-{
-	Mutex::Lock _l(_localConfig_m);
-	Dictionary::const_iterator i(_localConfig.find(key));
-	if (i == _localConfig.end())
-		return std::string();
-	return i->second;
-}
-
-void NodeConfig::clean()
-{
-	Mutex::Lock _l(_networks_m);
-	for(std::map< uint64_t,SharedPtr<Network> >::const_iterator n(_networks.begin());n!=_networks.end();++n)
-		n->second->clean();
-}
-
-void NodeConfig::_readLocalConfig()
-{
-	// assumes _localConfig_m is locked
-	std::string localDotConf(RR->homePath + ZT_PATH_SEPARATOR_S + "local.conf");
-	std::string buf;
-	if (Utils::readFile(localDotConf.c_str(),buf))
-		_localConfig.fromString(buf.c_str());
-}
-
-void NodeConfig::_writeLocalConfig()
-{
-	// assumes _localConfig_m is locked
-	Utils::writeFile(((RR->homePath + ZT_PATH_SEPARATOR_S + "local.conf")).c_str(),_localConfig.toString());
-}
-
-} // namespace ZeroTier

+ 0 - 181
node/NodeConfig.hpp

@@ -1,181 +0,0 @@
-/*
- * ZeroTier One - Network Virtualization Everywhere
- * Copyright (C) 2011-2015  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.
- *
- * 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.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <http://www.gnu.org/licenses/>.
- *
- * --
- *
- * ZeroTier may be used and distributed under the terms of the GPLv3, which
- * are available at: http://www.gnu.org/licenses/gpl-3.0.html
- *
- * If you would like to embed ZeroTier into a commercial application or
- * redistribute it in a modified binary form, please contact ZeroTier Networks
- * LLC. Start here: http://www.zerotier.com/
- */
-
-#ifndef ZT_NODECONFIG_HPP
-#define ZT_NODECONFIG_HPP
-
-#include <stdint.h>
-
-#include <map>
-#include <set>
-#include <string>
-#include <vector>
-#include <stdexcept>
-
-#include "SharedPtr.hpp"
-#include "Network.hpp"
-#include "Utils.hpp"
-#include "Buffer.hpp"
-#include "Dictionary.hpp"
-
-namespace ZeroTier {
-
-class RuntimeEnvironment;
-
-/**
- * Node configuration endpoint
- */
-class NodeConfig
-{
-public:
-	/**
-	 * @param renv Runtime environment
-	 * @throws std::runtime_error Unable to initialize or listen for IPC connections
-	 */
-	NodeConfig(const RuntimeEnvironment *renv);
-
-	~NodeConfig();
-
-	/**
-	 * Store something in local configuration cache
-	 *
-	 * By convention, keys starting with _ will not be shown in the command bus
-	 * local config functions.
-	 *
-	 * @param key Configuration key
-	 * @param value Configuration value
-	 */
-	void putLocalConfig(const std::string &key,const char *value);
-	void putLocalConfig(const std::string &key,const std::string &value);
-
-	/**
-	 * @param key Configuration key
-	 * @return Value or empty string if not found
-	 */
-	std::string getLocalConfig(const std::string &key) const;
-
-	/**
-	 * @param nwid Network ID
-	 * @return Network or NULL if no network for that ID
-	 */
-	inline SharedPtr<Network> network(uint64_t nwid) const
-	{
-		Mutex::Lock _l(_networks_m);
-		std::map< uint64_t,SharedPtr<Network> >::const_iterator n(_networks.find(nwid));
-		return ((n == _networks.end()) ? SharedPtr<Network>() : n->second);
-	}
-
-	/**
-	 * @return Vector containing all networks
-	 */
-	inline std::vector< SharedPtr<Network> > networks() const
-	{
-		std::vector< SharedPtr<Network> > nwlist;
-		Mutex::Lock _l(_networks_m);
-		for(std::map< uint64_t,SharedPtr<Network> >::const_iterator n(_networks.begin());n!=_networks.end();++n)
-			nwlist.push_back(n->second);
-		return nwlist;
-	}
-
-	/**
-	 * Join a network or return existing network if already joined
-	 *
-	 * @param nwid Network ID to join
-	 * @return New network instance
-	 */
-	inline SharedPtr<Network> join(uint64_t nwid)
-	{
-		Mutex::Lock _l(_networks_m);
-		SharedPtr<Network> &nw = _networks[nwid];
-		if (nw)
-			return nw;
-		else return (nw = Network::newInstance(RR,this,nwid));
-	}
-
-	/**
-	 * Leave a network
-	 *
-	 * @param nwid Network ID
-	 * @return True if network was left, false if we were not a member of this network
-	 */
-	inline bool leave(uint64_t nwid)
-	{
-		Mutex::Lock _l(_networks_m);
-		std::map< uint64_t,SharedPtr<Network> >::iterator n(_networks.find(nwid));
-		if (n != _networks.end()) {
-			n->second->destroy();
-			_networks.erase(n);
-			return true;
-		} else return false;
-	}
-
-	/**
-	 * Perform cleanup and possibly persist saved state
-	 */
-	void clean();
-
-	/**
-	 * @param nwid Network ID
-	 * @return True if this network exists
-	 */
-	inline bool hasNetwork(uint64_t nwid)
-	{
-		Mutex::Lock _l(_networks_m);
-		return (_networks.find(nwid) != _networks.end());
-	}
-
-	/**
-	 * @return Sorted vector of network tap device names from our virtual networks (not other taps on system)
-	 */
-	inline std::vector<std::string> networkTapDeviceNames() const
-	{
-		std::vector<std::string> tapDevs;
-		Mutex::Lock _l(_networks_m);
-		for(std::map< uint64_t,SharedPtr<Network> >::const_iterator n(_networks.begin());n!=_networks.end();++n) {
-			std::string dn(n->second->tapDeviceName());
-			if (dn.length())
-				tapDevs.push_back(dn);
-		}
-		return tapDevs;
-	}
-
-private:
-	void _readLocalConfig();
-	void _writeLocalConfig();
-
-	const RuntimeEnvironment *RR;
-
-	Dictionary _localConfig; // persisted as local.conf
-	Mutex _localConfig_m;
-
-	std::map< uint64_t,SharedPtr<Network> > _networks; // persisted in networks.d/
-	Mutex _networks_m;
-};
-
-} // namespace ZeroTier
-
-#endif

+ 2 - 35
node/RuntimeEnvironment.hpp

@@ -41,12 +41,8 @@ class Switch;
 class Topology;
 class CMWC4096;
 class Node;
-class SoftwareUpdater;
-class SocketManager;
 class Multicaster;
 class AntiRecursion;
-class EthernetTapFactory;
-class HttpClient;
 class NetworkConfigMaster;
 
 /**
@@ -65,50 +61,23 @@ class RuntimeEnvironment
 {
 public:
 	RuntimeEnvironment() :
-		homePath(),
 		identity(),
-		initialized(false),
-		tcpTunnelingEnabled(false),
-		timeOfLastResynchronize(0),
-		timeOfLastPacketReceived(0),
-		tapFactory((EthernetTapFactory *)0),
-		sm((SocketManager *)0),
 		netconfMaster((NetworkConfigMaster *)0),
 		log((Logger *)0),
 		prng((CMWC4096 *)0),
-		http((HttpClient *)0),
 		sw((Switch *)0),
 		mc((Multicaster *)0),
 		antiRec((AntiRecursion *)0),
 		topology((Topology *)0),
 		nc((NodeConfig *)0),
-		node((Node *)0),
-		updater((SoftwareUpdater *)0)
+		node((Node *)0)
 	{
 	}
 
-	// Full path to home folder
-	std::string homePath;
-
 	// This node's identity
 	Identity identity;
 
-	// Are we initialized?
-	volatile bool initialized;
-
-	// Are we in outgoing TCP failover mode?
-	volatile bool tcpTunnelingEnabled;
-
-	// Time network environment (e.g. fingerprint) last changed -- used to determine online-ness
-	volatile uint64_t timeOfLastResynchronize;
-
-	// Time last packet was received -- from anywhere. This is updated in Peer::receive()
-	// via an ugly const_cast<>.
-	volatile uint64_t timeOfLastPacketReceived;
-
-	// These are passed in from outside and are not created or deleted by the ZeroTier node core
-	EthernetTapFactory *tapFactory;
-	SocketManager *sm;
+	// This is set externally to an instance of this base class if netconf functionality is enabled
 	NetworkConfigMaster *netconfMaster;
 
 	/*
@@ -121,14 +90,12 @@ public:
 
 	Logger *log; // null if logging is disabled
 	CMWC4096 *prng;
-	HttpClient *http;
 	Switch *sw;
 	Multicaster *mc;
 	AntiRecursion *antiRec;
 	Topology *topology;
 	NodeConfig *nc;
 	Node *node;
-	SoftwareUpdater *updater; // null if software updates are not enabled
 };
 
 } // namespace ZeroTier

+ 0 - 1
objects.mk

@@ -15,7 +15,6 @@ OBJS=\
 	node/Network.o \
 	node/NetworkConfig.o \
 	node/Node.o \
-	node/NodeConfig.o \
 	node/OutboundMulticast.o \
 	node/Packet.o \
 	node/Peer.o \

+ 22 - 0
osdep/SoftwareUpdater.hpp

@@ -38,6 +38,28 @@
 #include "Defaults.hpp"
 #include "Address.hpp"
 
+/**
+ * Delay between fetches of the root topology update URL
+ *
+ * 86400000 = check once every 24 hours (this doesn't change often)
+ */
+#define ZT_UPDATE_ROOT_TOPOLOGY_CHECK_INTERVAL 86400000
+
+/**
+ * Minimum interval between attempts to do a software update
+ */
+#define ZT_UPDATE_MIN_INTERVAL 120000
+
+/**
+ * Maximum interval between checks for new versions
+ */
+#define ZT_UPDATE_MAX_INTERVAL 7200000
+
+/**
+ * Software update HTTP timeout in seconds
+ */
+#define ZT_UPDATE_HTTP_TIMEOUT 120
+
 namespace ZeroTier {
 
 class RuntimeEnvironment;