This commit is contained in:
Adam Ierymenko 2020-01-08 18:08:41 -08:00
parent 263798d1c3
commit 9642ff5fb9
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
21 changed files with 502 additions and 760 deletions

View file

@ -19,7 +19,11 @@
#ifndef ZT_ZEROTIER_API_H
#define ZT_ZEROTIER_API_H
#ifdef __cplusplus
#include <cstdint>
#else
#include <stdint.h>
#endif
/* For struct sockaddr_storage, which is referenced here. */
#if defined(_WIN32) || defined(_WIN64)
@ -513,45 +517,6 @@ enum ZT_Event
ZT_EVENT_REMOTE_TRACE = 7
};
/**
* A root server
*/
typedef struct {
/**
* Name of root
*
* This will be a DNS name for dynamic roots. For static roots
* it will be the ZeroTier address. The presence or absence
* of a dot is used internally as a distinguisher.
*/
const char *name;
/**
* Serialized locator
*/
const void *locator;
/**
* The size of locator in bytes
*/
unsigned int locatorSize;
} ZT_Root;
/**
* List of root servers
*/
typedef struct {
/**
* Number of root servers
*/
unsigned int count;
/**
* Array of root servers
*/
ZT_Root roots[];
} ZT_RootList;
/**
* Payload of REMOTE_TRACE event
*/
@ -1010,29 +975,6 @@ enum ZT_PeerRole
ZT_PEER_ROLE_PLANET = 2 // planetary root
};
/**
* DNS record types for reporting DNS results
*
* These integer IDs (other than end of results) are the same as the DNS protocol's
* internal IDs. Not all of these are used by ZeroTier, and not all DNS record types
* are listed here. These are just common ones that are used now or may be used in
* the future for some purpose.
*/
enum ZT_DNSRecordType
{
ZT_DNS_RECORD__END_OF_RESULTS = 0,
ZT_DNS_RECORD_A = 1,
ZT_DNS_RECORD_NS = 2,
ZT_DNS_RECORD_CNAME = 5,
ZT_DNS_RECORD_PTR = 12,
ZT_DNS_RECORD_MX = 15,
ZT_DNS_RECORD_TXT = 16,
ZT_DNS_RECORD_AAAA = 28,
ZT_DNS_RECORD_LOC = 29,
ZT_DNS_RECORD_SRV = 33,
ZT_DNS_RECORD_DNAME = 39
};
/**
* Virtual network configuration
*/
@ -1541,8 +1483,9 @@ typedef int (*ZT_PathCheckFunction)(
* (1) Node
* (2) User pointer
* (3) ZeroTier address (least significant 40 bits)
* (4) Desired address family or -1 for any
* (5) Buffer to fill with result
* (4) Identity in string form
* (5) Desired address family or -1 for any
* (6) Buffer to fill with result
*
* If provided this function will be occasionally called to get physical
* addresses that might be tried to reach a ZeroTier address. It must
@ -1554,53 +1497,10 @@ typedef int (*ZT_PathLookupFunction)(
void *, /* User ptr */
void *, /* Thread ptr */
uint64_t, /* ZeroTier address (40 bits) */
const char *, /* Identity in string form */
int, /* Desired ss_family or -1 for any */
struct sockaddr_storage *); /* Result buffer */
/**
* Function to request an asynchronous DNS TXT lookup
*
* Parameters:
* (1) Node
* (2) User pointer
* (3) Thread pointer
* (4) Array of DNS record types we want
* (5) Number of DNS record types in array
* (6) DNS name to fetch
* (7) DNS request ID to supply to ZT_Node_processDNSResult()
*
* DNS is not handled in the core because every platform and runtime
* typically has its own DNS functions or libraries and these may need
* to interface with OS or network services in your local environment.
* Instead this function and its result submission counterpart are
* provided so you can provide a DNS implementation.
*
* If this callback is set in your callback struct to a NULL value,
* DNS will not be available. The ZeroTier protocol is designed to
* work in the absence of DNS but you may not get optimal results. For
* example you may default to root servers that are not geographically
* optimal or your node may cease to function if a root server's IP
* changes and there's no way to signal this.
*
* This function requests resolution of a DNS record. The result
* submission method ZT_Node_processDNSResult() must be called at
* least once in response. See its documentation.
*
* Right now ZeroTier only requests resolution of TXT records, but
* it's possible that this will change in the future.
*
* It's safe to call processDNSResult() from within your handler
* for this function.
*/
typedef void (*ZT_DNSResolver)(
ZT_Node *, /* Node */
void *, /* User ptr */
void *, /* Thread ptr */
const enum ZT_DNSRecordType *, /* DNS record type(s) to fetch */
unsigned int, /* Number of DNS record type(s) */
const char *, /* DNS name to fetch */
uintptr_t); /* Request ID for returning results */
/****************************************************************************/
/* C Node API */
/****************************************************************************/
@ -1640,11 +1540,6 @@ struct ZT_Node_Callbacks
*/
ZT_EventCallback eventCallback;
/**
* STRONGLY RECOMMENDED: Function to request a DNS lookup
*/
ZT_DNSResolver dnsResolver;
/**
* OPTIONAL: Function to check whether a given physical path should be used
*/
@ -1750,60 +1645,6 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_processBackgroundTasks(
int64_t now,
volatile int64_t *nextBackgroundTaskDeadline);
/**
* Submit the result(s) of a requested DNS query
*
* This MUST be called at least once after the node requsts DNS resolution.
* If there are no results or DNS is not implemented or available, just
* send one ZT_DNS_RECORD__END_OF_RESULTS to signal that no results were
* obtained.
*
* If result is non-NULL but resultLength is zero then result is assumed to
* be a C string terminated by a zero. Passing an unterminated string with a
* zero resultLength will result in a crash.
*
* The results of A and AAAA records can be returned as either strings or
* binary IP address bytes (network byte order). If the result is a string,
* resultLength must be 0 to signal that result is a C string. Otherwise for
* A resultLength must be 4 and for AAAA it must be 16 if the result is
* in binary format.
*
* The Node implementation makes an effort to ignore obviously invalid
* submissions like an AAAA record in bianry form with length 25, but this
* is not guaranteed. It's possible to crash your program by calling this
* with garbage inputs.
*
* Results may be submitted in any order and order should not be assumed
* to have any meaning.
*
* The ZT_DNS_RECORD__END_OF_RESULTS pseudo-response must be sent after all
* results have been submitted. The result and resultLength paramters are
* ignored for this type ID.
*
* It is safe to call this function from inside the DNS request callback,
* such as to return a locally cached result or a result from some kind
* of local database. It's also safe to call this function from threads
* other than the one that received the DNS request.
*
* @param node Node instance that requested DNS resolution
* @param tptr Thread pointer to pass to functions/callbacks resulting from this call
* @param dnsRequestID Request ID supplied to DNS request callback
* @param name DNS name
* @param recordType Record type of this result
* @param result Result (content depends on record type)
* @param resultLength Length of result
* @param resultIsString If non-zero, IP results for A and AAAA records are being given as C strings not binary IPs
*/
ZT_SDK_API void ZT_Node_processDNSResult(
ZT_Node *node,
void *tptr,
uintptr_t dnsRequestID,
const char *name,
enum ZT_DNSRecordType recordType,
const void *result,
unsigned int resultLength,
int resultIsString);
/**
* Join a network
*
@ -1884,36 +1725,25 @@ ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastSubscribe(ZT_Node *node,void *tpt
ZT_SDK_API enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
/**
* List roots for this node
* Add a root server (has no effect if already added)
*
* @param node Node instance
* @param now Current time
* @return List of roots, use ZT_Node_freeQueryResult to free this when done
* @param identity Identity of this root server in string format
* @return OK (0) or error code if a fatal error condition has occurred
*/
ZT_SDK_API ZT_RootList *ZT_Node_listRoots(ZT_Node *node,int64_t now);
ZT_SDK_API enum ZT_ResultCode ZT_Node_addRoot(ZT_Node *node,const char *identity);
/**
* Add or update a root
* Remove a root server
*
* The node will begin trying to resolve the DNS TXT record for
* this root and possibly obtain it from other peers.
* This removes this node's root designation but does not prevent this node
* from communicating with it or close active paths to it.
*
* @param node Node instance
* @param name DNS name or simply the address in hex form for static roots
* @param locator Binary-serialized locator of NULL if none
* @param locatorSize Size of locator or 0 if none
* @return OK (0) or error code
* @param identity Identity in string format
* @return OK (0) or error code if a fatal error condition has occurred
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_setRoot(ZT_Node *node,const char *name,const void *locator,unsigned int locatorSize);
/**
* Remove a dynamic root
*
* @param node Node instance
* @param name DNS name of this dynamic root or the address in hex form for static roots
* @return OK (0) or error code
*/
ZT_SDK_API enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node,const char *name);
ZT_SDK_API enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node,const char *identity);
/**
* Get this node's 40-bit ZeroTier address

View file

@ -37,9 +37,9 @@
#define ZT_ADDRESS_RESERVED_PREFIX 0xff
/**
* Maximum DNS or URL name size for an Endpoint (set so that max marshaled endpoint size is 128 bytes)
* Maximum DNS or URL name size for an Endpoint (set so that max marshaled endpoint size is 64 bytes)
*/
#define ZT_ENDPOINT_MAX_NAME_SIZE 124
#define ZT_ENDPOINT_MAX_NAME_SIZE 61
/**
* Size of an identity hash (SHA384)

View file

@ -60,13 +60,13 @@ static EccPoint curve_G = CONCAT(Curve_G_, ECC_CURVE);
static uint64_t curve_n[NUM_ECC_DIGITS] = CONCAT(Curve_N_, ECC_CURVE);
// Use ZeroTier's secure PRNG
static inline int getRandomNumber(uint64_t *p_vli)
static ZT_ALWAYS_INLINE int getRandomNumber(uint64_t *p_vli)
{
Utils::getSecureRandom(p_vli,ECC_BYTES);
return 1;
}
static inline void vli_clear(uint64_t *p_vli)
static ZT_ALWAYS_INLINE void vli_clear(uint64_t *p_vli)
{
uint i;
for(i=0; i<NUM_ECC_DIGITS; ++i)
@ -76,7 +76,7 @@ static inline void vli_clear(uint64_t *p_vli)
}
/* Returns 1 if p_vli == 0, 0 otherwise. */
static inline int vli_isZero(uint64_t *p_vli)
static ZT_ALWAYS_INLINE int vli_isZero(uint64_t *p_vli)
{
uint i;
for(i = 0; i < NUM_ECC_DIGITS; ++i)
@ -90,13 +90,13 @@ static inline int vli_isZero(uint64_t *p_vli)
}
/* Returns nonzero if bit p_bit of p_vli is set. */
static inline uint64_t vli_testBit(uint64_t *p_vli, uint p_bit)
static ZT_ALWAYS_INLINE uint64_t vli_testBit(uint64_t *p_vli, uint p_bit)
{
return (p_vli[p_bit/64] & ((uint64_t)1 << (p_bit % 64)));
}
/* Counts the number of 64-bit "digits" in p_vli. */
static inline uint vli_numDigits(uint64_t *p_vli)
static ZT_ALWAYS_INLINE uint vli_numDigits(uint64_t *p_vli)
{
int i;
/* Search from the end until we find a non-zero digit.
@ -109,7 +109,7 @@ static inline uint vli_numDigits(uint64_t *p_vli)
}
/* Counts the number of bits required for p_vli. */
static inline uint vli_numBits(uint64_t *p_vli)
static ZT_ALWAYS_INLINE uint vli_numBits(uint64_t *p_vli)
{
uint i;
uint64_t l_digit;
@ -130,7 +130,7 @@ static inline uint vli_numBits(uint64_t *p_vli)
}
/* Sets p_dest = p_src. */
static inline void vli_set(uint64_t *p_dest, uint64_t *p_src)
static ZT_ALWAYS_INLINE void vli_set(uint64_t *p_dest, uint64_t *p_src)
{
uint i;
for(i=0; i<NUM_ECC_DIGITS; ++i)
@ -464,7 +464,7 @@ static inline void vli_mmod_fast(uint64_t *p_result, uint64_t *p_product)
//#endif
/* Computes p_result = (p_left * p_right) % curve_p. */
static inline void vli_modMult_fast(uint64_t *p_result, uint64_t *p_left, uint64_t *p_right)
static ZT_ALWAYS_INLINE void vli_modMult_fast(uint64_t *p_result, uint64_t *p_left, uint64_t *p_right)
{
uint64_t l_product[2 * NUM_ECC_DIGITS];
vli_mult(l_product, p_left, p_right);
@ -472,7 +472,7 @@ static inline void vli_modMult_fast(uint64_t *p_result, uint64_t *p_left, uint64
}
/* Computes p_result = p_left^2 % curve_p. */
static inline void vli_modSquare_fast(uint64_t *p_result, uint64_t *p_left)
static ZT_ALWAYS_INLINE void vli_modSquare_fast(uint64_t *p_result, uint64_t *p_left)
{
uint64_t l_product[2 * NUM_ECC_DIGITS];
vli_square(l_product, p_left);
@ -576,7 +576,7 @@ static inline void vli_modInv(uint64_t *p_result, uint64_t *p_input, uint64_t *p
/* ------ Point operations ------ */
/* Returns 1 if p_point is the point at infinity, 0 otherwise. */
static inline int EccPoint_isZero(EccPoint *p_point)
static ZT_ALWAYS_INLINE int EccPoint_isZero(EccPoint *p_point)
{
return (vli_isZero(p_point->x) && vli_isZero(p_point->y));
}
@ -635,7 +635,7 @@ static inline void EccPoint_double_jacobian(uint64_t *X1, uint64_t *Y1, uint64_t
}
/* Modify (x1, y1) => (x1 * z^2, y1 * z^3) */
static inline void apply_z(uint64_t *X1, uint64_t *Y1, uint64_t *Z)
static ZT_ALWAYS_INLINE void apply_z(uint64_t *X1, uint64_t *Y1, uint64_t *Z)
{
uint64_t t1[NUM_ECC_DIGITS];
@ -772,7 +772,7 @@ static inline void EccPoint_mult(EccPoint *p_result, EccPoint *p_point, uint64_t
vli_set(p_result->y, Ry[0]);
}
static inline void ecc_bytes2native(uint64_t p_native[NUM_ECC_DIGITS], const uint8_t p_bytes[ECC_BYTES])
static ZT_ALWAYS_INLINE void ecc_bytes2native(uint64_t p_native[NUM_ECC_DIGITS], const uint8_t p_bytes[ECC_BYTES])
{
unsigned i;
for(i=0; i<NUM_ECC_DIGITS; ++i)
@ -783,7 +783,7 @@ static inline void ecc_bytes2native(uint64_t p_native[NUM_ECC_DIGITS], const uin
}
}
static inline void ecc_native2bytes(uint8_t p_bytes[ECC_BYTES], const uint64_t p_native[NUM_ECC_DIGITS])
static ZT_ALWAYS_INLINE void ecc_native2bytes(uint8_t p_bytes[ECC_BYTES], const uint64_t p_native[NUM_ECC_DIGITS])
{
unsigned i;
for(i=0; i<NUM_ECC_DIGITS; ++i)
@ -961,7 +961,7 @@ static inline void vli_modMult(uint64_t *p_result, uint64_t *p_left, uint64_t *p
vli_set(p_result, l_product);
}
static inline uint umax(uint a, uint b)
static ZT_ALWAYS_INLINE uint umax(uint a, uint b)
{
return (a > b ? a : b);
}

View file

@ -24,7 +24,7 @@
#include "Address.hpp"
#include "Utils.hpp"
#define ZT_ENDPOINT_MARSHAL_SIZE_MAX (ZT_ENDPOINT_MAX_NAME_SIZE+4)
#define ZT_ENDPOINT_MARSHAL_SIZE_MAX (ZT_ENDPOINT_MAX_NAME_SIZE+3)
namespace ZeroTier {
@ -46,10 +46,10 @@ public:
ZT_ALWAYS_INLINE Endpoint() { memset(reinterpret_cast<void *>(this),0,sizeof(Endpoint)); }
ZT_ALWAYS_INLINE Endpoint(const InetAddress &sa) : _t(INETADDR) { _v.sa = sa; }
explicit ZT_ALWAYS_INLINE Endpoint(const InetAddress &sa) : _t(INETADDR) { _v.sa = sa; }
ZT_ALWAYS_INLINE Endpoint(const Address &zt,const uint8_t identityHash[ZT_IDENTITY_HASH_SIZE]) : _t(ZEROTIER) { _v.zt.a = zt.toInt(); memcpy(_v.zt.idh,identityHash,ZT_IDENTITY_HASH_SIZE); }
ZT_ALWAYS_INLINE Endpoint(const char *name,const int port) : _t(DNSNAME) { Utils::scopy(_v.dns.name,sizeof(_v.dns.name),name); _v.dns.port = port; }
ZT_ALWAYS_INLINE Endpoint(const char *url) : _t(URL) { Utils::scopy(_v.url,sizeof(_v.url),url); }
explicit ZT_ALWAYS_INLINE Endpoint(const char *url) : _t(URL) { Utils::scopy(_v.url,sizeof(_v.url),url); }
ZT_ALWAYS_INLINE const InetAddress *sockaddr() const { return (_t == INETADDR) ? reinterpret_cast<const InetAddress *>(&_v.sa) : nullptr; }
ZT_ALWAYS_INLINE const char *dnsName() const { return (_t == DNSNAME) ? _v.dns.name : nullptr; }
@ -61,6 +61,45 @@ public:
ZT_ALWAYS_INLINE Type type() const { return _t; }
ZT_ALWAYS_INLINE bool operator==(const Endpoint &ep) const
{
if (_t == ep._t) {
switch(_t) {
case INETADDR: return (*sockaddr() == *ep.sockaddr());
case DNSNAME: return ((_v.dns.port == ep._v.dns.port)&&(strcmp(_v.dns.name,ep._v.dns.name) == 0));
case ZEROTIER: return ((_v.zt.a == ep._v.zt.a)&&(memcmp(_v.zt.idh,ep._v.zt.idh,sizeof(_v.zt.idh)) == 0));
case URL: return (strcmp(_v.url,ep._v.url) == 0);
case ETHERNET: return (_v.eth == ep._v.eth);
default: return true;
}
}
return false;
}
ZT_ALWAYS_INLINE bool operator!=(const Endpoint &ep) const { return (!(*this == ep)); }
ZT_ALWAYS_INLINE bool operator<(const Endpoint &ep) const
{
if ((int)_t < (int)ep._t) {
return true;
} else if (_t == ep._t) {
int ncmp;
switch(_t) {
case INETADDR: return (*sockaddr() < *ep.sockaddr());
case DNSNAME:
ncmp = strcmp(_v.dns.name,ep._v.dns.name);
return ((ncmp < 0) ? true : (ncmp == 0)&&(_v.dns.port < ep._v.dns.port));
case ZEROTIER: return (_v.zt.a < ep._v.zt.a) ? true : ((_v.zt.a == ep._v.zt.a)&&(memcmp(_v.zt.idh,ep._v.zt.idh,sizeof(_v.zt.idh)) < 0));
case URL: return (strcmp(_v.url,ep._v.url) < 0);
case ETHERNET: return (_v.eth < ep._v.eth);
default: return false;
}
}
return false;
}
ZT_ALWAYS_INLINE bool operator>(const Endpoint &ep) const { return (ep < *this); }
ZT_ALWAYS_INLINE bool operator<=(const Endpoint &ep) const { return !(ep < *this); }
ZT_ALWAYS_INLINE bool operator>=(const Endpoint &ep) const { return !(*this < ep); }
// Marshal interface ///////////////////////////////////////////////////////
static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_ENDPOINT_MARSHAL_SIZE_MAX; }
inline int marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const
{
@ -79,16 +118,16 @@ public:
if (p == (ZT_ENDPOINT_MAX_NAME_SIZE+1))
return -1;
}
data[p++] = (uint8_t)((_v.dns.port >> 8) & 0xff);
data[p++] = (uint8_t)(_v.dns.port & 0xff);
data[p++] = (uint8_t)(_v.dns.port >> 8U);
data[p++] = (uint8_t)_v.dns.port;
return p;
case ZEROTIER:
data[0] = (uint8_t)ZEROTIER;
data[1] = (uint8_t)((_v.zt.a >> 32) & 0xff);
data[2] = (uint8_t)((_v.zt.a >> 24) & 0xff);
data[3] = (uint8_t)((_v.zt.a >> 16) & 0xff);
data[4] = (uint8_t)((_v.zt.a >> 8) & 0xff);
data[5] = (uint8_t)(_v.zt.a & 0xff);
data[1] = (uint8_t)(_v.zt.a >> 32U);
data[2] = (uint8_t)(_v.zt.a >> 24U);
data[3] = (uint8_t)(_v.zt.a >> 16U);
data[4] = (uint8_t)(_v.zt.a >> 8U);
data[5] = (uint8_t)_v.zt.a;
memcpy(data + 6,_v.zt.idh,ZT_IDENTITY_HASH_SIZE);
return (ZT_IDENTITY_HASH_SIZE + 6);
case URL:
@ -104,12 +143,12 @@ public:
return p;
case ETHERNET:
data[0] = (uint8_t)ETHERNET;
data[1] = (uint8_t)((_v.eth >> 40) & 0xff);
data[2] = (uint8_t)((_v.eth >> 32) & 0xff);
data[3] = (uint8_t)((_v.eth >> 24) & 0xff);
data[4] = (uint8_t)((_v.eth >> 16) & 0xff);
data[5] = (uint8_t)((_v.eth >> 8) & 0xff);
data[6] = (uint8_t)(_v.eth & 0xff);
data[1] = (uint8_t)(_v.eth >> 40U);
data[2] = (uint8_t)(_v.eth >> 32U);
data[3] = (uint8_t)(_v.eth >> 24U);
data[4] = (uint8_t)(_v.eth >> 16U);
data[5] = (uint8_t)(_v.eth >> 8U);
data[6] = (uint8_t)_v.eth;
return 7;
default:
data[0] = (uint8_t)NIL;
@ -142,17 +181,17 @@ public:
if ((p >= (ZT_ENDPOINT_MAX_NAME_SIZE+1))||(p >= (len-2)))
return -1;
}
_v.dns.port = ((int)data[p++]) << 8;
_v.dns.port |= (int)data[p++];
_v.dns.port = (uint16_t)(((unsigned int)data[p++]) << 8U);
_v.dns.port |= (uint16_t)data[p++];
return p;
case ZEROTIER:
if (len < (ZT_IDENTITY_HASH_SIZE + 6))
return -1;
_t = ZEROTIER;
_v.zt.a = ((uint64_t)data[1]) << 32;
_v.zt.a |= ((uint64_t)data[2]) << 24;
_v.zt.a |= ((uint64_t)data[3]) << 16;
_v.zt.a |= ((uint64_t)data[4]) << 8;
_v.zt.a = ((uint64_t)data[1]) << 32U;
_v.zt.a |= ((uint64_t)data[2]) << 24U;
_v.zt.a |= ((uint64_t)data[3]) << 16U;
_v.zt.a |= ((uint64_t)data[4]) << 8U;
_v.zt.a |= (uint64_t)data[5];
memcpy(_v.zt.idh,data + 6,ZT_IDENTITY_HASH_SIZE);
return (ZT_IDENTITY_HASH_SIZE + 6);
@ -175,16 +214,17 @@ public:
if (len < 7)
return -1;
_t = ZEROTIER;
_v.eth = ((uint64_t)data[1]) << 40;
_v.eth |= ((uint64_t)data[2]) << 32;
_v.eth |= ((uint64_t)data[3]) << 24;
_v.eth |= ((uint64_t)data[4]) << 16;
_v.eth |= ((uint64_t)data[5]) << 8;
_v.eth = ((uint64_t)data[1]) << 40U;
_v.eth |= ((uint64_t)data[2]) << 32U;
_v.eth |= ((uint64_t)data[3]) << 24U;
_v.eth |= ((uint64_t)data[4]) << 16U;
_v.eth |= ((uint64_t)data[5]) << 8U;
_v.eth |= (uint64_t)data[6];
return 7;
}
return false;
}
////////////////////////////////////////////////////////////////////////////
private:
Type _t;
@ -192,7 +232,7 @@ private:
struct sockaddr_storage sa;
struct {
char name[ZT_ENDPOINT_MAX_NAME_SIZE];
int port;
uint16_t port;
} dns;
struct {
uint64_t a;

View file

@ -368,7 +368,7 @@ public:
/**
* @return True if this identity contains something
*/
ZT_ALWAYS_INLINE operator bool() const { return (_address); }
explicit ZT_ALWAYS_INLINE operator bool() const { return (_address); }
ZT_ALWAYS_INLINE bool operator==(const Identity &id) const
{
@ -407,7 +407,7 @@ public:
// Marshal interface ///////////////////////////////////////////////////////
static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_IDENTITY_MARSHAL_SIZE_MAX; }
inline int marshal(uint8_t restrict data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool includePrivate = false) const
inline int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool includePrivate = false) const
{
_address.copyTo(data,ZT_ADDRESS_LENGTH);
switch(_type) {

View file

@ -11,11 +11,8 @@
*/
/****/
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <string>
#include <cstring>
#include <cstdint>
#include "Constants.hpp"
#include "InetAddress.hpp"
@ -33,20 +30,20 @@ InetAddress::IpScope InetAddress::ipScope() const
case AF_INET: {
const uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
switch(ip >> 24) {
switch(ip >> 24U) {
case 0x00: return IP_SCOPE_NONE; // 0.0.0.0/8 (reserved, never used)
case 0x06: return IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army)
case 0x0a: return IP_SCOPE_PRIVATE; // 10.0.0.0/8
case 0x0b: return IP_SCOPE_PSEUDOPRIVATE; // 11.0.0.0/8 (US DoD)
case 0x15: return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN)
case 0x16: return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA)
case 0x19: return IP_SCOPE_PSEUDOPRIVATE; // 25.0.0.0/8 (UK Ministry of Defense)
case 0x1a: return IP_SCOPE_PSEUDOPRIVATE; // 26.0.0.0/8 (US DISA)
case 0x1c: return IP_SCOPE_PSEUDOPRIVATE; // 28.0.0.0/8 (US DSI-North)
case 0x1d: return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA)
case 0x1e: return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA)
case 0x33: return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of Social Security)
case 0x37: return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD)
case 0x0b: //return IP_SCOPE_PSEUDOPRIVATE; // 11.0.0.0/8 (US DoD)
case 0x15: //return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN)
case 0x16: //return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA)
case 0x19: //return IP_SCOPE_PSEUDOPRIVATE; // 25.0.0.0/8 (UK Ministry of Defense)
case 0x1a: //return IP_SCOPE_PSEUDOPRIVATE; // 26.0.0.0/8 (US DISA)
case 0x1c: //return IP_SCOPE_PSEUDOPRIVATE; // 28.0.0.0/8 (US DSI-North)
case 0x1d: //return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA)
case 0x1e: //return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA)
case 0x33: //return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of Social Security)
case 0x37: //return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD)
case 0x38: return IP_SCOPE_PSEUDOPRIVATE; // 56.0.0.0/8 (US Postal Service)
case 0x64:
if ((ip & 0xffc00000) == 0x64400000) return IP_SCOPE_PRIVATE; // 100.64.0.0/10
@ -164,7 +161,7 @@ bool InetAddress::fromString(const char *ipSlashPort)
unsigned int port = 0;
if (*portAt) {
*(portAt++) = (char)0;
port = Utils::strToUInt(portAt) & 0xffff;
port = Utils::strToUInt(portAt) & 0xffffU;
}
if (strchr(buf,':')) {
@ -189,7 +186,7 @@ InetAddress InetAddress::netmask() const
InetAddress r(*this);
switch(r.ss_family) {
case AF_INET:
reinterpret_cast<struct sockaddr_in *>(&r)->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)(0xffffffffU << (32 - netmaskBits())));
break;
case AF_INET6: {
uint64_t nm[2];
@ -211,7 +208,7 @@ InetAddress InetAddress::broadcast() const
{
if (ss_family == AF_INET) {
InetAddress r(*this);
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffff >> netmaskBits()));
reinterpret_cast<struct sockaddr_in *>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffffU >> netmaskBits()));
return r;
}
return InetAddress();
@ -222,7 +219,7 @@ InetAddress InetAddress::network() const
InetAddress r(*this);
switch(r.ss_family) {
case AF_INET:
reinterpret_cast<struct sockaddr_in *>(&r)->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)(0xffffffffU << (32 - netmaskBits())));
break;
case AF_INET6: {
uint64_t nm[2];
@ -294,7 +291,7 @@ bool InetAddress::isNetwork() const
if (bits >= 32)
return false;
uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
return ((ip & (0xffffffff >> bits)) == 0);
return ((ip & (0xffffffffU >> bits)) == 0);
}
case AF_INET6: {
unsigned int bits = netmaskBits();
@ -304,7 +301,7 @@ bool InetAddress::isNetwork() const
return false;
const unsigned char *ip = reinterpret_cast<const unsigned char *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
unsigned int p = bits / 8;
if ((ip[p++] & (0xff >> (bits % 8))) != 0)
if ((ip[p++] & (0xffU >> (bits % 8))) != 0)
return false;
while (p < 16) {
if (ip[p++])
@ -378,48 +375,49 @@ bool InetAddress::operator<(const InetAddress &a) const
InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac)
{
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);
InetAddress r;
sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r);
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] & 0xfdU;
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 r;
}
InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress)
{
InetAddress r;
struct sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r);
sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r);
sin6->sin6_family = AF_INET6;
sin6->sin6_addr.s6_addr[0] = 0xfd;
sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 56);
sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 48);
sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 40);
sin6->sin6_addr.s6_addr[4] = (uint8_t)(nwid >> 32);
sin6->sin6_addr.s6_addr[5] = (uint8_t)(nwid >> 24);
sin6->sin6_addr.s6_addr[6] = (uint8_t)(nwid >> 16);
sin6->sin6_addr.s6_addr[7] = (uint8_t)(nwid >> 8);
sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 56U);
sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 48U);
sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 40U);
sin6->sin6_addr.s6_addr[4] = (uint8_t)(nwid >> 32U);
sin6->sin6_addr.s6_addr[5] = (uint8_t)(nwid >> 24U);
sin6->sin6_addr.s6_addr[6] = (uint8_t)(nwid >> 16U);
sin6->sin6_addr.s6_addr[7] = (uint8_t)(nwid >> 8U);
sin6->sin6_addr.s6_addr[8] = (uint8_t)nwid;
sin6->sin6_addr.s6_addr[9] = 0x99;
sin6->sin6_addr.s6_addr[10] = 0x93;
sin6->sin6_addr.s6_addr[11] = (uint8_t)(zeroTierAddress >> 32);
sin6->sin6_addr.s6_addr[12] = (uint8_t)(zeroTierAddress >> 24);
sin6->sin6_addr.s6_addr[13] = (uint8_t)(zeroTierAddress >> 16);
sin6->sin6_addr.s6_addr[14] = (uint8_t)(zeroTierAddress >> 8);
sin6->sin6_addr.s6_addr[11] = (uint8_t)(zeroTierAddress >> 32U);
sin6->sin6_addr.s6_addr[12] = (uint8_t)(zeroTierAddress >> 24U);
sin6->sin6_addr.s6_addr[13] = (uint8_t)(zeroTierAddress >> 16U);
sin6->sin6_addr.s6_addr[14] = (uint8_t)(zeroTierAddress >> 8U);
sin6->sin6_addr.s6_addr[15] = (uint8_t)zeroTierAddress;
sin6->sin6_port = Utils::hton((uint16_t)88); // /88 includes 0xfd + network ID, discriminating by device ID below that
return r;
@ -427,19 +425,19 @@ InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid,uint64_t zeroTierAddress)
InetAddress InetAddress::makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress)
{
nwid ^= (nwid >> 32);
nwid ^= (nwid >> 32U);
InetAddress r;
struct sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r);
sockaddr_in6 *const sin6 = reinterpret_cast<struct sockaddr_in6 *>(&r);
sin6->sin6_family = AF_INET6;
sin6->sin6_addr.s6_addr[0] = 0xfc;
sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24);
sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 16);
sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 8);
sin6->sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24U);
sin6->sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 16U);
sin6->sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 8U);
sin6->sin6_addr.s6_addr[4] = (uint8_t)nwid;
sin6->sin6_addr.s6_addr[5] = (uint8_t)(zeroTierAddress >> 32);
sin6->sin6_addr.s6_addr[6] = (uint8_t)(zeroTierAddress >> 24);
sin6->sin6_addr.s6_addr[7] = (uint8_t)(zeroTierAddress >> 16);
sin6->sin6_addr.s6_addr[8] = (uint8_t)(zeroTierAddress >> 8);
sin6->sin6_addr.s6_addr[5] = (uint8_t)(zeroTierAddress >> 32U);
sin6->sin6_addr.s6_addr[6] = (uint8_t)(zeroTierAddress >> 24U);
sin6->sin6_addr.s6_addr[7] = (uint8_t)(zeroTierAddress >> 16U);
sin6->sin6_addr.s6_addr[8] = (uint8_t)(zeroTierAddress >> 8U);
sin6->sin6_addr.s6_addr[9] = (uint8_t)zeroTierAddress;
sin6->sin6_addr.s6_addr[15] = 0x01;
sin6->sin6_port = Utils::hton((uint16_t)40);

