Whole heap more cleanup and refactoring...

This commit is contained in:
Adam Ierymenko 2015-03-31 17:53:34 -07:00
parent 647ce82b86
commit 36eab4f1a9
14 changed files with 575 additions and 770 deletions

View file

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

View file

@ -299,16 +299,21 @@
*/ */
#define ZT_STARTUP_AGGRO (ZT_PING_UNANSWERED_AFTER * 2) #define ZT_STARTUP_AGGRO (ZT_PING_UNANSWERED_AFTER * 2)
/**
* How long since last message from an authoritative upstream peer before we increment our desperation level?
*/
#define ZT_DESPERATION_INCREMENT (ZT_STARTUP_AGGRO * 2)
/**
* "Spam" packets to lower desperation links every Nth packet
*/
#define ZT_DESPERATION_SPAM_EVERY 10
/** /**
* Maximum delay between runs of the main loop in Node.cpp * Maximum delay between runs of the main loop in Node.cpp
*/ */
#define ZT_MAX_SERVICE_LOOP_INTERVAL ZT_STARTUP_AGGRO #define ZT_MAX_SERVICE_LOOP_INTERVAL ZT_STARTUP_AGGRO
/**
* Try TCP tunnels if nothing received for this long
*/
#define ZT_TCP_TUNNEL_FAILOVER_TIMEOUT (ZT_STARTUP_AGGRO * 5)
/** /**
* Timeout for overall peer activity (measured from last receive) * Timeout for overall peer activity (measured from last receive)
*/ */
@ -319,11 +324,6 @@
*/ */
#define ZT_PEER_PATH_ACTIVITY_TIMEOUT ZT_PEER_ACTIVITY_TIMEOUT #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 * 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) #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 * Sanity limit on maximum bridge routes
* *

View file

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

View file

@ -35,39 +35,20 @@
#include <string> #include <string>
#include "Constants.hpp" #include "Constants.hpp"
#include "../include/ZeroTierOne.h"
#include "Utils.hpp" #include "Utils.hpp"
#include "MAC.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 { 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) * Loopback IPv4 address (no port)
*/ */
@ -88,9 +69,16 @@ public:
*/ */
static const InetAddress DEFAULT6; static const InetAddress DEFAULT6;
InetAddress() throw() { memset(&_sa,0,sizeof(_sa)); } InetAddress() throw() { memset(this,0,sizeof(InetAddress)); }
InetAddress(const InetAddress &a) throw() { memcpy(&_sa,&a._sa,sizeof(_sa)); } InetAddress(const InetAddress &a) throw() { memcpy(this,&a,sizeof(InetAddress)); }
InetAddress(const struct sockaddr *sa) throw() { this->set(sa); } 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 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 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); } InetAddress(const std::string &ip,unsigned int port) throw() { this->set(ip,port); }
@ -100,23 +88,84 @@ public:
inline InetAddress &operator=(const InetAddress &a) inline InetAddress &operator=(const InetAddress &a)
throw() throw()
{ {
memcpy(&_sa,&a._sa,sizeof(_sa)); memcpy(this,&a,sizeof(InetAddress));
return *this; return *this;
} }
/** inline InetAddress &operator=(const struct sockaddr_storage &ss)
* Set from an OS-level sockaddr structure
*
* @param sa Socket address (V4 or V6)
*/
inline void set(const struct sockaddr *sa)
throw() throw()
{ {
switch(sa->sa_family) { memcpy(this,&ss,sizeof(InetAddress));
case AF_INET: memcpy(&_sa.sin,sa,sizeof(struct sockaddr_in)); break; return *this;
case AF_INET6: memcpy(&_sa.sin6,sa,sizeof(struct sockaddr_in6)); break; }
default: memset(&_sa,0,sizeof(_sa)); break;
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(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) inline void setPort(unsigned int port)
throw() throw()
{ {
if (_sa.saddr.sa_family == AF_INET) switch(ss_family) {
_sa.sin.sin_port = Utils::hton((uint16_t)port); case AF_INET:
else if (_sa.saddr.sa_family == AF_INET6) reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton((uint16_t)port);
_sa.sin6.sin6_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,45 +211,35 @@ public:
bool isLinkLocal() const bool isLinkLocal() const
throw(); 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 * @return True if this is a loopback address
*/ */
inline bool isLoopback() const inline bool isLoopback() const throw() { return ((*this == LO4)||(*this == LO6)); }
throw()
{
return ((*this == LO4)||(*this == LO6));
}
/** /**
* @return ASCII IP/port format representation * @return ASCII IP/port format representation
*/ */
std::string toString() const; std::string toString() const;
/**
* @param ipSlashPort ASCII IP/port format notation
*/
void fromString(const std::string &ipSlashPort);
/** /**
* @return IP portion only, in ASCII string format * @return IP portion only, in ASCII string format
*/ */
std::string toIpString() const; std::string toIpString() const;
/**
* @param ipSlashPort ASCII IP/port format notation
*/
void fromString(const std::string &ipSlashPort);
/** /**
* @return Port or 0 if no port component defined * @return Port or 0 if no port component defined
*/ */
inline unsigned int port() const inline unsigned int port() const
throw() throw()
{ {
switch(_sa.saddr.sa_family) { switch(ss_family) {
case AF_INET: return Utils::ntoh((uint16_t)_sa.sin.sin_port); 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)_sa.sin6.sin6_port); case AF_INET6: return Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_port));
default: return 0; default: return 0;
} }
} }
@ -229,33 +272,22 @@ public:
/** /**
* @return True if this is an IPv4 address * @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 * @return True if this is an IPv6 address
*/ */
inline bool isV6() const throw() { return (_sa.saddr.sa_family == AF_INET6); } inline bool isV6() const throw() { return (ss_family == AF_INET6); }
/**
* @return Address type or TYPE_NULL if not defined
*/
inline AddressType type() const throw() { return (AddressType)_sa.saddr.sa_family; }
/** /**
* Force type to IPv4 * 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 * Force type to IPv6
*/ */
inline void setV6() throw() { _sa.saddr.sa_family = AF_INET6; } inline void setV6() throw() { ss_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); }
/** /**
* @return Length of sockaddr_in if IPv4, sockaddr_in6 if IPv6 * @return Length of sockaddr_in if IPv4, sockaddr_in6 if IPv6
@ -263,99 +295,62 @@ public:
inline unsigned int saddrLen() const inline unsigned int saddrLen() const
throw() throw()
{ {
switch(_sa.saddr.sa_family) { switch(ss_family) {
case AF_INET: return sizeof(struct sockaddr_in); case AF_INET: return sizeof(struct sockaddr_in);
case AF_INET6: return sizeof(struct sockaddr_in6); case AF_INET6: return sizeof(struct sockaddr_in6);
default: return 0; 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) * @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) * @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
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
throw() throw()
{ {
if (_sa.saddr.sa_family == a._sa.saddr.sa_family) { switch(ss_family) {
switch(_sa.saddr.sa_family) { case AF_INET: return (const void *)&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
case AF_INET: case AF_INET6: return (const void *)(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
return (_sa.sin.sin_addr.s_addr == a._sa.sin.sin_addr.s_addr); default: return 0;
case AF_INET6:
return (!memcmp(_sa.sin6.sin6_addr.s6_addr,a._sa.sin6.sin6_addr.s6_addr,16));
}
} }
return false;
} }
/** /**
* Compare IP/netmask with another IP/netmask * @return pointer to raw IP address bytes
*
* @param ipnet IP/netmask to compare with
* @return True if [netmask] bits match
*/ */
bool sameNetworkAs(const InetAddress &ipnet) const inline void *rawIpData()
throw(); throw()
{
/** switch(ss_family) {
* Determine whether this address is within an ip/netmask 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);
* @param ipnet IP/netmask default: return 0;
* @return True if this address is within this network }
*/ }
bool within(const InetAddress &ipnet) const
throw();
/** /**
* Set to null/zero * 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 * @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); } 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 !(a < *this); } inline bool operator<=(const InetAddress &a) const throw() { return !(a < *this); }
inline bool operator>=(const InetAddress &a) const throw() { return !(*this < a); } inline bool operator>=(const InetAddress &a) const throw() { return !(*this < a); }
@ -366,13 +361,6 @@ public:
*/ */
static InetAddress makeIpv6LinkLocal(const MAC &mac) static InetAddress makeIpv6LinkLocal(const MAC &mac)
throw(); throw();
private:
union {
struct sockaddr saddr;
struct sockaddr_in sin;
struct sockaddr_in6 sin6;
} _sa;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -71,6 +71,13 @@ public:
MAC(const Address &ztaddr,uint64_t nwid) throw() { fromAddress(ztaddr,nwid); } 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 * Set MAC to zero
*/ */