View file

@ -18,8 +18,9 @@
#include <cstring>
#include <cstdint>
#include "Constants.hpp"
#include "../include/ZeroTierOne.h"
#include "Constants.hpp"
#include "Utils.hpp"
#include "MAC.hpp"
#include "Buffer.hpp"
@ -464,16 +465,16 @@ struct InetAddress : public sockaddr_storage
unsigned long h = 0;
switch(ss_family) {
case AF_INET:
h = (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr) & 0xffffff00) >> 8;
h ^= (h >> 14);
h = (Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr) & 0xffffff00U) >> 8U;
h ^= (h >> 14U);
break;
case AF_INET6: {
const uint8_t *ip = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
h = ((unsigned long)ip[0]); h <<= 1;
h += ((unsigned long)ip[1]); h <<= 1;
h += ((unsigned long)ip[2]); h <<= 1;
h += ((unsigned long)ip[3]); h <<= 1;
h += ((unsigned long)ip[4]); h <<= 1;
h = ((unsigned long)ip[0]); h <<= 1U;
h += ((unsigned long)ip[1]); h <<= 1U;
h += ((unsigned long)ip[2]); h <<= 1U;
h += ((unsigned long)ip[3]); h <<= 1U;
h += ((unsigned long)ip[4]); h <<= 1U;
h += ((unsigned long)ip[5]);
} break;
}
@ -483,30 +484,31 @@ struct InetAddress : public sockaddr_storage
/**
* @return True if address family is non-zero
*/
ZT_ALWAYS_INLINE operator bool() const { return (ss_family != 0); }
explicit ZT_ALWAYS_INLINE operator bool() const { return (ss_family != 0); }
// Marshal interface ///////////////////////////////////////////////////////
static ZT_ALWAYS_INLINE int marshalSizeMax() { return 19; }
inline int marshal(uint8_t restrict data[19]) const
inline int marshal(uint8_t data[19]) const
{
unsigned int port;
switch(ss_family) {
case AF_INET:
const unsigned int port = Utils::ntoh((uint16_t)reinterpret_cast<const sockaddr_in *>(this)->sin_port);
port = Utils::ntoh((uint16_t)reinterpret_cast<const sockaddr_in *>(this)->sin_port);
data[0] = 4;
data[1] = reinterpret_cast<const uint8_t *>(&(reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr))[0];
data[2] = reinterpret_cast<const uint8_t *>(&(reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr))[1];
data[3] = reinterpret_cast<const uint8_t *>(&(reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr))[2];
data[4] = reinterpret_cast<const uint8_t *>(&(reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr))[3];
data[5] = (uint8_t)((port >> 8) & 0xff);
data[6] = (uint8_t)(port & 0xff);
data[5] = (uint8_t)(port >> 8U);
data[6] = (uint8_t)port;
return 7;
case AF_INET6:
const unsigned int port = Utils::ntoh((uint16_t)reinterpret_cast<const sockaddr_in6 *>(this)->sin6_port);
port = Utils::ntoh((uint16_t)reinterpret_cast<const sockaddr_in6 *>(this)->sin6_port);
data[0] = 6;
for(int i=0;i<16;++i)
data[i+1] = reinterpret_cast<const sockaddr_in6 *>(this)->sin6_addr.s6_addr[i];
data[17] = (uint8_t)((port >> 8) & 0xff);
data[18] = (uint8_t)(port & 0xff);
data[17] = (uint8_t)(port >> 8U);
data[18] = (uint8_t)port;
return 19;
default:
data[0] = 0;

View file

@ -16,6 +16,7 @@
#include <algorithm>
#include <vector>
#include <cstdint>
#include "Constants.hpp"
#include "Endpoint.hpp"
@ -35,7 +36,12 @@ namespace ZeroTier {
class Locator
{
public:
ZT_ALWAYS_INLINE Locator() : _ts(0),_endpointCount(0),_signatureLength(0) {}
ZT_ALWAYS_INLINE Locator() { this->clear(); }
/**
* Zero the Locator data structure
*/
ZT_ALWAYS_INLINE void clear() { memset(reinterpret_cast<void *>(this),0,sizeof(Locator)); }
/**
* @return Timestamp (a.k.a. revision number) set by Location signer
@ -43,31 +49,42 @@ public:
ZT_ALWAYS_INLINE int64_t timestamp() const { return _ts; }
/**
* Create and sign a Locator
*
* @param ts Timestamp
* @param id Identity (must include secret to allow signing)
* @param at Array of Endpoint objects specifying where this peer might be found
* @param endpointCount Number of endpoints (max: ZT_LOCATOR_MAX_ENDPOINTS)
* @return True if init and sign were successful
* @return True if locator is signed
*/
inline bool create(const int64_t ts,const Identity &id,const Endpoint *restrict at,const unsigned int endpointCount)
ZT_ALWAYS_INLINE bool isSigned() const { return (_signatureLength > 0); }
/**
* Add an endpoint to this locator if not already present
*
* @param ep Endpoint to add
* @return True if endpoint was added (or already present), false if locator is full
*/
inline bool add(const Endpoint &ep)
{
if ((endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(!id.hasPrivate()))
if (_endpointCount >= ZT_LOCATOR_MAX_ENDPOINTS)
return false;
if (!std::binary_search(_at,_at + _endpointCount,ep)) {
_at[_endpointCount++] = ep;
std::sort(_at,_at + _endpointCount);
}
return true;
}
/**
* Sign this locator
*
* @param id Identity that includes private key
* @return True if signature successful
*/
inline bool sign(const int64_t ts,const Identity &id)
{
uint8_t signData[ZT_LOCATOR_MARSHAL_SIZE_MAX];
if (!id.hasPrivate())
return false;
_ts = ts;
for(unsigned int i=0;i<endpointCount;++i)
_at[i] = at[i];
_endpointCount = endpointCount;
uint8_t signData[ZT_LOCATOR_MARSHAL_SIZE_MAX];
const unsigned int signLen = marshal(signData,true);
if (signLen == 0)
return false;
if ((_signatureLength = id.sign(signData,signLen,_signature,sizeof(_signature))) == 0)
return false;
return true;
_signatureLength = id.sign(signData, signLen, _signature, sizeof(_signature));
return (_signatureLength > 0);
}
/**
@ -85,26 +102,19 @@ public:
return id.verify(signData,signLen,_signature,_signatureLength);
}
ZT_ALWAYS_INLINE operator bool() const { return (_ts != 0); }
explicit ZT_ALWAYS_INLINE operator bool() const { return (_ts != 0); }
// Marshal interface ///////////////////////////////////////////////////////
static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_LOCATOR_MARSHAL_SIZE_MAX; }
inline int marshal(uint8_t restrict data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool excludeSignature = false) const
inline int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool excludeSignature = false) const
{
if ((_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE))
return -1;
data[0] = (uint8_t)((uint64_t)_ts >> 56);
data[1] = (uint8_t)((uint64_t)_ts >> 48);
data[2] = (uint8_t)((uint64_t)_ts >> 40);
data[3] = (uint8_t)((uint64_t)_ts >> 32);
data[4] = (uint8_t)((uint64_t)_ts >> 24);
data[5] = (uint8_t)((uint64_t)_ts >> 16);
data[6] = (uint8_t)((uint64_t)_ts >> 8);
data[7] = (uint8_t)((uint64_t)_ts);
Utils::putUInt64(data,(uint64_t)_ts);
int p = 8;
data[p++] = (uint8_t)(_endpointCount >> 8);
data[p++] = (uint8_t)(_endpointCount >> 8U);
data[p++] = (uint8_t)_endpointCount;
for(unsigned int i=0;i<_endpointCount;++i) {
int tmp = _at[i].marshal(data + p);
@ -114,10 +124,10 @@ public:
}
if (!excludeSignature) {
data[p++] = (uint8_t)(_signatureLength >> 8);
data[p++] = (uint8_t)(_signatureLength >> 8U);
data[p++] = (uint8_t)_signatureLength;
memcpy(data + p,_signature,_signatureLength);
p += _signatureLength;
p += (int)_signatureLength;
}
return p;
@ -127,21 +137,13 @@ public:
if (len <= (8 + 48))
return -1;
uint64_t ts = ((uint64_t)data[0] << 56);
ts |= ((uint64_t)data[1] << 48);
ts |= ((uint64_t)data[2] << 40);
ts |= ((uint64_t)data[3] << 32);
ts |= ((uint64_t)data[4] << 24);
ts |= ((uint64_t)data[5] << 16);
ts |= ((uint64_t)data[6] << 8);
ts |= (uint64_t)data[7];
_ts = (int64_t)ts;
_ts = (int64_t)Utils::readUInt64(data);
int p = 8;
if ((p + 2) > len)
return -1;
unsigned int ec = (int)data[p++];
ec <<= 8;
ec <<= 8U;
ec |= data[p++];
if (ec > ZT_LOCATOR_MAX_ENDPOINTS)
return -1;
@ -156,7 +158,7 @@ public:
if ((p + 2) > len)
return -1;
unsigned int sl = data[p++];
sl <<= 8;
sl <<= 8U;
sl |= data[p++];
if (sl > ZT_SIGNATURE_BUFFER_SIZE)
return -1;

View file

@ -68,7 +68,7 @@ public:
/**
* @return Time we last pushed credentials to this member
*/
inline int64_t lastPushedCredentials() const { return _lastPushedCredentials; }
ZT_ALWAYS_INLINE int64_t lastPushedCredentials() const { return _lastPushedCredentials; }
/**
* Check whether we should push MULTICAST_LIKEs to this peer, and update last sent time if true
@ -76,7 +76,7 @@ public:
* @param now Current time
* @return True if we should update multicasts
*/
inline bool multicastLikeGate(const int64_t now)
ZT_ALWAYS_INLINE bool multicastLikeGate(const int64_t now)
{
if ((now - _lastUpdatedMulticast) >= ZT_MULTICAST_ANNOUNCE_PERIOD) {
_lastUpdatedMulticast = now;
@ -91,7 +91,7 @@ public:
* @param nconf Our network config
* @return True if this peer is allowed on this network at all
*/
inline bool isAllowedOnNetwork(const NetworkConfig &nconf) const
ZT_ALWAYS_INLINE bool isAllowedOnNetwork(const NetworkConfig &nconf) const
{
if (nconf.isPublic()) return true; // public network
if (_com.timestamp() <= _comRevocationThreshold) return false; // COM has been revoked
@ -107,7 +107,7 @@ public:
* @return True if this peer has a certificate of ownership for the given resource
*/
template<typename T>
inline bool peerOwnsAddress(const NetworkConfig &nconf,const T &r) const
ZT_ALWAYS_INLINE bool peerOwnsAddress(const NetworkConfig &nconf,const T &r) const
{
if (_isUnspoofableAddress(nconf,r))
return true;
@ -128,7 +128,7 @@ public:
* @param id Tag ID
* @return Pointer to tag or NULL if not found
*/
inline const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const
ZT_ALWAYS_INLINE const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const
{
const Tag *const t = _remoteTags.get(id);
return (((t)&&(_isCredentialTimestampValid(nconf,*t))) ? t : (Tag *)0);
@ -146,7 +146,7 @@ public:
* @param now Current time
* @param nconf Current network configuration
*/
void clean(const int64_t now,const NetworkConfig &nconf);
void clean(int64_t now,const NetworkConfig &nconf);
/**
* Generates a key for internal use in indexing credentials by type and credential ID
@ -156,29 +156,29 @@ public:
/**
* @return Bytes received so far
*/
inline uint64_t receivedBytes() const { return _received; }
ZT_ALWAYS_INLINE uint64_t receivedBytes() const { return _received; }
/**
* @return Bytes sent so far
*/
inline uint64_t sentBytes() const { return _sent; }
ZT_ALWAYS_INLINE uint64_t sentBytes() const { return _sent; }
/**
* @param bytes Bytes received
*/
inline void logReceivedBytes(const unsigned int bytes) { _received = (uint64_t)bytes; }
ZT_ALWAYS_INLINE void logReceivedBytes(const unsigned int bytes) { _received = (uint64_t)bytes; }
/**
* @param bytes Bytes sent
*/
inline void logSentBytes(const unsigned int bytes) { _sent = (uint64_t)bytes; }
ZT_ALWAYS_INLINE void logSentBytes(const unsigned int bytes) { _sent = (uint64_t)bytes; }
private:
// This returns true if a resource is an IPv6 NDP-emulated address. These embed the ZT
// address of the peer and therefore cannot be spoofed, causing peerOwnsAddress() to
// always return true for them. A certificate is not required for these.
inline bool _isUnspoofableAddress(const NetworkConfig &nconf,const MAC &m) const { return false; }
inline bool _isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const
ZT_ALWAYS_INLINE bool _isUnspoofableAddress(const NetworkConfig &nconf,const MAC &m) const { return false; }
ZT_ALWAYS_INLINE bool _isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const
{
if ((ip.isV6())&&(nconf.ndpEmulation())) {
const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt()));
@ -219,7 +219,7 @@ private:
// This compares the remote credential's timestamp to the timestamp in our network config
// plus or minus the permitted maximum timestamp delta.
template<typename C>
inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &remoteCredential) const
ZT_ALWAYS_INLINE bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &remoteCredential) const
{
const int64_t ts = remoteCredential.timestamp();
if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) {
@ -271,7 +271,7 @@ public:
class CapabilityIterator
{
public:
inline CapabilityIterator(Membership &m,const NetworkConfig &nconf) :
ZT_ALWAYS_INLINE CapabilityIterator(Membership &m,const NetworkConfig &nconf) :
_hti(m._remoteCaps),
_k((uint32_t *)0),
_c((Capability *)0),
@ -280,7 +280,7 @@ public:
{
}
inline Capability *next()
ZT_ALWAYS_INLINE Capability *next()
{
while (_hti.next(_k,_c)) {
if (_m._isCredentialTimestampValid(_nconf,*_c))

View file

@ -11,11 +11,11 @@
*/
/****/
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <stdint.h>
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
#include <cstring>
#include <cstdint>
#include "Constants.hpp"
#include "SharedPtr.hpp"
@ -40,10 +40,10 @@ namespace ZeroTier {
/* Public Node interface (C++, exposed via CAPI bindings) */
/****************************************************************************/
Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now) :
Node::Node(void *uPtr, void *tPtr, const struct ZT_Node_Callbacks *callbacks, int64_t now) :
_RR(this),
RR(&_RR),
_uPtr(uptr),
_uPtr(uPtr),
_networks(8),
_now(now),
_lastPing(0),
@ -61,7 +61,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
uint64_t idtmp[2];
idtmp[0] = 0; idtmp[1] = 0;
char tmp[2048];
int n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,tmp,sizeof(tmp) - 1);
int n = stateObjectGet(tPtr, ZT_STATE_OBJECT_IDENTITY_SECRET, idtmp, tmp, sizeof(tmp) - 1);
if (n > 0) {
tmp[n] = (char)0;
if (RR->identity.fromString(tmp)) {
@ -77,14 +77,14 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
RR->identity.toString(false,RR->publicIdentityStr);
RR->identity.toString(true,RR->secretIdentityStr);
idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0;
stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp,RR->secretIdentityStr,(unsigned int)strlen(RR->secretIdentityStr));
stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr,(unsigned int)strlen(RR->publicIdentityStr));
stateObjectPut(tPtr, ZT_STATE_OBJECT_IDENTITY_SECRET, idtmp, RR->secretIdentityStr, (unsigned int)strlen(RR->secretIdentityStr));
stateObjectPut(tPtr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, RR->publicIdentityStr, (unsigned int)strlen(RR->publicIdentityStr));
} else {
idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0;
n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp,sizeof(tmp) - 1);
n = stateObjectGet(tPtr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, tmp, sizeof(tmp) - 1);
if ((n > 0)&&(n < (int)sizeof(RR->publicIdentityStr))&&(n < (int)sizeof(tmp))) {
if (memcmp(tmp,RR->publicIdentityStr,n))
stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr,(unsigned int)strlen(RR->publicIdentityStr));
if (memcmp(tmp,RR->publicIdentityStr,n) != 0)
stateObjectPut(tPtr, ZT_STATE_OBJECT_IDENTITY_PUBLIC, idtmp, RR->publicIdentityStr, (unsigned int)strlen(RR->publicIdentityStr));
}
}
@ -117,7 +117,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
throw;
}
postEvent(tptr,ZT_EVENT_UP);
postEvent(tPtr, ZT_EVENT_UP);
}
Node::~Node()
@ -130,7 +130,7 @@ Node::~Node()
if (RR->topology) RR->topology->~Topology();
if (RR->sw) RR->sw->~Switch();
if (RR->t) RR->t->~Trace();
::free(RR->rtmem);
free(RR->rtmem);
}
ZT_ResultCode Node::processWirePacket(
@ -169,74 +169,42 @@ ZT_ResultCode Node::processVirtualNetworkFrame(
}
}
// This is passed as the argument to the DNS request handler and
// aggregates results.
struct _processBackgroundTasks_dnsResultAccumulator
// This function object is run past every peer every ZT_PEER_PING_PERIOD.
struct _processBackgroundTasks_ping_eachPeer
{
_processBackgroundTasks_dnsResultAccumulator(const Str &n) : dnsName(n) {}
Str dnsName;
std::vector<Str> txtRecords;
};
static const ZT_DNSRecordType s_txtRecordType[1] = { ZT_DNS_RECORD_TXT };
struct _processBackgroundTasks_eachRootName
{
ZT_Node_Callbacks *cb;
Node *n;
void *uPtr;
void *tPtr;
bool updateAll;
inline bool operator()(const Str &dnsName,const Locator &loc)
{
if ((strchr(dnsName.c_str(),'.'))&&((updateAll)||(!loc))) {
_processBackgroundTasks_dnsResultAccumulator *dnsReq = new _processBackgroundTasks_dnsResultAccumulator(dnsName);
cb->dnsResolver(reinterpret_cast<ZT_Node *>(n),uPtr,tPtr,s_txtRecordType,1,dnsName.c_str(),(uintptr_t)dnsReq);
}
return true;
}
};
struct _processBackgroundTasks_ping_eachRoot
{
Hashtable< void *,bool > roots;
int64_t now;
void *tPtr;
bool online;
inline bool operator()(const SharedPtr<Peer> &peer,const std::vector<InetAddress> &addrs)
ZT_ALWAYS_INLINE bool operator()(const SharedPtr<Peer> &peer,const bool isRoot)
{
unsigned int v4SendCount = 0,v6SendCount = 0;
peer->ping(tPtr,now,v4SendCount,v6SendCount);
for(std::vector<InetAddress>::const_iterator a(addrs.begin());a!=addrs.end();++a) {
if ( ((a->isV4())&&(v4SendCount == 0)) || ((a->isV6())&&(v6SendCount == 0)) )
peer->sendHELLO(tPtr,-1,*a,now);
if (isRoot) {
if ((now - peer->lastReceive()) <= ZT_PEER_PING_PERIOD)
online = true;
if (v4SendCount == 0) {
InetAddress try4;
parent->externalPathLookup(tPtr,peer->identity(),AF_INET,try4);
if (try4.ss_family == AF_INET)
peer->sendHELLO(tPtr,-1,try4,now);
}
if (v6SendCount == 0) {
InetAddress try6;
parent->externalPathLookup(tPtr,peer->identity(),AF_INET6,try6);
if (try6.ss_family == AF_INET6)
peer->sendHELLO(tPtr,-1,try6,now);
}
}
if (!online)
online = ((now - peer->lastReceive()) <= ((ZT_PEER_PING_PERIOD * 2) + 5000));
roots.set((void *)peer.ptr(),true);
return true;
}
};
struct _processBackgroundTasks_ping_eachPeer
{
int64_t now;
Node *parent;
void *tPtr;
Hashtable< void *,bool > *roots;
inline bool operator()(const SharedPtr<Peer> &peer)
{
if (!roots->contains((void *)peer.ptr())) {
unsigned int v4SendCount = 0,v6SendCount = 0;
peer->ping(tPtr,now,v4SendCount,v6SendCount);
}
return true;
}
bool online;
};
ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline)
ZT_ResultCode Node::processBackgroundTasks(void *tPtr, int64_t now, volatile int64_t *nextBackgroundTaskDeadline)
{
_now = now;
Mutex::Lock bl(_backgroundTasksLock);
@ -252,41 +220,19 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
if ((now - _lastPing) >= ZT_PEER_PING_PERIOD) {
_lastPing = now;
try {
// Periodically refresh locators for dynamic roots from their DNS names.
if (_cb.dnsResolver) {
_processBackgroundTasks_eachRootName cr;
cr.cb = &_cb;
cr.n = this;
cr.uPtr = _uPtr;
cr.tPtr = tptr;
if ((now - _lastDynamicRootUpdate) >= ZT_DYNAMIC_ROOT_UPDATE_PERIOD) {
_lastDynamicRootUpdate = now;
cr.updateAll = true;
} else {
cr.updateAll = false;
}
RR->topology->eachRootName(cr);
}
// Ping each root explicitly no matter what
_processBackgroundTasks_ping_eachRoot rf;
rf.now = now;
rf.tPtr = tptr;
rf.online = false;
RR->topology->eachRoot(rf);
// Ping peers that are active and we want to keep alive
_processBackgroundTasks_ping_eachPeer pf;
pf.now = now;
pf.tPtr = tptr;
pf.roots = &rf.roots;
RR->topology->eachPeer(pf);
pf.parent = this;
pf.tPtr = tPtr;
pf.online = false;
RR->topology->eachPeerWithRoot<_processBackgroundTasks_ping_eachPeer &>(pf);
// Update online status based on whether we can reach a root
if (rf.online != _online) {
_online = rf.online;
postEvent(tptr,_online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE);
if (pf.online != _online) {
_online = pf.online;
postEvent(tPtr, _online ? ZT_EVENT_ONLINE : ZT_EVENT_OFFLINE);
}
RR->topology->rankRoots(now);
} catch ( ... ) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
@ -300,7 +246,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
uint64_t *nwid = (uint64_t *)0;
SharedPtr<Network> *network = (SharedPtr<Network> *)0;
while (i.next(nwid,network)) {
(*network)->doPeriodicTasks(tptr,now);
(*network)->doPeriodicTasks(tPtr, now);
}
}
}
@ -332,7 +278,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
}
try {
*nextBackgroundTaskDeadline = now + (int64_t)std::max(std::min((unsigned long)ZT_MAX_TIMER_TASK_INTERVAL,RR->sw->doTimerTasks(tptr,now)),(unsigned long)ZT_MIN_TIMER_TASK_INTERVAL);
*nextBackgroundTaskDeadline = now + (int64_t)std::max(std::min((unsigned long)ZT_MAX_TIMER_TASK_INTERVAL,RR->sw->doTimerTasks(tPtr, now)), (unsigned long)ZT_MIN_TIMER_TASK_INTERVAL);
} catch ( ... ) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
@ -340,30 +286,6 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
return ZT_RESULT_OK;
}
void Node::processDNSResult(
void *tptr,
uintptr_t dnsRequestID,
const char *name,
enum ZT_DNSRecordType recordType,
const void *result,
unsigned int resultLength,
int resultIsString)
{
if (dnsRequestID) {
_processBackgroundTasks_dnsResultAccumulator *const acc = reinterpret_cast<_processBackgroundTasks_dnsResultAccumulator *>(dnsRequestID);
if (recordType == ZT_DNS_RECORD_TXT) {
if (result)
acc->txtRecords.emplace_back(reinterpret_cast<const char *>(result));
} else if (recordType == ZT_DNS_RECORD__END_OF_RESULTS) {
Locator loc;
if (loc.decodeTxtRecords(acc->dnsName,acc->txtRecords.begin(),acc->txtRecords.end())) {
RR->topology->setRoot(acc->dnsName,loc);
delete acc;
}
}
}
}
ZT_ResultCode Node::join(uint64_t nwid,void *uptr,void *tptr)
{
Mutex::Lock _l(_networks_m);
@ -423,44 +345,25 @@ ZT_ResultCode Node::multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,u
} else return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
}
ZT_RootList *Node::listRoots(int64_t now)
ZT_ResultCode Node::addRoot(const char *identity)
{
return RR->topology->apiRoots(now);
}
enum ZT_ResultCode Node::setRoot(const char *name,const void *locator,unsigned int locatorSize)
{
try {
Locator loc;
if ((locator)&&(locatorSize > 0)&&(locatorSize < 65535)) {
ScopedPtr< Buffer<65536> > locbuf(new Buffer<65536>());
locbuf->append(locator,locatorSize);
loc.deserialize(*locbuf,0);
if (!loc.verify())
return ZT_RESULT_ERROR_BAD_PARAMETER;
}
Str n;
if ((!name)||(strlen(name) == 0)) {
if (!loc)
return ZT_RESULT_ERROR_BAD_PARAMETER; /* no name and no locator */
char tmp[16];
loc.id().address().toString(tmp);
n = tmp;
} else {
n = name;
}
return RR->topology->setRoot(n,loc) ? ZT_RESULT_OK : ZT_RESULT_OK_IGNORED;
} catch ( ... ) {
if (!identity)
return ZT_RESULT_ERROR_BAD_PARAMETER;
}
Identity id;
if (!id.fromString(identity))
return ZT_RESULT_ERROR_BAD_PARAMETER;
RR->topology->addRoot(id);
return ZT_RESULT_OK;
}
enum ZT_ResultCode Node::removeRoot(const char *name)
ZT_ResultCode Node::removeRoot(const char *identity)
{
try {
if (name)
RR->topology->removeRoot(Str(name));
} catch ( ... ) {}
if (!identity)
return ZT_RESULT_ERROR_BAD_PARAMETER;
Identity id;
if (!id.fromString(identity))
return ZT_RESULT_ERROR_BAD_PARAMETER;
RR->topology->removeRoot(id);
return ZT_RESULT_OK;
}
@ -631,33 +534,6 @@ void Node::setController(void *networkControllerInstance)
/* Node methods used only within node/ */
/****************************************************************************/
SharedPtr< const Locator > Node::locator()
{
Mutex::Lock lck(_locator_m);
if (!_locator) {
Locator *l = new Locator();
try {
RR->topology->eachRoot([l](const SharedPtr<Peer> &p,const std::vector<InetAddress> &phyAddr) -> bool {
l->add(p->identity());
return true;
});
{
Mutex::Lock lck2(_localInterfaceAddresses_m);
for(std::vector< ZT_InterfaceAddress >::const_iterator a(_localInterfaceAddresses.begin());a!=_localInterfaceAddresses.end();++a) {
if (a->permanent != 0) {
l->add(*reinterpret_cast<const InetAddress *>(&(a->address)));
}
}
}
} catch ( ... ) {
delete l;
throw;
}
_locator.set(l);
}
return _locator;
}
bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const int64_t localSocket,const InetAddress &remoteAddress)
{
if (!Path::isAddressValidForPath(remoteAddress))
@ -679,6 +555,13 @@ bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,cons
return ( (_cb.pathCheckFunction) ? (_cb.pathCheckFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ztaddr.toInt(),localSocket,reinterpret_cast<const struct sockaddr_storage *>(&remoteAddress)) != 0) : true);
}
bool Node::externalPathLookup(void *tPtr,const Identity &id,int family,InetAddress &addr)
{
char idStr[ZT_IDENTITY_STRING_BUFFER_LENGTH];
id.toString(false,idStr);
return (_cb.pathLookupFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,id.address().toInt(),idStr,family,reinterpret_cast<sockaddr_storage *>(&addr)) == ZT_RESULT_OK);
}
ZT_ResultCode Node::setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork, const ZT_PhysicalPathConfiguration *pathConfig)
{
RR->topology->setPhysicalPathConfiguration(pathNetwork,pathConfig);
@ -870,21 +753,6 @@ enum ZT_ResultCode ZT_Node_processBackgroundTasks(ZT_Node *node,void *tptr,int64
}
}
void ZT_Node_processDNSResult(
ZT_Node *node,
void *tptr,
uintptr_t dnsRequestID,
const char *name,
enum ZT_DNSRecordType recordType,
const void *result,
unsigned int resultLength,
int resultIsString)
{
try {
reinterpret_cast<ZeroTier::Node *>(node)->processDNSResult(tptr,dnsRequestID,name,recordType,result,resultLength,resultIsString);
} catch ( ... ) {}
}
enum ZT_ResultCode ZT_Node_join(ZT_Node *node,uint64_t nwid,void *uptr,void *tptr)
{
try {
@ -929,19 +797,10 @@ enum ZT_ResultCode ZT_Node_multicastUnsubscribe(ZT_Node *node,uint64_t nwid,uint
}
}
ZT_RootList *ZT_Node_listRoots(ZT_Node *node,int64_t now)
enum ZT_ResultCode ZT_Node_addRoot(ZT_Node *node,const char *identity)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->listRoots(now);
} catch ( ... ) {
return nullptr;
}
}
enum ZT_ResultCode ZT_Node_setRoot(ZT_Node *node,const char *name,const void *locator,unsigned int locatorSize)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->setRoot(name,locator,locatorSize);
return reinterpret_cast<ZeroTier::Node *>(node)->addRoot(identity);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {
@ -949,10 +808,10 @@ enum ZT_ResultCode ZT_Node_setRoot(ZT_Node *node,const char *name,const void *lo
}
}
enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node,const char *name)
enum ZT_ResultCode ZT_Node_removeRoot(ZT_Node *node,const char *identity)
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->removeRoot(name);
return reinterpret_cast<ZeroTier::Node *>(node)->removeRoot(identity);
} catch (std::bad_alloc &exc) {
return ZT_RESULT_FATAL_ERROR_OUT_OF_MEMORY;
} catch ( ... ) {

View file

@ -51,7 +51,7 @@ class Locator;
class Node : public NetworkController::Sender
{
public:
Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64_t now);
Node(void *uPtr, void *tPtr, const struct ZT_Node_Callbacks *callbacks, int64_t now);
virtual ~Node();
// Get rid of alignment warnings on 32-bit Windows and possibly improve performance
@ -81,22 +81,13 @@ public:
const void *frameData,
unsigned int frameLength,
volatile int64_t *nextBackgroundTaskDeadline);
ZT_ResultCode processBackgroundTasks(void *tptr,int64_t now,volatile int64_t *nextBackgroundTaskDeadline);
void processDNSResult(
void *tptr,
uintptr_t dnsRequestID,
const char *name,
enum ZT_DNSRecordType recordType,
const void *result,
unsigned int resultLength,
int resultIsString);
ZT_ResultCode processBackgroundTasks(void *tPtr, int64_t now, volatile int64_t *nextBackgroundTaskDeadline);
ZT_ResultCode join(uint64_t nwid,void *uptr,void *tptr);
ZT_ResultCode leave(uint64_t nwid,void **uptr,void *tptr);
ZT_ResultCode multicastSubscribe(void *tptr,uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
ZT_ResultCode multicastUnsubscribe(uint64_t nwid,uint64_t multicastGroup,unsigned long multicastAdi);
ZT_RootList *listRoots(int64_t now);
enum ZT_ResultCode setRoot(const char *name,const void *locator,unsigned int locatorSize);
enum ZT_ResultCode removeRoot(const char *name);
ZT_ResultCode addRoot(const char *identity);
ZT_ResultCode removeRoot(const char *identity);
uint64_t address() const;
void status(ZT_NodeStatus *status) const;
ZT_PeerList *peers() const;
@ -104,16 +95,15 @@ public:
ZT_VirtualNetworkList *networks() const;
void setNetworkUserPtr(uint64_t nwid,void *ptr);
void freeQueryResult(void *qr);
int addLocalInterfaceAddress(const struct sockaddr_storage *addr);
void clearLocalInterfaceAddresses();
void setInterfaceAddresses(const ZT_InterfaceAddress *addrs,unsigned int addrCount);
int sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len);
void setController(void *networkControllerInstance);
// Internal functions ------------------------------------------------------
inline int64_t now() const { return _now; }
ZT_ALWAYS_INLINE int64_t now() const { return _now; }
inline bool putPacket(void *tPtr,const int64_t localSocket,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0)
ZT_ALWAYS_INLINE bool putPacket(void *tPtr,const int64_t localSocket,const InetAddress &addr,const void *data,unsigned int len,unsigned int ttl = 0)
{
return (_cb.wirePacketSendFunction(
reinterpret_cast<ZT_Node *>(this),
@ -126,7 +116,7 @@ public:
ttl) == 0);
}
inline void putFrame(void *tPtr,uint64_t nwid,void **nuptr,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
ZT_ALWAYS_INLINE void putFrame(void *tPtr,uint64_t nwid,void **nuptr,const MAC &source,const MAC &dest,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
{
_cb.virtualNetworkFrameFunction(
reinterpret_cast<ZT_Node *>(this),
@ -142,7 +132,7 @@ public:
len);
}
inline SharedPtr<Network> network(uint64_t nwid) const
ZT_ALWAYS_INLINE SharedPtr<Network> network(uint64_t nwid) const
{
Mutex::Lock _l(_networks_m);
const SharedPtr<Network> *n = _networks.get(nwid);
@ -151,43 +141,22 @@ public:
return SharedPtr<Network>();
}
inline bool belongsToNetwork(uint64_t nwid) const
{
Mutex::Lock _l(_networks_m);
return _networks.contains(nwid);
}
inline std::vector< SharedPtr<Network> > allNetworks() const
{
std::vector< SharedPtr<Network> > nw;
Mutex::Lock _l(_networks_m);
Hashtable< uint64_t,SharedPtr<Network> >::Iterator i(*const_cast< Hashtable< uint64_t,SharedPtr<Network> > * >(&_networks));
uint64_t *k = (uint64_t *)0;
SharedPtr<Network> *v = (SharedPtr<Network> *)0;
while (i.next(k,v))
nw.push_back(*v);
return nw;
}
inline std::vector<ZT_InterfaceAddress> directPaths() const
ZT_ALWAYS_INLINE std::vector<ZT_InterfaceAddress> directPaths() const
{
Mutex::Lock _l(_localInterfaceAddresses_m);
return _localInterfaceAddresses;
}
void setInterfaceAddresses(const ZT_InterfaceAddress *addrs,unsigned int addrCount);
SharedPtr< const Locator > locator();
inline void postEvent(void *tPtr,ZT_Event ev,const void *md = (const void *)0) { _cb.eventCallback(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ev,md); }
inline void configureVirtualNetworkPort(void *tPtr,uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { _cb.virtualNetworkConfigFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,nwid,nuptr,op,nc); }
inline bool online() const { return _online; }
inline int stateObjectGet(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],void *const data,const unsigned int maxlen) { return _cb.stateGetFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,data,maxlen); }
inline void stateObjectPut(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len) { _cb.statePutFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,data,(int)len); }
inline void stateObjectDelete(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2]) { _cb.statePutFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,(const void *)0,-1); }
ZT_ALWAYS_INLINE void postEvent(void *tPtr,ZT_Event ev,const void *md = (const void *)0) { _cb.eventCallback(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ev,md); }
ZT_ALWAYS_INLINE void configureVirtualNetworkPort(void *tPtr,uint64_t nwid,void **nuptr,ZT_VirtualNetworkConfigOperation op,const ZT_VirtualNetworkConfig *nc) { _cb.virtualNetworkConfigFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,nwid,nuptr,op,nc); }
ZT_ALWAYS_INLINE bool online() const { return _online; }
ZT_ALWAYS_INLINE int stateObjectGet(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],void *const data,const unsigned int maxlen) { return _cb.stateGetFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,data,maxlen); }
ZT_ALWAYS_INLINE void stateObjectPut(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2],const void *const data,const unsigned int len) { _cb.statePutFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,data,(int)len); }
ZT_ALWAYS_INLINE void stateObjectDelete(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2]) { _cb.statePutFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,type,id,(const void *)0,-1); }
bool shouldUsePathForZeroTierTraffic(void *tPtr,const Address &ztaddr,const int64_t localSocket,const InetAddress &remoteAddress);
inline bool externalPathLookup(void *tPtr,const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ztaddr.toInt(),family,reinterpret_cast<struct sockaddr_storage *>(&addr)) != 0) : false ); }
bool externalPathLookup(void *tPtr,const Identity &id,int family,InetAddress &addr);
ZT_ResultCode setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig);
inline const Identity &identity() const { return _RR.identity; }
ZT_ALWAYS_INLINE const Identity &identity() const { return _RR.identity; }
/**
* Register that we are expecting a reply to a packet ID
@ -198,9 +167,9 @@ public:
*
* @param packetId Packet ID to expect reply to
*/
inline void expectReplyTo(const uint64_t packetId)
ZT_ALWAYS_INLINE void expectReplyTo(const uint64_t packetId)
{
const unsigned long pid2 = (unsigned long)(packetId >> 32);
const unsigned long pid2 = (unsigned long)(packetId >> 32U);
const unsigned long bucket = (unsigned long)(pid2 & ZT_EXPECTING_REPLIES_BUCKET_MASK1);
_expectingRepliesTo[bucket][_expectingRepliesToBucketPtr[bucket]++ & ZT_EXPECTING_REPLIES_BUCKET_MASK2] = (uint32_t)pid2;
}
@ -215,7 +184,7 @@ public:
* @param packetId Packet ID to check
* @return True if we're expecting a reply
*/
inline bool expectingReplyTo(const uint64_t packetId) const
ZT_ALWAYS_INLINE bool expectingReplyTo(const uint64_t packetId) const
{
const uint32_t pid2 = (uint32_t)(packetId >> 32);
const unsigned long bucket = (unsigned long)(pid2 & ZT_EXPECTING_REPLIES_BUCKET_MASK1);
@ -233,7 +202,7 @@ public:
* @param from Source address of packet
* @return True if within rate limits
*/
inline bool rateGateIdentityVerification(const int64_t now,const InetAddress &from)
ZT_ALWAYS_INLINE bool rateGateIdentityVerification(const int64_t now,const InetAddress &from)
{
unsigned long iph = from.rateGateHash();
if ((now - _lastIdentityVerification[iph]) >= ZT_IDENTITY_VALIDATION_SOURCE_RATE_LIMIT) {
@ -247,9 +216,6 @@ public:
virtual void ncSendRevocation(const Address &destination,const Revocation &rev);
virtual void ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &destination,NetworkController::ErrorCode errorCode);
inline void setMultipathMode(uint8_t mode) { _multipathMode = mode; }
inline uint8_t getMultipathMode() { return _multipathMode; }
inline bool localControllerHasAuthorized(const int64_t now,const uint64_t nwid,const Address &addr) const
{
_localControllerAuthorizations_m.lock();
@ -260,6 +226,9 @@ public:
return false;
}
inline void setMultipathMode(uint8_t mode) { _multipathMode = mode; }
inline uint8_t getMultipathMode() { return _multipathMode; }
private:
RuntimeEnvironment _RR;
RuntimeEnvironment *RR;
@ -281,10 +250,10 @@ private:
struct _LocalControllerAuth
{
uint64_t nwid,address;
inline _LocalControllerAuth(const uint64_t nwid_,const Address &address_) : nwid(nwid_),address(address_.toInt()) {}
inline unsigned long hashCode() const { return (unsigned long)(nwid ^ address); }
inline bool operator==(const _LocalControllerAuth &a) const { return ((a.nwid == nwid)&&(a.address == address)); }
inline bool operator!=(const _LocalControllerAuth &a) const { return ((a.nwid != nwid)||(a.address != address)); }
ZT_ALWAYS_INLINE _LocalControllerAuth(const uint64_t nwid_,const Address &address_) : nwid(nwid_),address(address_.toInt()) {}
ZT_ALWAYS_INLINE unsigned long hashCode() const { return (unsigned long)(nwid ^ address); }
ZT_ALWAYS_INLINE bool operator==(const _LocalControllerAuth &a) const { return ((a.nwid == nwid)&&(a.address == address)); }
ZT_ALWAYS_INLINE bool operator!=(const _LocalControllerAuth &a) const { return ((a.nwid != nwid)||(a.address != address)); }
};
Hashtable< _LocalControllerAuth,int64_t > _localControllerAuthorizations;
Hashtable< uint64_t,SharedPtr<Network> > _networks;
@ -293,7 +262,6 @@ private:
Mutex _localControllerAuthorizations_m;
Mutex _networks_m;
Mutex _locator_m;
Mutex _localInterfaceAddresses_m;
Mutex _backgroundTasksLock;

View file

@ -28,6 +28,7 @@
#include "Utils.hpp"
#include "RingBuffer.hpp"
#include "Packet.hpp"
#include "Mutex.hpp"
/**
* Maximum return value of preferenceRank()
@ -52,9 +53,9 @@ public:
class HashKey
{
public:
inline HashKey() {}
ZT_ALWAYS_INLINE HashKey() {}
inline HashKey(const int64_t l,const InetAddress &r)
ZT_ALWAYS_INLINE HashKey(const int64_t l,const InetAddress &r)
{
if (r.ss_family == AF_INET) {
_k[0] = (uint64_t)reinterpret_cast<const struct sockaddr_in *>(&r)->sin_addr.s_addr;
@ -69,10 +70,10 @@ public:
}
}
inline unsigned long hashCode() const { return (unsigned long)(_k[0] + _k[1] + _k[2]); }
ZT_ALWAYS_INLINE unsigned long hashCode() const { return (unsigned long)(_k[0] + _k[1] + _k[2]); }
inline bool operator==(const HashKey &k) const { return ( (_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]) ); }
inline bool operator!=(const HashKey &k) const { return (!(*this == k)); }
ZT_ALWAYS_INLINE bool operator==(const HashKey &k) const { return ( (_k[0] == k._k[0]) && (_k[1] == k._k[1]) && (_k[2] == k._k[2]) ); }
ZT_ALWAYS_INLINE bool operator!=(const HashKey &k) const { return (!(*this == k)); }
private:
uint64_t _k[3];

View file

@ -691,12 +691,8 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA
void Peer::ping(void *tPtr,int64_t now,unsigned int &v4SendCount,unsigned int &v6SendCount)
{
v4SendCount = 0;
v6SendCount = 0;
Mutex::Lock _l(_paths_m);
// Emit traces regarding aggregate link status
if (_canUseMultipath) {
int alivePathCount = aggregateLinkPhysicalPathCount();
if ((now - _lastAggregateStatsReport) > ZT_PATH_AGGREGATE_STATS_REPORT_INTERVAL) {

View file

@ -30,8 +30,6 @@
#include "Hashtable.hpp"
#include "Mutex.hpp"
#define ZT_PEER_MAX_SERIALIZED_STATE_SIZE (sizeof(Peer) + 32 + (sizeof(Path) * 2))
namespace ZeroTier {
/**
@ -45,7 +43,7 @@ private:
inline Peer() {} // disabled to prevent bugs -- should not be constructed uninitialized
public:
inline ~Peer() { Utils::burn(_key,sizeof(_key)); }
ZT_ALWAYS_INLINE ~Peer() { Utils::burn(_key,sizeof(_key)); }
/**
* Construct a new peer
@ -60,12 +58,12 @@ public:
/**
* @return This peer's ZT address (short for identity().address())
*/
inline const Address &address() const { return _id.address(); }
ZT_ALWAYS_INLINE const Address &address() const { return _id.address(); }
/**
* @return This peer's identity
*/
inline const Identity &identity() const { return _id; }
ZT_ALWAYS_INLINE const Identity &identity() const { return _id; }
/**
* Log receipt of an authenticated packet
@ -85,13 +83,13 @@ public:
void received(
void *tPtr,
const SharedPtr<Path> &path,
const unsigned int hops,
const uint64_t packetId,
const unsigned int payloadLength,
const Packet::Verb verb,
const uint64_t inRePacketId,
const Packet::Verb inReVerb,
const uint64_t networkId);
unsigned int hops,
uint64_t packetId,
unsigned int payloadLength,
Packet::Verb verb,
uint64_t inRePacketId,
Packet::Verb inReVerb,
uint64_t networkId);
/**
* Check whether we have an active path to this peer via the given address
@ -122,7 +120,7 @@ public:
* @param force If true, send even if path is not alive
* @return True if we actually sent something
*/
inline bool sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force)
ZT_ALWAYS_INLINE bool sendDirect(void *tPtr,const void *data,unsigned int len,int64_t now,bool force)
{
SharedPtr<Path> bp(getAppropriatePath(now,force));
if (bp)
@ -139,7 +137,7 @@ public:
* @param verb Packet verb
* @param now Current time
*/
void recordOutgoingPacket(const SharedPtr<Path> &path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, int64_t now);
void recordOutgoingPacket(const SharedPtr<Path> &path, uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, int64_t now);
/**
* Record statistics on incoming packets
@ -150,7 +148,7 @@ public:
* @param verb Packet verb
* @param now Current time
*/
void recordIncomingPacket(void *tPtr, const SharedPtr<Path> &path, const uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, int64_t now);
void recordIncomingPacket(void *tPtr, const SharedPtr<Path> &path, uint64_t packetId, uint16_t payloadLength, const Packet::Verb verb, int64_t now);
/**
* Send an ACK to peer for the most recent packets received
@ -160,7 +158,7 @@ public:
* @param atAddress Destination for the ACK packet
* @param now Current time
*/
void sendACK(void *tPtr, const SharedPtr<Path> &path, const int64_t localSocket,const InetAddress &atAddress,int64_t now);
void sendACK(void *tPtr, const SharedPtr<Path> &path, int64_t localSocket,const InetAddress &atAddress,int64_t now);
/**
* Send a QoS packet to peer so that it can evaluate the quality of this link
@ -170,7 +168,7 @@ public:
* @param atAddress Destination for the QoS packet
* @param now Current time
*/
void sendQOS_MEASUREMENT(void *tPtr, const SharedPtr<Path> &path, const int64_t localSocket,const InetAddress &atAddress,int64_t now);
void sendQOS_MEASUREMENT(void *tPtr, const SharedPtr<Path> &path, int64_t localSocket,const InetAddress &atAddress,int64_t now);
/**
* Compute relative quality values and allocations for the components of the aggregate link
@ -217,7 +215,7 @@ public:
/**
* Send VERB_RENDEZVOUS to this and another peer via the best common IP scope and path
*/
void introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &other) const;
void introduce(void *tPtr,int64_t now,const SharedPtr<Peer> &other) const;
/**
* Send a HELLO to this peer at a specified physical address
@ -229,7 +227,7 @@ public:
* @param atAddress Destination address
* @param now Current time
*/
void sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atAddress,int64_t now);
void sendHELLO(void *tPtr,int64_t localSocket,const InetAddress &atAddress,int64_t now);
/**
* Send pings to active paths
@ -276,17 +274,17 @@ public:
/**
* @return Time of last receive of anything, whether direct or relayed
*/
inline int64_t lastReceive() const { return _lastReceive; }
ZT_ALWAYS_INLINE int64_t lastReceive() const { return _lastReceive; }
/**
* @return True if we've heard from this peer in less than ZT_PEER_ACTIVITY_TIMEOUT
*/
inline bool alive(const int64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); }
ZT_ALWAYS_INLINE bool alive(const int64_t now) const { return ((now - _lastReceive) < ZT_PEER_ACTIVITY_TIMEOUT); }
/**
* @return Latency in milliseconds of best/aggregate path or 0xffff if unknown / no paths
*/
inline unsigned int latency(const int64_t now)
ZT_ALWAYS_INLINE unsigned int latency(const int64_t now)
{
if (_canUseMultipath) {
return (int)computeAggregateLinkMeanLatency();
@ -298,32 +296,10 @@ public:
}
}
/**
* This computes a quality score for relays and root servers
*
* If we haven't heard anything from these in ZT_PEER_ACTIVITY_TIMEOUT, they
* receive the worst possible quality (max unsigned int). Otherwise the
* quality is a product of latency and the number of potential missed
* pings. This causes roots and relays to switch over a bit faster if they
* fail.
*
* @return Relay quality score computed from latency and other factors, lower is better
*/
inline unsigned int relayQuality(const int64_t now)
{
const uint64_t tsr = now - _lastReceive;
if (tsr >= ZT_PEER_ACTIVITY_TIMEOUT)
return (~(unsigned int)0);
unsigned int l = latency(now);
if (!l)
l = 0xffff;
return (l * (((unsigned int)tsr / (ZT_PEER_PING_PERIOD + 1000)) + 1));
}
/**
* @return 256-bit secret symmetric encryption key
*/
inline const unsigned char *key() const { return _key; }
ZT_ALWAYS_INLINE const unsigned char *key() const { return _key; }
/**
* Set the currently known remote version of this peer's client
@ -333,7 +309,7 @@ public:
* @param vmin Minor version
* @param vrev Revision
*/
inline void setRemoteVersion(unsigned int vproto,unsigned int vmaj,unsigned int vmin,unsigned int vrev)
ZT_ALWAYS_INLINE void setRemoteVersion(unsigned int vproto,unsigned int vmaj,unsigned int vmin,unsigned int vrev)
{
_vProto = (uint16_t)vproto;
_vMajor = (uint16_t)vmaj;
@ -341,11 +317,11 @@ public:
_vRevision = (uint16_t)vrev;
}
inline unsigned int remoteVersionProtocol() const { return _vProto; }
inline unsigned int remoteVersionMajor() const { return _vMajor; }
inline unsigned int remoteVersionMinor() const { return _vMinor; }
inline unsigned int remoteVersionRevision() const { return _vRevision; }
inline bool remoteVersionKnown() const { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); }
ZT_ALWAYS_INLINE unsigned int remoteVersionProtocol() const { return _vProto; }
ZT_ALWAYS_INLINE unsigned int remoteVersionMajor() const { return _vMajor; }
ZT_ALWAYS_INLINE unsigned int remoteVersionMinor() const { return _vMinor; }
ZT_ALWAYS_INLINE unsigned int remoteVersionRevision() const { return _vRevision; }
ZT_ALWAYS_INLINE bool remoteVersionKnown() const { return ((_vMajor > 0)||(_vMinor > 0)||(_vRevision > 0)); }
/**
* Periodically update known multipath activation constraints. This is done so that we know when and when

View file

@ -45,9 +45,9 @@ class Revocation : public Credential
friend class Credential;
public:
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_REVOCATION; }
static ZT_ALWAYS_INLINE Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_REVOCATION; }
inline Revocation() :
ZT_ALWAYS_INLINE Revocation() :
_id(0),
_credentialId(0),
_networkId(0),
@ -69,7 +69,7 @@ public:
* @param tgt Target node whose credential(s) are being revoked
* @param ct Credential type being revoked
*/
inline Revocation(const uint32_t i,const uint64_t nwid,const uint32_t cid,const uint64_t thr,const uint64_t fl,const Address &tgt,const Credential::Type ct) :
ZT_ALWAYS_INLINE Revocation(const uint32_t i,const uint64_t nwid,const uint32_t cid,const uint64_t thr,const uint64_t fl,const Address &tgt,const Credential::Type ct) :
_id(i),
_credentialId(cid),
_networkId(nwid),
@ -82,16 +82,16 @@ public:
{
}
inline uint32_t id() const { return _id; }
inline uint32_t credentialId() const { return _credentialId; }
inline uint64_t networkId() const { return _networkId; }
inline int64_t threshold() const { return _threshold; }
inline const Address &target() const { return _target; }
inline const Address &signer() const { return _signedBy; }
inline Credential::Type type() const { return _type; }
inline const uint8_t *signature() const { return _signature; }
inline unsigned int signatureLength() const { return _signatureLength; }
inline bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); }
ZT_ALWAYS_INLINE uint32_t id() const { return _id; }
ZT_ALWAYS_INLINE uint32_t credentialId() const { return _credentialId; }
ZT_ALWAYS_INLINE uint64_t networkId() const { return _networkId; }
ZT_ALWAYS_INLINE int64_t threshold() const { return _threshold; }
ZT_ALWAYS_INLINE const Address &target() const { return _target; }
ZT_ALWAYS_INLINE const Address &signer() const { return _signedBy; }
ZT_ALWAYS_INLINE Credential::Type type() const { return _type; }
ZT_ALWAYS_INLINE const uint8_t *signature() const { return _signature; }
ZT_ALWAYS_INLINE unsigned int signatureLength() const { return _signatureLength; }
ZT_ALWAYS_INLINE bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); }
/**
* @param signer Signing identity, must have private key
@ -115,7 +115,7 @@ public:
* @param RR Runtime environment to provide for peer lookup, etc.
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
*/
inline Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const