30
node/Node.cpp Normal file
View file

@ -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
node/Node.hpp Normal file
View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -41,12 +41,8 @@ class Switch;
class Topology; class Topology;
class CMWC4096; class CMWC4096;
class Node; class Node;
class SoftwareUpdater;
class SocketManager;
class Multicaster; class Multicaster;
class AntiRecursion; class AntiRecursion;
class EthernetTapFactory;
class HttpClient;
class NetworkConfigMaster; class NetworkConfigMaster;
/** /**
@ -65,50 +61,23 @@ class RuntimeEnvironment
{ {
public: public:
RuntimeEnvironment() : RuntimeEnvironment() :
homePath(),
identity(), identity(),
initialized(false),
tcpTunnelingEnabled(false),
timeOfLastResynchronize(0),
timeOfLastPacketReceived(0),
tapFactory((EthernetTapFactory *)0),
sm((SocketManager *)0),
netconfMaster((NetworkConfigMaster *)0), netconfMaster((NetworkConfigMaster *)0),
log((Logger *)0), log((Logger *)0),
prng((CMWC4096 *)0), prng((CMWC4096 *)0),
http((HttpClient *)0),
sw((Switch *)0), sw((Switch *)0),
mc((Multicaster *)0), mc((Multicaster *)0),
antiRec((AntiRecursion *)0), antiRec((AntiRecursion *)0),
topology((Topology *)0), topology((Topology *)0),
nc((NodeConfig *)0), nc((NodeConfig *)0),
node((Node *)0), node((Node *)0)
updater((SoftwareUpdater *)0)
{ {
} }
// Full path to home folder
std::string homePath;
// This node's identity // This node's identity
Identity identity; Identity identity;
// Are we initialized? // This is set externally to an instance of this base class if netconf functionality is enabled
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;
NetworkConfigMaster *netconfMaster; NetworkConfigMaster *netconfMaster;
/* /*
@ -121,14 +90,12 @@ public:
Logger *log; // null if logging is disabled Logger *log; // null if logging is disabled
CMWC4096 *prng; CMWC4096 *prng;
HttpClient *http;
Switch *sw; Switch *sw;
Multicaster *mc; Multicaster *mc;
AntiRecursion *antiRec; AntiRecursion *antiRec;
Topology *topology; Topology *topology;
NodeConfig *nc; NodeConfig *nc;
Node *node; Node *node;
SoftwareUpdater *updater; // null if software updates are not enabled
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

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

View file

@ -38,6 +38,28 @@
#include "Defaults.hpp" #include "Defaults.hpp"
#include "Address.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 { namespace ZeroTier {
class RuntimeEnvironment; class RuntimeEnvironment;