View file

@ -14,7 +14,6 @@
#ifndef ZT_SHAREDPTR_HPP
#define ZT_SHAREDPTR_HPP
#include "Mutex.hpp"
#include "AtomicCounter.hpp"
namespace ZeroTier {

View file

@ -52,9 +52,9 @@ class Tag : public Credential
friend class Credential;
public:
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_TAG; }
static ZT_ALWAYS_INLINE Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_TAG; }
inline Tag() :
ZT_ALWAYS_INLINE Tag() :
_id(0),
_value(0),
_networkId(0),
@ -70,7 +70,7 @@ public:
* @param id Tag ID
* @param value Tag value
*/
inline Tag(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id,const uint32_t value) :
ZT_ALWAYS_INLINE Tag(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id,const uint32_t value) :
_id(id),
_value(value),
_networkId(nwid),
@ -81,14 +81,14 @@ public:
{
}
inline uint32_t id() const { return _id; }
inline const uint32_t &value() const { return _value; }
inline uint64_t networkId() const { return _networkId; }
inline int64_t timestamp() const { return _ts; }
inline const Address &issuedTo() const { return _issuedTo; }
inline const Address &signer() const { return _signedBy; }
inline const uint8_t *signature() const { return _signature; }
inline unsigned int signatureLength() const { return _signatureLength; }
ZT_ALWAYS_INLINE uint32_t id() const { return _id; }
ZT_ALWAYS_INLINE const uint32_t &value() const { return _value; }
ZT_ALWAYS_INLINE uint64_t networkId() const { return _networkId; }
ZT_ALWAYS_INLINE int64_t timestamp() const { return _ts; }
ZT_ALWAYS_INLINE const Address &issuedTo() const { return _issuedTo; }
ZT_ALWAYS_INLINE const Address &signer() const { return _signedBy; }
ZT_ALWAYS_INLINE const uint8_t *signature() const { return _signature; }
ZT_ALWAYS_INLINE unsigned int signatureLength() const { return _signatureLength; }
/**
* Sign this tag
@ -114,7 +114,7 @@ public:
* @param RR Runtime environment to allow identity lookup for signedBy
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
*/
inline Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const
@ -172,23 +172,23 @@ public:
}
// Provides natural sort order by ID
inline bool operator<(const Tag &t) const { return (_id < t._id); }
ZT_ALWAYS_INLINE bool operator<(const Tag &t) const { return (_id < t._id); }
inline bool operator==(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) == 0); }
inline bool operator!=(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) != 0); }
ZT_ALWAYS_INLINE bool operator==(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) == 0); }
ZT_ALWAYS_INLINE bool operator!=(const Tag &t) const { return (memcmp(this,&t,sizeof(Tag)) != 0); }
// For searching sorted arrays or lists of Tags by ID
struct IdComparePredicate
{
inline bool operator()(const Tag &a,const Tag &b) const { return (a.id() < b.id()); }
inline bool operator()(const uint32_t a,const Tag &b) const { return (a < b.id()); }
inline bool operator()(const Tag &a,const uint32_t b) const { return (a.id() < b); }
inline bool operator()(const Tag *a,const Tag *b) const { return (a->id() < b->id()); }
inline bool operator()(const Tag *a,const Tag &b) const { return (a->id() < b.id()); }
inline bool operator()(const Tag &a,const Tag *b) const { return (a.id() < b->id()); }
inline bool operator()(const uint32_t a,const Tag *b) const { return (a < b->id()); }
inline bool operator()(const Tag *a,const uint32_t b) const { return (a->id() < b); }
inline bool operator()(const uint32_t a,const uint32_t b) const { return (a < b); }
ZT_ALWAYS_INLINE bool operator()(const Tag &a,const Tag &b) const { return (a.id() < b.id()); }
ZT_ALWAYS_INLINE bool operator()(const uint32_t a,const Tag &b) const { return (a < b.id()); }
ZT_ALWAYS_INLINE bool operator()(const Tag &a,const uint32_t b) const { return (a.id() < b); }
ZT_ALWAYS_INLINE bool operator()(const Tag *a,const Tag *b) const { return (a->id() < b->id()); }
ZT_ALWAYS_INLINE bool operator()(const Tag *a,const Tag &b) const { return (a->id() < b.id()); }
ZT_ALWAYS_INLINE bool operator()(const Tag &a,const Tag *b) const { return (a.id() < b->id()); }
ZT_ALWAYS_INLINE bool operator()(const uint32_t a,const Tag *b) const { return (a < b->id()); }
ZT_ALWAYS_INLINE bool operator()(const Tag *a,const uint32_t b) const { return (a->id() < b); }
ZT_ALWAYS_INLINE bool operator()(const uint32_t a,const uint32_t b) const { return (a < b); }
};
private:

View file

@ -55,8 +55,6 @@ public:
{
}
ZT_ALWAYS_INLINE ~Topology() {}
/**
* Add a peer to database
*
@ -173,6 +171,34 @@ public:
}
}
/**
* Apply a function or function object to all peers
*
* This locks the peer map during execution, so calls to get() etc. during
* eachPeer() will deadlock.
*
* @param f Function to apply
* @tparam F Function or function object type
*/
template<typename F>
ZT_ALWAYS_INLINE void eachPeerWithRoot(F f)
{
Mutex::Lock l(_peers_l);
std::vector<uintptr_t> rootPeerPtrs;
for(std::vector< SharedPtr<Peer> >::iterator i(_rootPeers.begin());i!=_rootPeers.end();++i)
rootPeerPtrs.push_back((uintptr_t)i->ptr());
std::sort(rootPeerPtrs.begin(),rootPeerPtrs.end());
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
Address *a = (Address *)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;
while (i.next(a,p)) {
if (!f(*((const SharedPtr<Peer> *)p),std::binary_search(rootPeerPtrs.begin(),rootPeerPtrs.end(),(uintptr_t)p->ptr())))
break;
}
}
/**
* Get the best relay to a given address, which may or may not be a root
*
@ -346,14 +372,24 @@ public:
return false;
}
/**
* Sort roots in asecnding order of apparent latency
*
* @param now Current time
*/
ZT_ALWAYS_INLINE void rankRoots(const int64_t now)
{
Mutex::Lock l1(_peers_l);
std::sort(_rootPeers.begin(),_rootPeers.end(),_RootSortComparisonOperator(now));
}
/**
* Do periodic tasks such as database cleanup
*/
inline void doPeriodicTasks(const int64_t now)
ZT_ALWAYS_INLINE void doPeriodicTasks(const int64_t now)
{
{
Mutex::Lock l1(_peers_l);
std::sort(_rootPeers.begin(),_rootPeers.end(),_RootSortComparisonOperator(now));
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
Address *a = (Address *)0;
SharedPtr<Peer> *p = (SharedPtr<Peer> *)0;

View file

@ -13,8 +13,8 @@
//#define ZT_TRACE
#include <stdio.h>
#include <stdarg.h>
#include <cstdio>
#include <cstdarg>
#include "Trace.hpp"
#include "RuntimeEnvironment.hpp"

View file

@ -372,6 +372,41 @@ template<typename T>
static ZT_ALWAYS_INLINE T ntoh(T n) { return n; }
#endif
static ZT_ALWAYS_INLINE uint64_t readUInt64(const void *const p)
{
#ifdef ZT_NO_TYPE_PUNNING
const uint8_t *const b = reinterpret_cast<const uint8_t *>(p);
return (
((uint64_t)b[0] << 56) |
((uint64_t)b[1] << 48) |
((uint64_t)b[2] << 40) |
((uint64_t)b[3] << 32) |
((uint64_t)b[4] << 24) |
((uint64_t)b[5] << 16) |
((uint64_t)b[6] << 8) |
(uint64_t)b[7]);
#else
return ntoh(*reinterpret_cast<const uint64_t *>(p));
#endif
}
static ZT_ALWAYS_INLINE void putUInt64(void *const p,const uint64_t i)
{
#ifdef ZT_NO_TYPE_PUNNING
uint8_t *const b = reinterpret_cast<uint8_t *>(p);
p[0] = (uint8_t)(i << 56);
p[1] = (uint8_t)(i << 48);
p[2] = (uint8_t)(i << 40);
p[3] = (uint8_t)(i << 32);
p[4] = (uint8_t)(i << 24);
p[5] = (uint8_t)(i << 16);
p[6] = (uint8_t)(i << 8);
p[7] = (uint8_t)i;
#else
*reinterpret_cast<uint64_t *>(p) = Utils::hton(i);
#endif
}
} // namespace Utils
} // namespace ZeroTier

View file

@ -11,10 +11,10 @@
*/
/****/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <stdexcept>
#include <iostream>