Work in progress on crypto stuff, refactoring to back out of use of structs for encode/decode as it is questionably portable.

This commit is contained in:
Adam Ierymenko 2020-04-16 12:34:51 -07:00
parent 16a3c14c53
commit 2b0127c26d
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
45 changed files with 909 additions and 1067 deletions

View file

@ -93,11 +93,7 @@ endif(WIN32)
if (
CMAKE_SYSTEM_PROCESSOR MATCHES "x86_64" OR
CMAKE_SYSTEM_PROCESSOR MATCHES "amd64" OR
CMAKE_SYSTEM_PROCESSOR MATCHES "i386" OR
CMAKE_SYSTEM_PROCESSOR MATCHES "i486" OR
CMAKE_SYSTEM_PROCESSOR MATCHES "i586" OR
CMAKE_SYSTEM_PROCESSOR MATCHES "i686"
CMAKE_SYSTEM_PROCESSOR MATCHES "amd64"
)
message("++ Adding SSE and AES-NI flags for processor ${CMAKE_SYSTEM_PROCESSOR}")
add_compile_options(-maes -mrdrnd -mpclmul -msse -msse2 -mssse3)

View file

@ -29,25 +29,6 @@
#include <sys/socket.h>
#endif
/* ZT_PACKED_STRUCT encloses structs whose contents should be bit-packed.
* Nearly all compilers support this. These macros detect the compiler and
* define it correctly for gcc/icc/clang or MSC. */
#ifndef ZT_PACKED_STRUCT
#if defined(__GCC__) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_1) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_2) || defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4) || defined(__INTEL_COMPILER) || defined(__clang__)
#define ZT_PACKED_STRUCT(D) D __attribute__((packed))
#define ZT_PACKED_STRUCT_START
#define ZT_PACKED_STRUCT_END __attribute__((packed))
#endif
#ifdef _MSC_VER
#define ZT_PACKED_STRUCT(D) __pragma(pack(push,1)) D __pragma(pack(pop))
#define ZT_PACKED_STRUCT_START __pragma(pack(push,1))
#define ZT_PACKED_STRUCT_END __pragma(pack(pop))
#endif
#endif
#ifndef ZT_PACKED_STRUCT
#error Missing a macro to define ZT_PACKED_STRUCT for your compiler.
#endif
#ifdef __cplusplus
#include <cstdint>
extern "C" {
@ -278,7 +259,6 @@ extern "C" {
/* ----------------------------------------------------------------------------------------------------------------- */
/**
* Identity type codes
*/
@ -297,7 +277,7 @@ typedef void ZT_Identity;
/**
* Full identity fingerprint with address and 384-bit hash of public key(s)
*/
ZT_PACKED_STRUCT(struct _ZT_Fingerprint
typedef struct
{
/**
* Short address (only least significant 40 bits are used)
@ -308,8 +288,7 @@ ZT_PACKED_STRUCT(struct _ZT_Fingerprint
* 384-bit hash of identity public key(s)
*/
uint8_t hash[48];
});
typedef struct _ZT_Fingerprint ZT_Fingerprint;
} ZT_Fingerprint;
/**
* Credential type IDs
@ -449,6 +428,8 @@ enum ZT_TraceCredentialRejectionReason
ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID = 4
};
#if 0
/**
* Physical path address from a trace event
*
@ -623,6 +604,8 @@ _ZT_TRACE_EVENT_STRUCT_END()
#undef _ZT_TRACE_EVENT_STRUCT_START
#undef _ZT_TRACE_EVENT_STRUCT_END
#endif
/****************************************************************************/
/**

View file

@ -23,10 +23,9 @@
#ifndef ZT_AES_NO_ACCEL
#ifdef ZT_ARCH_X64
#include <xmmintrin.h>
#include <emmintrin.h>
#include <smmintrin.h>
#include <immintrin.h>
#include <wmmintrin.h>
#define ZT_AES_AESNI 1
#endif
#endif
@ -57,7 +56,7 @@ public:
/**
* Create an un-initialized AES instance (must call init() before use)
*/
ZT_INLINE AES() noexcept // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
ZT_INLINE AES() noexcept
{
Utils::memoryLock(this,sizeof(AES));
}
@ -67,7 +66,7 @@ public:
*
* @param key 256-bit key
*/
explicit ZT_INLINE AES(const void *const key) noexcept // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
explicit ZT_INLINE AES(const void *const key) noexcept
{
Utils::memoryLock(this,sizeof(AES));
this->init(key);
@ -264,7 +263,7 @@ public:
* @param k0 First of two AES instances keyed with K0
* @param k1 Second of two AES instances keyed with K1
*/
ZT_INLINE GMACSIVEncryptor(const AES &k0,const AES &k1) noexcept : // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
ZT_INLINE GMACSIVEncryptor(const AES &k0,const AES &k1) noexcept :
_gmac(k0),
_ctr(k1) {}
@ -383,7 +382,7 @@ public:
class GMACSIVDecryptor
{
public:
ZT_INLINE GMACSIVDecryptor(const AES &k0,const AES &k1) noexcept : // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
ZT_INLINE GMACSIVDecryptor(const AES &k0,const AES &k1) noexcept :
_ctr(k1),
_gmac(k0) {}

View file

@ -107,7 +107,7 @@ public:
ZT_INLINE unsigned long hashCode() const noexcept { return (unsigned long)_a; }
ZT_INLINE operator bool() const noexcept { return (_a != 0); } // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
ZT_INLINE operator bool() const noexcept { return (_a != 0); }
ZT_INLINE bool operator==(const Address &a) const noexcept { return _a == a._a; }
ZT_INLINE bool operator!=(const Address &a) const noexcept { return _a != a._a; }

View file

@ -32,6 +32,7 @@ set(core_headers
OS.hpp
Path.hpp
Peer.hpp
PeerList.hpp
Poly1305.hpp
Protocol.hpp
RuntimeEnvironment.hpp

View file

@ -57,7 +57,7 @@ class Capability : public Credential
public:
static constexpr ZT_CredentialType credentialType() noexcept { return ZT_CREDENTIAL_TYPE_CAPABILITY; }
ZT_INLINE Capability() noexcept { memoryZero(this); } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
ZT_INLINE Capability() noexcept { memoryZero(this); }
/**
* @param id Capability ID

View file

@ -149,6 +149,11 @@
*/
#define ZT_PEER_HELLO_INTERVAL 120000LL
/**
* Timeout for peers being alive
*/
#define ZT_PEER_ALIVE_TIMEOUT ((ZT_PEER_HELLO_INTERVAL * 2) + 5000)
/**
* Global timeout for peers in milliseconds
*

View file

@ -31,18 +31,19 @@
namespace ZeroTier {
#ifdef __CPP11__
struct _MapHasher
struct intl_MapHasher
{
template<typename O>
std::size_t operator()(const O &obj) const noexcept { return (std::size_t)obj.hashCode(); }
std::size_t operator()(const uint64_t i) const noexcept { return (std::size_t)Utils::hash64(i ^ Utils::s_mapNonce); }
std::size_t operator()(const int64_t i) const noexcept { return (std::size_t)Utils::hash64((uint64_t)i ^ Utils::s_mapNonce); }
std::size_t operator()(const uint32_t i) const noexcept { return (std::size_t)Utils::hash32(i ^ (uint32_t)Utils::s_mapNonce); }
std::size_t operator()(const int32_t i) const noexcept { return (std::size_t)Utils::hash32((uint32_t)i ^ (uint32_t)Utils::s_mapNonce); }
std::size_t operator()(const uint64_t i) const noexcept { return (std::size_t)Utils::hash64(i + Utils::s_mapNonce); }
std::size_t operator()(const int64_t i) const noexcept { return (std::size_t)Utils::hash64((uint64_t)i + Utils::s_mapNonce); }
std::size_t operator()(const uint32_t i) const noexcept { return (std::size_t)Utils::hash32(i + (uint32_t)Utils::s_mapNonce); }
std::size_t operator()(const int32_t i) const noexcept { return (std::size_t)Utils::hash32((uint32_t)i + (uint32_t)Utils::s_mapNonce); }
};
template<typename K,typename V>
class Map : public std::unordered_map< K,V,_MapHasher,std::equal_to<K>,Utils::Mallocator< std::pair<const K,V> > >
class Map : public std::unordered_map< K,V,intl_MapHasher,std::equal_to<K>,Utils::Mallocator< std::pair<const K,V> > >
{
public:
ZT_INLINE V *get(const K &key) noexcept
@ -66,7 +67,14 @@ public:
this->emplace(key,value);
}
};
template<typename K,typename V>
class MultiMap : public std::unordered_multimap< K,V,intl_MapHasher,std::equal_to<K>,Utils::Mallocator< std::pair<const K,V> > >
{
};
#else
template<typename K,typename V>
class Map : public std::map< K,V,std::less<K>,Utils::Mallocator< std::pair<const K,V> > >
{
@ -92,6 +100,12 @@ public:
(*this)[key] = value;
}
};
template<typename K,typename V>
class MultiMap : public std::multimap< K,V,std::less<K>,Utils::Mallocator< std::pair<const K,V> > >
{
};
#endif
template<typename K,typename V>

View file

@ -22,10 +22,6 @@
#include "FCV.hpp"
#include "Containers.hpp"
#include <cstring>
#include <cstdlib>
#include <vector>
namespace ZeroTier {
/**

View file

@ -19,10 +19,6 @@ Dictionary::Dictionary()
{
}
Dictionary::~Dictionary()
{
}
std::vector<uint8_t> &Dictionary::operator[](const char *k)
{
return m_entries[s_toKey(k)];

View file

@ -20,8 +20,6 @@
#include "Buf.hpp"
#include "Containers.hpp"
#include <cstdint>
namespace ZeroTier {
/**
@ -42,7 +40,6 @@ class Dictionary
{
public:
Dictionary();
~Dictionary();
/**
* Get a reference to a value

View file

@ -49,7 +49,7 @@ public:
*/
ZT_INLINE void sending(const uint64_t packetId,const int64_t now) noexcept
{
_packetIdSent[Utils::hash64(packetId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS].store((uint32_t)(now / ZT_EXPECT_TTL));
m_packetIdSent[Utils::hash64(packetId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS].store((uint32_t)(now / ZT_EXPECT_TTL));
}
/**
@ -64,12 +64,12 @@ public:
*/
ZT_INLINE bool expecting(const uint64_t inRePacketId,const int64_t now) noexcept
{
return (((now / ZT_EXPECT_TTL) - (int64_t)_packetIdSent[(unsigned long)Utils::hash64(inRePacketId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS].exchange(0)) <= 1);
return (((now / ZT_EXPECT_TTL) - (int64_t)m_packetIdSent[(unsigned long)Utils::hash64(inRePacketId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS].exchange(0)) <= 1);
}
private:
// Each bucket contains a timestamp in units of the max expect duration.
std::atomic<uint32_t> _packetIdSent[ZT_EXPECT_BUCKETS];
std::atomic<uint32_t> m_packetIdSent[ZT_EXPECT_BUCKETS];
};
} // namespace ZeroTier

View file

@ -49,7 +49,7 @@ public:
/**
* @return True if this FCV is trivially copyable, which means its type is also.
*/
static constexpr bool isTriviallyCopyable() noexcept { return isTriviallyCopyable(reinterpret_cast<const T *>(0)); }
static constexpr bool isTriviallyCopyable() noexcept { return ZeroTier::isTriviallyCopyable(reinterpret_cast<const T *>(nullptr)); }
ZT_INLINE FCV() noexcept : _s(0) {} // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
ZT_INLINE FCV(const FCV &v) : _s(0) { *this = v; } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)

View file

@ -43,15 +43,15 @@ public:
*/
ZT_INLINE Fingerprint() noexcept { memoryZero(this); } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
ZT_INLINE Address address() const noexcept { return Address(_fp.address); }
ZT_INLINE const uint8_t *hash() const noexcept { return _fp.hash; }
ZT_INLINE ZT_Fingerprint *apiFingerprint() noexcept { return &_fp; }
ZT_INLINE const ZT_Fingerprint *apiFingerprint() const noexcept { return &_fp; }
ZT_INLINE Address address() const noexcept { return Address(m_cfp.address); }
ZT_INLINE const uint8_t *hash() const noexcept { return m_cfp.hash; }
ZT_INLINE ZT_Fingerprint *apiFingerprint() noexcept { return &m_cfp; }
ZT_INLINE const ZT_Fingerprint *apiFingerprint() const noexcept { return &m_cfp; }
/**
* @return True if hash is not all zero (missing/unspecified)
*/
ZT_INLINE bool haveHash() const noexcept { return (!Utils::allZero(_fp.hash,sizeof(_fp.hash))); }
ZT_INLINE bool haveHash() const noexcept { return (!Utils::allZero(m_cfp.hash, sizeof(m_cfp.hash))); }
/**
* Get a base32-encoded representation of this fingerprint
@ -62,7 +62,7 @@ public:
{
uint8_t tmp[48 + 5];
address().copyTo(tmp);
Utils::copy<48>(tmp + 5,_fp.hash);
Utils::copy<48>(tmp + 5, m_cfp.hash);
Utils::b32e(tmp,sizeof(tmp),s,ZT_FINGERPRINT_STRING_BUFFER_LENGTH);
s[ZT_FINGERPRINT_STRING_BUFFER_LENGTH-1] = 0; // sanity check, ensure always zero terminated
}
@ -78,25 +78,25 @@ public:
uint8_t tmp[48 + 5];
if (Utils::b32d(s,tmp,sizeof(tmp)) != sizeof(tmp))
return false;
_fp.address = Address(tmp).toInt();
Utils::copy<48>(_fp.hash,tmp + 5);
m_cfp.address = Address(tmp).toInt();
Utils::copy<48>(m_cfp.hash, tmp + 5);
return true;
}
ZT_INLINE void zero() noexcept { memoryZero(this); }
ZT_INLINE unsigned long hashCode() const noexcept { return _fp.address; }
ZT_INLINE unsigned long hashCode() const noexcept { return m_cfp.address; }
ZT_INLINE operator bool() const noexcept { return (_fp.address != 0); } // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
ZT_INLINE operator bool() const noexcept { return (m_cfp.address != 0); } // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
ZT_INLINE bool operator==(const Fingerprint &h) const noexcept { return ((_fp.address == h._fp.address) && (memcmp(_fp.hash,h._fp.hash,ZT_FINGERPRINT_HASH_SIZE) == 0)); }
ZT_INLINE bool operator==(const Fingerprint &h) const noexcept { return ((m_cfp.address == h.m_cfp.address) && (memcmp(m_cfp.hash, h.m_cfp.hash, ZT_FINGERPRINT_HASH_SIZE) == 0)); }
ZT_INLINE bool operator!=(const Fingerprint &h) const noexcept { return !(*this == h); }
ZT_INLINE bool operator<(const Fingerprint &h) const noexcept { return ((_fp.address < h._fp.address) || ((_fp.address == h._fp.address) && (memcmp(_fp.hash,h._fp.hash,ZT_FINGERPRINT_HASH_SIZE) < 0))); }
ZT_INLINE bool operator<(const Fingerprint &h) const noexcept { return ((m_cfp.address < h.m_cfp.address) || ((m_cfp.address == h.m_cfp.address) && (memcmp(m_cfp.hash, h.m_cfp.hash, ZT_FINGERPRINT_HASH_SIZE) < 0))); }
ZT_INLINE bool operator>(const Fingerprint &h) const noexcept { return (h < *this); }
ZT_INLINE bool operator<=(const Fingerprint &h) const noexcept { return !(h < *this); }
ZT_INLINE bool operator>=(const Fingerprint &h) const noexcept { return !(*this < h); }
private:
ZT_Fingerprint _fp;
ZT_Fingerprint m_cfp;
};
static_assert(sizeof(Fingerprint) == sizeof(ZT_Fingerprint),"Fingerprint should be the same size as the underlying C ZT_Fingerprint");

View file

@ -176,8 +176,8 @@ const Identity Identity::NIL;
bool Identity::generate(const Type t)
{
_type = t;
_hasPrivate = true;
m_type = t;
m_hasPrivate = true;
switch(t) {
case C25519: {
@ -186,9 +186,9 @@ bool Identity::generate(const Type t)
uint8_t digest[64];
char *const genmem = new char[ZT_V0_IDENTITY_GEN_MEMORY];
do {
C25519::generateSatisfying(identityV0ProofOfWorkCriteria(digest,genmem),_pub.c25519,_priv.c25519);
_address.setTo(digest + 59);
} while (_address.isReserved());
C25519::generateSatisfying(identityV0ProofOfWorkCriteria(digest,genmem), m_pub.c25519, m_priv.c25519);
m_address.setTo(digest + 59);
} while (m_address.isReserved());
delete[] genmem;
_computeHash();
} break;
@ -201,21 +201,21 @@ bool Identity::generate(const Type t)
// Loop until we pass the PoW criteria. The nonce is only 8 bits, so generate
// some new key material every time it wraps. The ECC384 generator is slightly
// faster so use that one.
_pub.nonce = 0;
C25519::generateCombined(_pub.c25519,_priv.c25519);
ECC384GenerateKey(_pub.p384,_priv.p384);
m_pub.nonce = 0;
C25519::generateCombined(m_pub.c25519, m_priv.c25519);
ECC384GenerateKey(m_pub.p384, m_priv.p384);
for(;;) {
if (identityV1ProofOfWorkCriteria(&_pub,sizeof(_pub),b))
if (identityV1ProofOfWorkCriteria(&m_pub, sizeof(m_pub), b))
break;
if (++_pub.nonce == 0)
ECC384GenerateKey(_pub.p384,_priv.p384);
if (++m_pub.nonce == 0)
ECC384GenerateKey(m_pub.p384, m_priv.p384);
}
// If we passed PoW then check that the address is valid, otherwise loop
// back around and run the whole process again.
_computeHash();
_address.setTo(_fp.hash());
if (!_address.isReserved())
m_address.setTo(m_fp.hash());
if (!m_address.isReserved())
break;
}
free(b);
@ -231,24 +231,24 @@ bool Identity::generate(const Type t)
bool Identity::locallyValidate() const noexcept
{
try {
if ((!_address.isReserved()) && (_address)) {
switch (_type) {
if ((!m_address.isReserved()) && (m_address)) {
switch (m_type) {
case C25519: {
uint8_t digest[64];
char *genmem = new char[ZT_V0_IDENTITY_GEN_MEMORY];
identityV0ProofOfWorkFrankenhash(_pub.c25519,ZT_C25519_COMBINED_PUBLIC_KEY_SIZE,digest,genmem);
identityV0ProofOfWorkFrankenhash(m_pub.c25519, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, digest, genmem);
delete[] genmem;
return ((_address == Address(digest + 59)) && (digest[0] < 17));
return ((m_address == Address(digest + 59)) && (digest[0] < 17));
}
case P384: {
if (_address != Address(_fp.hash()))
if (m_address != Address(m_fp.hash()))
return false;
uint64_t *const b = (uint64_t *)malloc(ZT_IDENTITY_V1_POW_MEMORY_SIZE * 8); // NOLINT(hicpp-use-auto,modernize-use-auto)
if (!b)
return false;
const bool ok = identityV1ProofOfWorkCriteria(&_pub,sizeof(_pub),b);
const bool ok = identityV1ProofOfWorkCriteria(&m_pub, sizeof(m_pub), b);
free(b);
return ok;
}
@ -261,15 +261,15 @@ bool Identity::locallyValidate() const noexcept
void Identity::hashWithPrivate(uint8_t h[ZT_FINGERPRINT_HASH_SIZE]) const
{
if (_hasPrivate) {
switch (_type) {
if (m_hasPrivate) {
switch (m_type) {
case C25519:
SHA384(h,_pub.c25519,ZT_C25519_COMBINED_PUBLIC_KEY_SIZE,_priv.c25519,ZT_C25519_COMBINED_PRIVATE_KEY_SIZE);
SHA384(h, m_pub.c25519, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv.c25519, ZT_C25519_COMBINED_PRIVATE_KEY_SIZE);
break;
case P384:
SHA384(h,&_pub,sizeof(_pub),&_priv,sizeof(_priv));
SHA384(h, &m_pub, sizeof(m_pub), &m_priv, sizeof(m_priv));
break;
}
@ -280,20 +280,20 @@ void Identity::hashWithPrivate(uint8_t h[ZT_FINGERPRINT_HASH_SIZE]) const
unsigned int Identity::sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const
{
if (_hasPrivate) {
switch(_type) {
if (m_hasPrivate) {
switch(m_type) {
case C25519:
if (siglen >= ZT_C25519_SIGNATURE_LEN) {
C25519::sign(_priv.c25519,_pub.c25519,data,len,sig);
C25519::sign(m_priv.c25519, m_pub.c25519, data, len, sig);
return ZT_C25519_SIGNATURE_LEN;
}
case P384:
if (siglen >= ZT_ECC384_SIGNATURE_SIZE) {
uint8_t h[48];
SHA384(h,data,len,&_pub,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE); // include C25519 public key in hash
ECC384ECDSASign(_priv.p384,h,(uint8_t *)sig);
SHA384(h, data, len, &m_pub, ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE); // include C25519 public key in hash
ECC384ECDSASign(m_priv.p384, h, (uint8_t *)sig);
return ZT_ECC384_SIGNATURE_SIZE;
}
@ -304,16 +304,16 @@ unsigned int Identity::sign(const void *data,unsigned int len,void *sig,unsigned
bool Identity::verify(const void *data,unsigned int len,const void *sig,unsigned int siglen) const
{
switch(_type) {
switch(m_type) {
case C25519:
return C25519::verify(_pub.c25519,data,len,sig,siglen);
return C25519::verify(m_pub.c25519, data, len, sig, siglen);
case P384:
if (siglen == ZT_ECC384_SIGNATURE_SIZE) {
uint8_t h[48];
SHA384(h,data,len,&_pub,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
return ECC384ECDSAVerify(_pub.p384,h,(const uint8_t *)sig);
SHA384(h, data, len, &m_pub, ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
return ECC384ECDSAVerify(m_pub.p384, h, (const uint8_t *)sig);
}
break;
@ -325,34 +325,34 @@ bool Identity::agree(const Identity &id,uint8_t key[ZT_SYMMETRIC_KEY_SIZE]) cons
{
uint8_t rawkey[128];
uint8_t h[64];
if (_hasPrivate) {
if (_type == C25519) {
if (m_hasPrivate) {
if (m_type == C25519) {
if ((id._type == C25519)||(id._type == P384)) {
if ((id.m_type == C25519) || (id.m_type == P384)) {
// If we are a C25519 key we can agree with another C25519 key or with only the
// C25519 portion of a type 1 P-384 key.
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
C25519::agree(m_priv.c25519, id.m_pub.c25519, rawkey);
SHA512(h,rawkey,ZT_C25519_ECDH_SHARED_SECRET_SIZE);
Utils::copy<ZT_SYMMETRIC_KEY_SIZE>(key,h);
return true;
}
} else if (_type == P384) {
} else if (m_type == P384) {
if (id._type == P384) {
if (id.m_type == P384) {
// For another P384 identity we execute DH agreement with BOTH keys and then
// hash the results together. For those (cough FIPS cough) who only consider
// P384 to be kosher, the C25519 secret can be considered a "salt"
// or something. For those who don't trust P384 this means the privacy of
// your traffic is also protected by C25519.
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
ECC384ECDH(id._pub.p384,_priv.p384,rawkey + ZT_C25519_ECDH_SHARED_SECRET_SIZE);
C25519::agree(m_priv.c25519, id.m_pub.c25519, rawkey);
ECC384ECDH(id.m_pub.p384, m_priv.p384, rawkey + ZT_C25519_ECDH_SHARED_SECRET_SIZE);
SHA384(h,rawkey,ZT_C25519_ECDH_SHARED_SECRET_SIZE + ZT_ECC384_SHARED_SECRET_SIZE);
Utils::copy<ZT_SYMMETRIC_KEY_SIZE>(key,h);
return true;
} else if (id._type == C25519) {
} else if (id.m_type == C25519) {
// If the other identity is a C25519 identity we can agree using only that type.
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
C25519::agree(m_priv.c25519, id.m_pub.c25519, rawkey);
SHA512(h,rawkey,ZT_C25519_ECDH_SHARED_SECRET_SIZE);
Utils::copy<ZT_SYMMETRIC_KEY_SIZE>(key,h);
return true;
@ -366,20 +366,20 @@ bool Identity::agree(const Identity &id,uint8_t key[ZT_SYMMETRIC_KEY_SIZE]) cons
char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const
{
char *p = buf;
_address.toString(p);
m_address.toString(p);
p += 10;
*(p++) = ':';
switch(_type) {
switch(m_type) {
case C25519: {
*(p++) = '0';
*(p++) = ':';
Utils::hex(_pub.c25519,ZT_C25519_COMBINED_PUBLIC_KEY_SIZE,p);
Utils::hex(m_pub.c25519, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, p);
p += ZT_C25519_COMBINED_PUBLIC_KEY_SIZE * 2;
if ((_hasPrivate)&&(includePrivate)) {
if ((m_hasPrivate) && (includePrivate)) {
*(p++) = ':';
Utils::hex(_priv.c25519,ZT_C25519_COMBINED_PRIVATE_KEY_SIZE,p);
Utils::hex(m_priv.c25519, ZT_C25519_COMBINED_PRIVATE_KEY_SIZE, p);
p += ZT_C25519_COMBINED_PRIVATE_KEY_SIZE * 2;
}
*p = (char)0;
@ -389,12 +389,12 @@ char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_
case P384: {
*(p++) = '1';
*(p++) = ':';
int el = Utils::b32e((const uint8_t *)(&_pub),sizeof(_pub),p,(int)(ZT_IDENTITY_STRING_BUFFER_LENGTH - (uintptr_t)(p - buf)));
int el = Utils::b32e((const uint8_t *)(&m_pub), sizeof(m_pub), p, (int)(ZT_IDENTITY_STRING_BUFFER_LENGTH - (uintptr_t)(p - buf)));
if (el <= 0) return nullptr;
p += el;
if ((_hasPrivate)&&(includePrivate)) {
if ((m_hasPrivate) && (includePrivate)) {
*(p++) = ':';
el = Utils::b32e((const uint8_t *)(&_priv),sizeof(_priv),p,(int)(ZT_IDENTITY_STRING_BUFFER_LENGTH - (uintptr_t)(p - buf)));
el = Utils::b32e((const uint8_t *)(&m_priv), sizeof(m_priv), p, (int)(ZT_IDENTITY_STRING_BUFFER_LENGTH - (uintptr_t)(p - buf)));
if (el <= 0) return nullptr;
p += el;
}
@ -409,17 +409,17 @@ char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_
bool Identity::fromString(const char *str)
{
_fp.zero();
_hasPrivate = false;
m_fp.zero();
m_hasPrivate = false;
if (!str) {
_address.zero();
m_address.zero();
return false;
}
char tmp[ZT_IDENTITY_STRING_BUFFER_LENGTH];
if (!Utils::scopy(tmp,sizeof(tmp),str)) {
_address.zero();
m_address.zero();
return false;
}
@ -429,37 +429,37 @@ bool Identity::fromString(const char *str)
switch(fno++) {
case 0:
_address = Address(Utils::hexStrToU64(f));
if (_address.isReserved()) {
_address.zero();
m_address = Address(Utils::hexStrToU64(f));
if (m_address.isReserved()) {
m_address.zero();
return false;
}
break;
case 1:
if ((f[0] == '0')&&(!f[1])) {
_type = C25519;
m_type = C25519;
} else if ((f[0] == '1')&&(!f[1])) {
_type = P384;
m_type = P384;
} else {
_address.zero();
m_address.zero();
return false;
}
break;
case 2:
switch(_type) {
switch(m_type) {
case C25519:
if (Utils::unhex(f,strlen(f),_pub.c25519,ZT_C25519_COMBINED_PUBLIC_KEY_SIZE) != ZT_C25519_COMBINED_PUBLIC_KEY_SIZE) {
_address.zero();
if (Utils::unhex(f, strlen(f), m_pub.c25519, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE) != ZT_C25519_COMBINED_PUBLIC_KEY_SIZE) {
m_address.zero();
return false;
}
break;
case P384:
if (Utils::b32d(f,(uint8_t *)(&_pub),sizeof(_pub)) != sizeof(_pub)) {
_address.zero();
if (Utils::b32d(f, (uint8_t *)(&m_pub), sizeof(m_pub)) != sizeof(m_pub)) {
m_address.zero();
return false;
}
break;
@ -469,23 +469,23 @@ bool Identity::fromString(const char *str)
case 3:
if (strlen(f) > 1) {
switch(_type) {
switch(m_type) {
case C25519:
if (Utils::unhex(f,strlen(f),_priv.c25519,ZT_C25519_COMBINED_PRIVATE_KEY_SIZE) != ZT_C25519_COMBINED_PRIVATE_KEY_SIZE) {
_address.zero();
if (Utils::unhex(f, strlen(f), m_priv.c25519, ZT_C25519_COMBINED_PRIVATE_KEY_SIZE) != ZT_C25519_COMBINED_PRIVATE_KEY_SIZE) {
m_address.zero();
return false;
} else {
_hasPrivate = true;
m_hasPrivate = true;
}
break;
case P384:
if (Utils::b32d(f,(uint8_t *)(&_priv),sizeof(_priv)) != sizeof(_priv)) {
_address.zero();
if (Utils::b32d(f, (uint8_t *)(&m_priv), sizeof(m_priv)) != sizeof(m_priv)) {
m_address.zero();
return false;
} else {
_hasPrivate = true;
m_hasPrivate = true;
}
break;
@ -497,13 +497,13 @@ bool Identity::fromString(const char *str)
}
if (fno < 3) {
_address.zero();
m_address.zero();
return false;
}
_computeHash();
if ((_type == P384)&&(_address != Address(_fp.hash()))) {
_address.zero();
if ((m_type == P384) && (m_address != Address(m_fp.hash()))) {
m_address.zero();
return false;
}
@ -512,14 +512,14 @@ bool Identity::fromString(const char *str)
int Identity::marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool includePrivate) const noexcept
{
_address.copyTo(data);
switch(_type) {
m_address.copyTo(data);
switch(m_type) {
case C25519:
data[ZT_ADDRESS_LENGTH] = (uint8_t)C25519;
Utils::copy<ZT_C25519_COMBINED_PUBLIC_KEY_SIZE>(data + ZT_ADDRESS_LENGTH + 1,_pub.c25519);
if ((includePrivate)&&(_hasPrivate)) {
Utils::copy<ZT_C25519_COMBINED_PUBLIC_KEY_SIZE>(data + ZT_ADDRESS_LENGTH + 1, m_pub.c25519);
if ((includePrivate)&&(m_hasPrivate)) {
data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE] = ZT_C25519_COMBINED_PRIVATE_KEY_SIZE;
Utils::copy<ZT_C25519_COMBINED_PRIVATE_KEY_SIZE>(data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1,_priv.c25519);
Utils::copy<ZT_C25519_COMBINED_PRIVATE_KEY_SIZE>(data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1, m_priv.c25519);
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1 + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE;
} else {
data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE] = 0;
@ -528,10 +528,10 @@ int Identity::marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool incl
case P384:
data[ZT_ADDRESS_LENGTH] = (uint8_t)P384;
Utils::copy<ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE>(data + ZT_ADDRESS_LENGTH + 1,&_pub);
if ((includePrivate)&&(_hasPrivate)) {
Utils::copy<ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE>(data + ZT_ADDRESS_LENGTH + 1,&m_pub);
if ((includePrivate)&&(m_hasPrivate)) {
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
Utils::copy<ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE>(data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,&_priv);
Utils::copy<ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE>(data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,&m_priv);
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
} else {
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = 0;
@ -544,32 +544,32 @@ int Identity::marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool incl
int Identity::unmarshal(const uint8_t *data,const int len) noexcept
{
_fp.zero();
_hasPrivate = false;
m_fp.zero();
m_hasPrivate = false;
if (len < (1 + ZT_ADDRESS_LENGTH))
return -1;
_address.setTo(data);
m_address.setTo(data);
unsigned int privlen;
switch((_type = (Type)data[ZT_ADDRESS_LENGTH])) {
switch((m_type = (Type)data[ZT_ADDRESS_LENGTH])) {
case C25519:
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1))
return -1;
Utils::copy<ZT_C25519_COMBINED_PUBLIC_KEY_SIZE>(_pub.c25519,data + ZT_ADDRESS_LENGTH + 1);
Utils::copy<ZT_C25519_COMBINED_PUBLIC_KEY_SIZE>(m_pub.c25519, data + ZT_ADDRESS_LENGTH + 1);
_computeHash();
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE];
if (privlen == ZT_C25519_COMBINED_PRIVATE_KEY_SIZE) {
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1 + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE))
return -1;
_hasPrivate = true;
Utils::copy<ZT_C25519_COMBINED_PRIVATE_KEY_SIZE>(_priv.c25519,data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1);
m_hasPrivate = true;
Utils::copy<ZT_C25519_COMBINED_PRIVATE_KEY_SIZE>(m_priv.c25519, data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1);
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1 + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE;
} else if (privlen == 0) {
_hasPrivate = false;
m_hasPrivate = false;
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1;
}
break;
@ -578,20 +578,20 @@ int Identity::unmarshal(const uint8_t *data,const int len) noexcept
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1))
return -1;
Utils::copy<ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE>(&_pub,data + ZT_ADDRESS_LENGTH + 1);
Utils::copy<ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE>(&m_pub, data + ZT_ADDRESS_LENGTH + 1);
_computeHash(); // this sets the address for P384
if (_address != Address(_fp.hash())) // this sanity check is possible with V1 identities
if (m_address != Address(m_fp.hash())) // this sanity check is possible with V1 identities
return -1;
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE];
if (privlen == ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE) {
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE))
return -1;
_hasPrivate = true;
Utils::copy<ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE>(&_priv,data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1);
m_hasPrivate = true;
Utils::copy<ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE>(&m_priv, data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1);
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
} else if (privlen == 0) {
_hasPrivate = false;
m_hasPrivate = false;
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1;
}
break;
@ -603,19 +603,19 @@ int Identity::unmarshal(const uint8_t *data,const int len) noexcept
void Identity::_computeHash()
{
switch(_type) {
switch(m_type) {
default:
_fp.zero();
m_fp.zero();
break;
case C25519:
_fp._fp.address = _address.toInt();
SHA384(_fp._fp.hash,_pub.c25519,ZT_C25519_COMBINED_PUBLIC_KEY_SIZE);
m_fp.m_cfp.address = m_address.toInt();
SHA384(m_fp.m_cfp.hash, m_pub.c25519, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE);
break;
case P384:
SHA384(_fp._fp.hash,&_pub,sizeof(_pub));
_fp._fp.address = _address.toInt();
SHA384(m_fp.m_cfp.hash, &m_pub, sizeof(m_pub));
m_fp.m_cfp.address = m_address.toInt();
break;
}
}

View file

@ -22,6 +22,7 @@
#include "ECC384.hpp"
#include "TriviallyCopyable.hpp"
#include "Fingerprint.hpp"
#include "Containers.hpp"
#include <cstdio>
#include <cstdlib>
@ -86,7 +87,7 @@ public:
ZT_INLINE ~Identity()
{
Utils::memoryUnlock(this,sizeof(Identity));
Utils::burn(reinterpret_cast<void *>(&this->_priv),sizeof(this->_priv));
Utils::burn(reinterpret_cast<void *>(&this->m_priv), sizeof(this->m_priv));
}
/**
@ -97,7 +98,7 @@ public:
/**
* @return Identity type (undefined if identity is null or invalid)
*/
ZT_INLINE Type type() const noexcept { return _type; }
ZT_INLINE Type type() const noexcept { return m_type; }
/**
* Generate a new identity (address, key pair)
@ -123,7 +124,7 @@ public:
/**
* @return True if this identity contains a private key
*/
ZT_INLINE bool hasPrivate() const noexcept { return _hasPrivate; }
ZT_INLINE bool hasPrivate() const noexcept { return m_hasPrivate; }
/**
* Get a 384-bit hash of this identity's public key(s)
@ -137,7 +138,7 @@ public:
*
* @return Hash of public key(s)
*/
ZT_INLINE const Fingerprint &fingerprint() const noexcept { return _fp; }
ZT_INLINE const Fingerprint &fingerprint() const noexcept { return m_fp; }
/**
* Compute a hash of this identity's public and private keys.
@ -187,7 +188,7 @@ public:
/**
* @return This identity's address
*/
ZT_INLINE Address address() const noexcept { return _address; }
ZT_INLINE Address address() const noexcept { return m_address; }
/**
* Serialize to a more human-friendly string
@ -197,6 +198,7 @@ public:
* @return ASCII string representation of identity (pointer to buf)
*/
char *toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const;
ZT_INLINE String toString(const bool includePrivate = false) const { char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]; toString(includePrivate); return String(buf); }
/**
* Deserialize a human-friendly string
@ -212,13 +214,13 @@ public:
/**
* @return True if this identity contains something
*/
explicit ZT_INLINE operator bool() const noexcept { return (_address); }
explicit ZT_INLINE operator bool() const noexcept { return (m_address); }
ZT_INLINE unsigned long hashCode() const noexcept { return _fp.hashCode(); }
ZT_INLINE unsigned long hashCode() const noexcept { return m_fp.hashCode(); }
ZT_INLINE bool operator==(const Identity &id) const noexcept { return (_fp == id._fp); }
ZT_INLINE bool operator==(const Identity &id) const noexcept { return (m_fp == id.m_fp); }
ZT_INLINE bool operator!=(const Identity &id) const noexcept { return !(*this == id); }
ZT_INLINE bool operator<(const Identity &id) const noexcept { return (_fp < id._fp); }
ZT_INLINE bool operator<(const Identity &id) const noexcept { return (m_fp < id.m_fp); }
ZT_INLINE bool operator>(const Identity &id) const noexcept { return (id < *this); }
ZT_INLINE bool operator<=(const Identity &id) const noexcept { return !(id < *this); }
ZT_INLINE bool operator>=(const Identity &id) const noexcept { return !(*this < id); }
@ -230,19 +232,19 @@ public:
private:
void _computeHash();
Address _address;
Fingerprint _fp;
Address m_address;
Fingerprint m_fp;
ZT_PACKED_STRUCT(struct { // do not re-order these fields
uint8_t c25519[ZT_C25519_COMBINED_PRIVATE_KEY_SIZE];
uint8_t p384[ZT_ECC384_PRIVATE_KEY_SIZE];
}) _priv;
}) m_priv;
ZT_PACKED_STRUCT(struct { // do not re-order these fields
uint8_t nonce; // nonce for PoW generate/verify
uint8_t c25519[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE]; // Curve25519 and Ed25519 public keys
uint8_t p384[ZT_ECC384_PUBLIC_KEY_SIZE]; // NIST P-384 public key
}) _pub;
Type _type; // _type determines which fields in _priv and _pub are used
bool _hasPrivate;
}) m_pub;
Type m_type; // _type determines which fields in _priv and _pub are used
bool m_hasPrivate;
};
} // namespace ZeroTier

View file

@ -26,7 +26,7 @@ const InetAddress InetAddress::NIL;
InetAddress::IpScope InetAddress::ipScope() const noexcept
{
switch(_data.ss_family) {
switch(m_sockaddr.ss_family) {
case AF_INET: {
const uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr);
@ -99,11 +99,11 @@ void InetAddress::set(const void *ipBytes,unsigned int ipLen,unsigned int port)
if (ipLen == 4) {
uint32_t ipb[1];
Utils::copy<4>(ipb,ipBytes);
_data.ss_family = AF_INET;
m_sockaddr.ss_family = AF_INET;
reinterpret_cast<sockaddr_in *>(this)->sin_addr.s_addr = ipb[0];
reinterpret_cast<sockaddr_in *>(this)->sin_port = Utils::hton((uint16_t)port);
} else if (ipLen == 16) {
_data.ss_family = AF_INET6;
m_sockaddr.ss_family = AF_INET6;
Utils::copy<16>(reinterpret_cast<sockaddr_in6 *>(this)->sin6_addr.s6_addr,ipBytes);
reinterpret_cast<sockaddr_in6 *>(this)->sin6_port = Utils::hton((uint16_t)port);
}
@ -111,7 +111,7 @@ void InetAddress::set(const void *ipBytes,unsigned int ipLen,unsigned int port)
bool InetAddress::isDefaultRoute() const noexcept
{
switch(_data.ss_family) {
switch(m_sockaddr.ss_family) {
case AF_INET:
return ( (reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr == 0) && (reinterpret_cast<const sockaddr_in *>(this)->sin_port == 0) );
case AF_INET6:
@ -139,7 +139,7 @@ char *InetAddress::toString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noex
char *InetAddress::toIpString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noexcept
{
buf[0] = (char)0;
switch(_data.ss_family) {
switch(m_sockaddr.ss_family) {
case AF_INET: {
#ifdef _WIN32
inet_ntop(AF_INET, (void*)&reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN);
@ -199,7 +199,7 @@ bool InetAddress::fromString(const char *ipSlashPort) noexcept
InetAddress InetAddress::netmask() const noexcept
{
InetAddress r(*this);
switch(r._data.ss_family) {
switch(r.m_sockaddr.ss_family) {
case AF_INET:
reinterpret_cast<sockaddr_in *>(&r)->sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffffU << (32 - netmaskBits())));
break;
@ -221,7 +221,7 @@ InetAddress InetAddress::netmask() const noexcept
InetAddress InetAddress::broadcast() const noexcept
{
if (_data.ss_family == AF_INET) {
if (m_sockaddr.ss_family == AF_INET) {
InetAddress r(*this);
reinterpret_cast<sockaddr_in *>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffffU >> netmaskBits()));
return r;
@ -232,7 +232,7 @@ InetAddress InetAddress::broadcast() const noexcept
InetAddress InetAddress::network() const noexcept
{
InetAddress r(*this);
switch(r._data.ss_family) {
switch(r.m_sockaddr.ss_family) {
case AF_INET:
reinterpret_cast<sockaddr_in *>(&r)->sin_addr.s_addr &= Utils::hton((uint32_t)(0xffffffffU << (32 - netmaskBits())));
break;
@ -250,8 +250,8 @@ InetAddress InetAddress::network() const noexcept
bool InetAddress::isEqualPrefix(const InetAddress &addr) const noexcept
{
if (addr._data.ss_family == _data.ss_family) {
switch(_data.ss_family) {
if (addr.m_sockaddr.ss_family == m_sockaddr.ss_family) {
switch(m_sockaddr.ss_family) {
case AF_INET6: {
const InetAddress mask(netmask());
InetAddress addr_mask(addr.netmask());
@ -272,8 +272,8 @@ bool InetAddress::isEqualPrefix(const InetAddress &addr) const noexcept
bool InetAddress::containsAddress(const InetAddress &addr) const noexcept
{
if (addr._data.ss_family == _data.ss_family) {
switch(_data.ss_family) {
if (addr.m_sockaddr.ss_family == m_sockaddr.ss_family) {
switch(m_sockaddr.ss_family) {
case AF_INET: {
const unsigned int bits = netmaskBits();
if (bits == 0)
@ -302,7 +302,7 @@ bool InetAddress::containsAddress(const InetAddress &addr) const noexcept
void InetAddress::forTrace(ZT_TraceEventPathAddress &ta) const noexcept
{
uint32_t tmp;
switch(_data.ss_family) {
switch(m_sockaddr.ss_family) {
default:
Utils::zero<sizeof(ZT_TraceEventPathAddress)>(&ta);
break;
@ -327,7 +327,7 @@ void InetAddress::forTrace(ZT_TraceEventPathAddress &ta) const noexcept
bool InetAddress::isNetwork() const noexcept
{
switch(_data.ss_family) {
switch(m_sockaddr.ss_family) {
case AF_INET: {
unsigned int bits = netmaskBits();
if (bits <= 0)
@ -360,7 +360,7 @@ bool InetAddress::isNetwork() const noexcept
int InetAddress::marshal(uint8_t data[ZT_INETADDRESS_MARSHAL_SIZE_MAX]) const noexcept
{
unsigned int port;
switch(_data.ss_family) {
switch(m_sockaddr.ss_family) {
case AF_INET:
port = Utils::ntoh((uint16_t)reinterpret_cast<const sockaddr_in *>(this)->sin_port);
data[0] = 4;
@ -421,8 +421,8 @@ int InetAddress::unmarshal(const uint8_t *restrict data,const int len) noexcept
bool InetAddress::operator==(const InetAddress &a) const noexcept
{
if (_data.ss_family == a._data.ss_family) {
switch(_data.ss_family) {
if (m_sockaddr.ss_family == a.m_sockaddr.ss_family) {
switch(m_sockaddr.ss_family) {
case AF_INET:
return (
(reinterpret_cast<const sockaddr_in *>(this)->sin_port == reinterpret_cast<const sockaddr_in *>(&a)->sin_port)&&
@ -442,10 +442,10 @@ bool InetAddress::operator==(const InetAddress &a) const noexcept
bool InetAddress::operator<(const InetAddress &a) const noexcept
{
if (_data.ss_family < a._data.ss_family)
if (m_sockaddr.ss_family < a.m_sockaddr.ss_family)
return true;
else if (_data.ss_family == a._data.ss_family) {
switch(_data.ss_family) {
else if (m_sockaddr.ss_family == a.m_sockaddr.ss_family) {
switch(m_sockaddr.ss_family) {
case AF_INET:
if (reinterpret_cast<const sockaddr_in *>(this)->sin_port < reinterpret_cast<const sockaddr_in *>(&a)->sin_port)
return true;

View file

@ -166,7 +166,7 @@ public:
/**
* @return Address family (ss_family in sockaddr_storage)
*/
ZT_INLINE uint8_t family() const noexcept { return _data.ss_family; }
ZT_INLINE uint8_t family() const noexcept { return m_sockaddr.ss_family; }
/**
* @return IP scope classification (e.g. loopback, link-local, private, global)
@ -189,7 +189,7 @@ public:
*/
ZT_INLINE void setPort(unsigned int port) noexcept
{
switch(_data.ss_family) {
switch(m_sockaddr.ss_family) {
case AF_INET:
reinterpret_cast<sockaddr_in *>(this)->sin_port = Utils::hton((uint16_t)port);
break;
@ -227,7 +227,7 @@ public:
*/
ZT_INLINE unsigned int port() const noexcept
{
switch(_data.ss_family) {
switch(m_sockaddr.ss_family) {
case AF_INET: return Utils::ntoh((uint16_t)(reinterpret_cast<const sockaddr_in *>(this)->sin_port));
case AF_INET6: return Utils::ntoh((uint16_t)(reinterpret_cast<const sockaddr_in6 *>(this)->sin6_port));
default: return 0;
@ -251,7 +251,7 @@ public:
ZT_INLINE bool netmaskBitsValid() const noexcept
{
const unsigned int n = port();
switch(_data.ss_family) {
switch(m_sockaddr.ss_family) {
case AF_INET: return (n <= 32);
case AF_INET6: return (n <= 128);
}
@ -323,7 +323,7 @@ public:
*/
ZT_INLINE const void *rawIpData() const noexcept
{
switch(_data.ss_family) {
switch(m_sockaddr.ss_family) {
case AF_INET: return (const void *)&(reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr);
case AF_INET6: return (const void *)(reinterpret_cast<const sockaddr_in6 *>(this)->sin6_addr.s6_addr);
default: return nullptr;
@ -336,7 +336,7 @@ public:
ZT_INLINE InetAddress ipOnly() const noexcept
{
InetAddress r;
switch(_data.ss_family) {
switch(m_sockaddr.ss_family) {
case AF_INET:
reinterpret_cast<sockaddr_in *>(&r)->sin_family = AF_INET;
reinterpret_cast<sockaddr_in *>(&r)->sin_addr.s_addr = reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr;
@ -357,8 +357,8 @@ public:
*/
ZT_INLINE bool ipsEqual(const InetAddress &a) const noexcept
{
const uint8_t f = _data.ss_family;
if (f == a._data.ss_family) {
const uint8_t f = m_sockaddr.ss_family;
if (f == a.m_sockaddr.ss_family) {
if (f == AF_INET)
return (reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr == reinterpret_cast<const sockaddr_in *>(&a)->sin_addr.s_addr);
if (f == AF_INET6)
@ -378,8 +378,8 @@ public:
*/
ZT_INLINE bool ipsEqual2(const InetAddress &a) const noexcept
{
const uint8_t f = _data.ss_family;
if (f == a._data.ss_family) {
const uint8_t f = m_sockaddr.ss_family;
if (f == a.m_sockaddr.ss_family) {
if (f == AF_INET)
return (reinterpret_cast<const sockaddr_in *>(this)->sin_addr.s_addr == reinterpret_cast<const sockaddr_in *>(&a)->sin_addr.s_addr);
if (f == AF_INET6)
@ -391,16 +391,16 @@ public:
ZT_INLINE unsigned long hashCode() const noexcept
{
if (_data.ss_family == AF_INET) {
return (unsigned long)Utils::hash32(((uint32_t)reinterpret_cast<const sockaddr_in *>(&_data)->sin_addr.s_addr + (uint32_t)reinterpret_cast<const sockaddr_in *>(&_data)->sin_port) ^ (uint32_t)Utils::s_mapNonce);
} else if (_data.ss_family == AF_INET6) {
if (m_sockaddr.ss_family == AF_INET) {
return (unsigned long)Utils::hash32(((uint32_t)reinterpret_cast<const sockaddr_in *>(&m_sockaddr)->sin_addr.s_addr + (uint32_t)reinterpret_cast<const sockaddr_in *>(&m_sockaddr)->sin_port) ^ (uint32_t)Utils::s_mapNonce);
} else if (m_sockaddr.ss_family == AF_INET6) {
return (unsigned long)Utils::hash64(
(Utils::loadAsIsEndian<uint64_t>(reinterpret_cast<const sockaddr_in6 *>(&_data)->sin6_addr.s6_addr) +
Utils::loadAsIsEndian<uint64_t>(reinterpret_cast<const sockaddr_in6 *>(&_data)->sin6_addr.s6_addr + 8) +
(uint64_t)reinterpret_cast<const sockaddr_in6 *>(&_data)->sin6_port) ^ Utils::s_mapNonce
(Utils::loadAsIsEndian<uint64_t>(reinterpret_cast<const sockaddr_in6 *>(&m_sockaddr)->sin6_addr.s6_addr) +
Utils::loadAsIsEndian<uint64_t>(reinterpret_cast<const sockaddr_in6 *>(&m_sockaddr)->sin6_addr.s6_addr + 8) +
(uint64_t)reinterpret_cast<const sockaddr_in6 *>(&m_sockaddr)->sin6_port) ^ Utils::s_mapNonce
);
}
return Utils::fnv1a32(&_data,sizeof(_data));
return Utils::fnv1a32(&m_sockaddr, sizeof(m_sockaddr));
}
/**
@ -493,7 +493,7 @@ public:
static InetAddress makeIpv66plane(uint64_t nwid,uint64_t zeroTierAddress) noexcept;
private:
sockaddr_storage _data;
sockaddr_storage m_sockaddr;
};
static_assert(sizeof(sockaddr_storage) == sizeof(InetAddress),"InetAddress sizing incorrect");

View file

@ -20,50 +20,50 @@ bool Locator::sign(const int64_t ts,const Identity &id) noexcept
uint8_t signData[ZT_LOCATOR_MARSHAL_SIZE_MAX];
if (!id.hasPrivate())
return false;
_ts = ts;
if (_endpointCount > 0)
std::sort(_at,_at + _endpointCount);
m_ts = ts;
if (m_endpointCount > 0)
std::sort(m_at, m_at + m_endpointCount);
const unsigned int signLen = marshal(signData,true);
_signatureLength = id.sign(signData, signLen, _signature, sizeof(_signature));
return (_signatureLength > 0);
m_signatureLength = id.sign(signData, signLen, m_signature, sizeof(m_signature));
return (m_signatureLength > 0);
}
bool Locator::verify(const Identity &id) const noexcept
{
if ((_ts == 0)||(_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE))
if ((m_ts == 0) || (m_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS) || (m_signatureLength > ZT_SIGNATURE_BUFFER_SIZE))
return false;
uint8_t signData[ZT_LOCATOR_MARSHAL_SIZE_MAX];
const unsigned int signLen = marshal(signData,true);
return id.verify(signData,signLen,_signature,_signatureLength);
return id.verify(signData, signLen, m_signature, m_signatureLength);
}
int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],const bool excludeSignature) const noexcept
{
if ((_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS)||(_signatureLength > ZT_SIGNATURE_BUFFER_SIZE))
if ((m_endpointCount > ZT_LOCATOR_MAX_ENDPOINTS) || (m_signatureLength > ZT_SIGNATURE_BUFFER_SIZE))
return -1;
data[0] = 0xff; // version byte, currently 0xff to never be the same as byte 0 of an identity for legacy compatibility reasons
Utils::storeBigEndian<int64_t>(data + 1,_ts);
Utils::storeBigEndian<int64_t>(data + 1, m_ts);
int p = 9;
if (_ts > 0) {
Utils::storeBigEndian(data + p,(uint16_t)_endpointCount);
if (m_ts > 0) {
Utils::storeBigEndian(data + p,(uint16_t)m_endpointCount);
p += 2;
for (unsigned int i = 0; i < _endpointCount; ++i) {
int tmp = _at[i].marshal(data + p);
for (unsigned int i = 0;i < m_endpointCount;++i) {
int tmp = m_at[i].marshal(data + p);
if (tmp < 0)
return -1;
p += tmp;
}
if (!excludeSignature) {
Utils::storeBigEndian(data + p,(uint16_t)_signatureLength);
Utils::storeBigEndian(data + p,(uint16_t)m_signatureLength);
p += 2;
Utils::copy(data + p,_signature,_signatureLength);
p += (int)_signatureLength;
Utils::copy(data + p, m_signature, m_signatureLength);
p += (int)m_signatureLength;
}
Utils::storeBigEndian(data + p,_flags);
Utils::storeBigEndian(data + p, m_flags);
p += 2;
}
@ -77,17 +77,17 @@ int Locator::unmarshal(const uint8_t *restrict data,const int len) noexcept
if (data[0] != 0xff)
return -1;
_ts = Utils::loadBigEndian<int64_t>(data + 1);
m_ts = Utils::loadBigEndian<int64_t>(data + 1);
int p = 9;
if (_ts > 0) {
if (m_ts > 0) {
const unsigned int ec = Utils::loadBigEndian<uint16_t>(data + p);
p += 2;
if (ec > ZT_LOCATOR_MAX_ENDPOINTS)
return -1;
_endpointCount = ec;
m_endpointCount = ec;
for (unsigned int i = 0; i < ec; ++i) {
int tmp = _at[i].unmarshal(data + p,len - p);
int tmp = m_at[i].unmarshal(data + p, len - p);
if (tmp < 0)
return -1;
p += tmp;
@ -99,18 +99,18 @@ int Locator::unmarshal(const uint8_t *restrict data,const int len) noexcept
p += 2;
if (sl > ZT_SIGNATURE_BUFFER_SIZE)
return -1;
_signatureLength = sl;
m_signatureLength = sl;
if ((p + (int)sl) > len)
return -1;
Utils::copy(_signature,data + p,sl);
Utils::copy(m_signature, data + p, sl);
p += (int)sl;
if ((p + 2) > len)
return -1;
_flags = Utils::loadBigEndian<uint16_t>(data + p);
m_flags = Utils::loadBigEndian<uint16_t>(data + p);
p += 2;
} else {
_ts = 0;
m_ts = 0;
}
return p;

View file

@ -47,32 +47,32 @@ public:
/**
* @return Timestamp (a.k.a. revision number) set by Location signer
*/
ZT_INLINE int64_t timestamp() const noexcept { return _ts; }
ZT_INLINE int64_t timestamp() const noexcept { return m_ts; }
/**
* @return True if locator is signed
*/
ZT_INLINE bool isSigned() const noexcept { return (_signatureLength > 0); }
ZT_INLINE bool isSigned() const noexcept { return (m_signatureLength > 0); }
/**
* @return Length of signature in bytes or 0 if none
*/
ZT_INLINE unsigned int signatureLength() const noexcept { return _signatureLength; }
ZT_INLINE unsigned int signatureLength() const noexcept { return m_signatureLength; }
/**
* @return Pointer to signature bytes
*/
ZT_INLINE const uint8_t *signature() const noexcept { return _signature; }
ZT_INLINE const uint8_t *signature() const noexcept { return m_signature; }
/**
* @return Number of endpoints in this locator
*/
ZT_INLINE unsigned int endpointCount() const noexcept { return _endpointCount; }
ZT_INLINE unsigned int endpointCount() const noexcept { return m_endpointCount; }
/**
* @return Pointer to array of endpoints
*/
ZT_INLINE const Endpoint *endpoints() const noexcept { return _at; }
ZT_INLINE const Endpoint *endpoints() const noexcept { return m_at; }
/**
* Add an endpoint to this locator
@ -85,9 +85,9 @@ public:
*/
ZT_INLINE bool add(const Endpoint &ep) noexcept
{
if (_endpointCount >= ZT_LOCATOR_MAX_ENDPOINTS)
if (m_endpointCount >= ZT_LOCATOR_MAX_ENDPOINTS)
return false;
_at[_endpointCount++] = ep;
m_at[m_endpointCount++] = ep;
return true;
}
@ -110,19 +110,19 @@ public:
*/
bool verify(const Identity &id) const noexcept;
explicit ZT_INLINE operator bool() const noexcept { return (_ts != 0); }
explicit ZT_INLINE operator bool() const noexcept { return (m_ts != 0); }
static constexpr int marshalSizeMax() noexcept { return ZT_LOCATOR_MARSHAL_SIZE_MAX; }
int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX],bool excludeSignature = false) const noexcept;
int unmarshal(const uint8_t *restrict data,int len) noexcept;
private:
int64_t _ts;
unsigned int _endpointCount;
unsigned int _signatureLength;
Endpoint _at[ZT_LOCATOR_MAX_ENDPOINTS];
uint16_t _flags;
uint8_t _signature[ZT_SIGNATURE_BUFFER_SIZE];
int64_t m_ts;
unsigned int m_endpointCount;
unsigned int m_signatureLength;
Endpoint m_at[ZT_LOCATOR_MAX_ENDPOINTS];
uint16_t m_flags;
uint8_t m_signature[ZT_SIGNATURE_BUFFER_SIZE];
};
} // namespace ZeroTier

View file

@ -31,26 +31,26 @@ namespace ZeroTier {
class MAC : public TriviallyCopyable
{
public:
ZT_INLINE MAC() noexcept : _m(0ULL) {}
ZT_INLINE MAC(const uint8_t a,const uint8_t b,const uint8_t c,const uint8_t d,const uint8_t e,const uint8_t f) noexcept : _m((((uint64_t)a) << 40U) | (((uint64_t)b) << 32U) | (((uint64_t)c) << 24U) | (((uint64_t)d) << 16U) | (((uint64_t)e) << 8U) | ((uint64_t)f) ) {}
explicit ZT_INLINE MAC(const uint64_t m) noexcept : _m(m) {}
ZT_INLINE MAC() noexcept : m_mac(0ULL) {}
ZT_INLINE MAC(const uint8_t a,const uint8_t b,const uint8_t c,const uint8_t d,const uint8_t e,const uint8_t f) noexcept : m_mac((((uint64_t)a) << 40U) | (((uint64_t)b) << 32U) | (((uint64_t)c) << 24U) | (((uint64_t)d) << 16U) | (((uint64_t)e) << 8U) | ((uint64_t)f) ) {}
explicit ZT_INLINE MAC(const uint64_t m) noexcept : m_mac(m) {}
explicit ZT_INLINE MAC(const uint8_t b[6]) noexcept { setTo(b); } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
ZT_INLINE MAC(const Address &ztaddr,const uint64_t nwid) noexcept { fromAddress(ztaddr,nwid); } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
/**
* @return MAC in 64-bit integer
*/
ZT_INLINE uint64_t toInt() const noexcept { return _m; }
ZT_INLINE uint64_t toInt() const noexcept { return m_mac; }
/**
* Set MAC to zero
*/
ZT_INLINE void zero() noexcept { _m = 0ULL; }
ZT_INLINE void zero() noexcept { m_mac = 0ULL; }
/**
* @return True if MAC is non-zero
*/
ZT_INLINE operator bool() const noexcept { return (_m != 0ULL); } // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
ZT_INLINE operator bool() const noexcept { return (m_mac != 0ULL); } // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
/**
* @param bits Raw MAC in big-endian byte order
@ -58,7 +58,7 @@ public:
*/
ZT_INLINE void setTo(const uint8_t b[6]) noexcept
{
_m = ((uint64_t)b[0] << 40U) | ((uint64_t)b[1] << 32U) | ((uint64_t)b[2] << 24U) | ((uint64_t)b[3] << 16U) | ((uint64_t)b[4] << 8U) | (uint64_t)b[5];
m_mac = ((uint64_t)b[0] << 40U) | ((uint64_t)b[1] << 32U) | ((uint64_t)b[2] << 24U) | ((uint64_t)b[3] << 16U) | ((uint64_t)b[4] << 8U) | (uint64_t)b[5];
}
/**
@ -67,23 +67,23 @@ public:
*/
ZT_INLINE void copyTo(uint8_t b[6]) const noexcept
{
b[0] = (uint8_t)(_m >> 40U);
b[1] = (uint8_t)(_m >> 32U);
b[2] = (uint8_t)(_m >> 24U);
b[3] = (uint8_t)(_m >> 16U);
b[4] = (uint8_t)(_m >> 8U);
b[5] = (uint8_t)_m;
b[0] = (uint8_t)(m_mac >> 40U);
b[1] = (uint8_t)(m_mac >> 32U);
b[2] = (uint8_t)(m_mac >> 24U);
b[3] = (uint8_t)(m_mac >> 16U);
b[4] = (uint8_t)(m_mac >> 8U);
b[5] = (uint8_t)m_mac;
}
/**
* @return True if this is broadcast (all 0xff)
*/
ZT_INLINE bool isBroadcast() const noexcept { return _m; }
ZT_INLINE bool isBroadcast() const noexcept { return m_mac; }
/**
* @return True if this is a multicast MAC
*/
ZT_INLINE bool isMulticast() const noexcept { return ((_m & 0x010000000000ULL) != 0ULL); }
ZT_INLINE bool isMulticast() const noexcept { return ((m_mac & 0x010000000000ULL) != 0ULL); }
/**
* Set this MAC to a MAC derived from an address and a network ID
@ -100,7 +100,7 @@ public:
m ^= ((nwid >> 24U) & 0xffU) << 16U;
m ^= ((nwid >> 32U) & 0xffU) << 8U;
m ^= (nwid >> 40U) & 0xffU;
_m = m;
m_mac = m;
}
/**
@ -112,7 +112,7 @@ public:
*/
ZT_INLINE Address toAddress(uint64_t nwid) const noexcept
{
uint64_t a = _m & 0xffffffffffULL; // least significant 40 bits of MAC are formed from address
uint64_t a = m_mac & 0xffffffffffULL; // least significant 40 bits of MAC are formed from address
a ^= ((nwid >> 8U) & 0xffU) << 32U; // ... XORed with bits 8-48 of the nwid in little-endian byte order, so unmask it
a ^= ((nwid >> 16U) & 0xffU) << 24U;
a ^= ((nwid >> 24U) & 0xffU) << 16U;
@ -135,49 +135,49 @@ public:
* @param i Value from 0 to 5 (inclusive)
* @return Byte at said position (address interpreted in big-endian order)
*/
ZT_INLINE uint8_t operator[](unsigned int i) const noexcept { return (uint8_t)(_m >> (40 - (i * 8))); }
ZT_INLINE uint8_t operator[](unsigned int i) const noexcept { return (uint8_t)(m_mac >> (40 - (i * 8))); }
/**
* @return 6, which is the number of bytes in a MAC, for container compliance
*/
ZT_INLINE unsigned int size() const noexcept { return 6; }
ZT_INLINE unsigned long hashCode() const noexcept { return (unsigned long)Utils::hash64(_m); }
ZT_INLINE unsigned long hashCode() const noexcept { return (unsigned long)Utils::hash64(m_mac); }
ZT_INLINE char *toString(char buf[18]) const noexcept
{
buf[0] = Utils::HEXCHARS[(_m >> 44U) & 0xfU];
buf[1] = Utils::HEXCHARS[(_m >> 40U) & 0xfU];
buf[0] = Utils::HEXCHARS[(m_mac >> 44U) & 0xfU];
buf[1] = Utils::HEXCHARS[(m_mac >> 40U) & 0xfU];
buf[2] = ':';
buf[3] = Utils::HEXCHARS[(_m >> 36U) & 0xfU];
buf[4] = Utils::HEXCHARS[(_m >> 32U) & 0xfU];
buf[3] = Utils::HEXCHARS[(m_mac >> 36U) & 0xfU];
buf[4] = Utils::HEXCHARS[(m_mac >> 32U) & 0xfU];
buf[5] = ':';
buf[6] = Utils::HEXCHARS[(_m >> 28U) & 0xfU];
buf[7] = Utils::HEXCHARS[(_m >> 24U) & 0xfU];
buf[6] = Utils::HEXCHARS[(m_mac >> 28U) & 0xfU];
buf[7] = Utils::HEXCHARS[(m_mac >> 24U) & 0xfU];
buf[8] = ':';
buf[9] = Utils::HEXCHARS[(_m >> 20U) & 0xfU];
buf[10] = Utils::HEXCHARS[(_m >> 16U) & 0xfU];
buf[9] = Utils::HEXCHARS[(m_mac >> 20U) & 0xfU];
buf[10] = Utils::HEXCHARS[(m_mac >> 16U) & 0xfU];
buf[11] = ':';
buf[12] = Utils::HEXCHARS[(_m >> 12U) & 0xfU];
buf[13] = Utils::HEXCHARS[(_m >> 8U) & 0xfU];
buf[12] = Utils::HEXCHARS[(m_mac >> 12U) & 0xfU];
buf[13] = Utils::HEXCHARS[(m_mac >> 8U) & 0xfU];
buf[14] = ':';
buf[15] = Utils::HEXCHARS[(_m >> 4U) & 0xfU];
buf[16] = Utils::HEXCHARS[_m & 0xfU];
buf[15] = Utils::HEXCHARS[(m_mac >> 4U) & 0xfU];
buf[16] = Utils::HEXCHARS[m_mac & 0xfU];
buf[17] = (char)0;
return buf;
}
ZT_INLINE MAC &operator=(const uint64_t m) noexcept { _m = m; return *this; }
ZT_INLINE MAC &operator=(const uint64_t m) noexcept { m_mac = m; return *this; }
ZT_INLINE bool operator==(const MAC &m) const noexcept { return (_m == m._m); }
ZT_INLINE bool operator!=(const MAC &m) const noexcept { return (_m != m._m); }
ZT_INLINE bool operator<(const MAC &m) const noexcept { return (_m < m._m); }
ZT_INLINE bool operator<=(const MAC &m) const noexcept { return (_m <= m._m); }
ZT_INLINE bool operator>(const MAC &m) const noexcept { return (_m > m._m); }
ZT_INLINE bool operator>=(const MAC &m) const noexcept { return (_m >= m._m); }
ZT_INLINE bool operator==(const MAC &m) const noexcept { return (m_mac == m.m_mac); }
ZT_INLINE bool operator!=(const MAC &m) const noexcept { return (m_mac != m.m_mac); }
ZT_INLINE bool operator<(const MAC &m) const noexcept { return (m_mac < m.m_mac); }
ZT_INLINE bool operator<=(const MAC &m) const noexcept { return (m_mac <= m.m_mac); }
ZT_INLINE bool operator>(const MAC &m) const noexcept { return (m_mac > m.m_mac); }
ZT_INLINE bool operator>=(const MAC &m) const noexcept { return (m_mac >= m.m_mac); }
private:
uint64_t _m;
uint64_t m_mac;
};
} // namespace ZeroTier

View file

@ -21,10 +21,10 @@
namespace ZeroTier {
Membership::Membership() :
_comRevocationThreshold(0),
_lastPushedCredentials(0),
_comAgreementLocalTimestamp(0),
_comAgreementRemoteTimestamp(0)
m_comRevocationThreshold(0),
m_lastPushedCredentials(0),
m_comAgreementLocalTimestamp(0),
m_comAgreementRemoteTimestamp(0)
{
}
@ -110,30 +110,30 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
}
}
_lastPushedCredentials = now;
m_lastPushedCredentials = now;
}
void Membership::clean(const int64_t now,const NetworkConfig &nconf)
{
_cleanCredImpl<Tag>(nconf,_remoteTags);
_cleanCredImpl<Capability>(nconf,_remoteCaps);
_cleanCredImpl<CertificateOfOwnership>(nconf,_remoteCoos);
m_cleanCredImpl<Tag>(nconf, m_remoteTags);
m_cleanCredImpl<Capability>(nconf, m_remoteCaps);
m_cleanCredImpl<CertificateOfOwnership>(nconf, m_remoteCoos);
}
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const CertificateOfMembership &com)
{
const int64_t newts = com.timestamp();
if (newts <= _comRevocationThreshold) {
if (newts <= m_comRevocationThreshold) {
RR->t->credentialRejected(tPtr,0xd9992121,com.networkId(),sourcePeerIdentity.address(),sourcePeerIdentity,com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED);
return ADD_REJECTED;
}
const int64_t oldts = _com.timestamp();
const int64_t oldts = m_com.timestamp();
if (newts < oldts) {
RR->t->credentialRejected(tPtr,0xd9928192,com.networkId(),sourcePeerIdentity.address(),sourcePeerIdentity,com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST);
return ADD_REJECTED;
}
if ((newts == oldts)&&(_com == com))
if ((newts == oldts)&&(m_com == com))
return ADD_ACCEPTED_REDUNDANT;
switch(com.verify(RR,tPtr)) {
@ -141,7 +141,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
RR->t->credentialRejected(tPtr,0x0f198241,com.networkId(),sourcePeerIdentity.address(),sourcePeerIdentity,com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
return Membership::ADD_REJECTED;
case Credential::VERIFY_OK:
_com = com;
m_com = com;
return ADD_ACCEPTED_NEW;
case Credential::VERIFY_BAD_SIGNATURE:
RR->t->credentialRejected(tPtr,0xbaf0aaaa,com.networkId(),sourcePeerIdentity.address(),sourcePeerIdentity,com.id(),com.timestamp(),ZT_CREDENTIAL_TYPE_COM,ZT_TRACE_CREDENTIAL_REJECTION_REASON_SIGNATURE_VERIFICATION_FAILED);
@ -191,9 +191,9 @@ static ZT_INLINE Membership::AddCredentialResult _addCredImpl(
return Membership::ADD_DEFERRED_FOR_WHOIS;
}
}
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Tag &tag) { return _addCredImpl<Tag>(_remoteTags,_revocations,RR,tPtr,sourcePeerIdentity,nconf,tag); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Capability &cap) { return _addCredImpl<Capability>(_remoteCaps,_revocations,RR,tPtr,sourcePeerIdentity,nconf,cap); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const CertificateOfOwnership &coo) { return _addCredImpl<CertificateOfOwnership>(_remoteCoos,_revocations,RR,tPtr,sourcePeerIdentity,nconf,coo); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Tag &tag) { return _addCredImpl<Tag>(m_remoteTags, m_revocations, RR, tPtr, sourcePeerIdentity, nconf, tag); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Capability &cap) { return _addCredImpl<Capability>(m_remoteCaps, m_revocations, RR, tPtr, sourcePeerIdentity, nconf, cap); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const CertificateOfOwnership &coo) { return _addCredImpl<CertificateOfOwnership>(m_remoteCoos, m_revocations, RR, tPtr, sourcePeerIdentity, nconf, coo); }
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const Identity &sourcePeerIdentity,const NetworkConfig &nconf,const Revocation &rev)
{
@ -206,18 +206,18 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
const ZT_CredentialType ct = rev.typeBeingRevoked();
switch(ct) {
case ZT_CREDENTIAL_TYPE_COM:
if (rev.threshold() > _comRevocationThreshold) {
_comRevocationThreshold = rev.threshold();
if (rev.threshold() > m_comRevocationThreshold) {
m_comRevocationThreshold = rev.threshold();
return ADD_ACCEPTED_NEW;
}
return ADD_ACCEPTED_REDUNDANT;
case ZT_CREDENTIAL_TYPE_CAPABILITY:
case ZT_CREDENTIAL_TYPE_TAG:
case ZT_CREDENTIAL_TYPE_COO:
rt = &(_revocations[credentialKey(ct,rev.credentialId())]);
rt = &(m_revocations[credentialKey(ct, rev.credentialId())]);
if (*rt < rev.threshold()) {
*rt = rev.threshold();
_comRevocationThreshold = rev.threshold();
m_comRevocationThreshold = rev.threshold();
return ADD_ACCEPTED_NEW;
}
return ADD_ACCEPTED_REDUNDANT;
@ -231,7 +231,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
}
}
bool Membership::_isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const noexcept
bool Membership::m_isUnspoofableAddress(const NetworkConfig &nconf, const InetAddress &ip) const noexcept
{
if ((ip.isV6())&&(nconf.ndpEmulation())) {
const InetAddress sixpl(InetAddress::makeIpv66plane(nconf.networkId,nconf.issuedTo.toInt()));

View file

@ -64,7 +64,7 @@ public:
/**
* @return Time we last pushed credentials to this member
*/
ZT_INLINE int64_t lastPushedCredentials() const noexcept { return _lastPushedCredentials; }
ZT_INLINE int64_t lastPushedCredentials() const noexcept { return m_lastPushedCredentials; }
/**
* Get a remote member's tag (if we have it)
@ -75,8 +75,8 @@ public:
*/
ZT_INLINE const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const noexcept
{
const Tag *const t = _remoteTags.get(id);
return (((t)&&(_isCredentialTimestampValid(nconf,*t))) ? t : (Tag *)0);
const Tag *const t = m_remoteTags.get(id);
return (((t)&&(m_isCredentialTimestampValid(nconf, *t))) ? t : (Tag *)0);
}
/**
@ -103,10 +103,10 @@ public:
template<typename T>
ZT_INLINE bool peerOwnsAddress(const NetworkConfig &nconf,const T &r) const noexcept
{
if (_isUnspoofableAddress(nconf,r))
if (s_isUnspoofableAddress(nconf, r))
return true;
for(Map< uint32_t,CertificateOfOwnership >::const_iterator i(_remoteCoos.begin());i!=_remoteCoos.end();++i) {
if (_isCredentialTimestampValid(nconf,i->second)&&(i->second.owns(r)))
for(Map< uint32_t,CertificateOfOwnership >::const_iterator i(m_remoteCoos.begin());i != m_remoteCoos.end();++i) {
if (m_isCredentialTimestampValid(nconf, i->second) && (i->second.owns(r)))
return true;
}
return false;
@ -119,9 +119,9 @@ public:
*/
ZT_INLINE bool certificateOfMembershipAgress(const CertificateOfMembership &localCom,const Identity &remoteIdentity)
{
if ((_comAgreementLocalTimestamp == localCom.timestamp())&&(_comAgreementRemoteTimestamp == _com.timestamp()))
if ((m_comAgreementLocalTimestamp == localCom.timestamp()) && (m_comAgreementRemoteTimestamp == m_com.timestamp()))
return true;
if (_com.agreesWith(localCom)) {
if (m_com.agreesWith(localCom)) {
// SECURITY: newer network controllers embed the full fingerprint into the COM. If we are
// joined to a network managed by one of these, our COM will contain one. If it's present
// we compare vs the other and require them to match. If our COM does not contain a full
@ -130,18 +130,18 @@ public:
// and in so doing indicates if it's new or old. However this will go away after a while
// once we can be pretty sure there are no ancient controllers around.
if (localCom.issuedTo().haveHash()) {
if (localCom.issuedTo() != _com.issuedTo())
if (localCom.issuedTo() != m_com.issuedTo())
return false;
} else {
// LEGACY: support networks run by old controllers.
if (localCom.issuedTo().address() != _com.issuedTo().address())
if (localCom.issuedTo().address() != m_com.issuedTo().address())
return false;
}
// Remember that these two COMs agreed. If any are updated this is invalidated and a full
// agreement check will be done again.
_comAgreementLocalTimestamp = localCom.timestamp();
_comAgreementRemoteTimestamp = _com.timestamp();
m_comAgreementLocalTimestamp = localCom.timestamp();
m_comAgreementRemoteTimestamp = m_com.timestamp();
return true;
}
@ -158,77 +158,77 @@ 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.
ZT_INLINE bool _isUnspoofableAddress(const NetworkConfig &nconf,const MAC &m) const noexcept { return false; }
bool _isUnspoofableAddress(const NetworkConfig &nconf,const InetAddress &ip) const noexcept;
ZT_INLINE static bool s_isUnspoofableAddress(const NetworkConfig &nconf, const MAC &m) noexcept { return false; }
bool m_isUnspoofableAddress(const NetworkConfig &nconf, const InetAddress &ip) const noexcept;
// 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>
ZT_INLINE bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &remoteCredential) const noexcept
ZT_INLINE bool m_isCredentialTimestampValid(const NetworkConfig &nconf, const C &remoteCredential) const noexcept
{
const int64_t ts = remoteCredential.timestamp();
if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) {
const int64_t *threshold = _revocations.get(credentialKey(C::credentialType(),remoteCredential.id()));
const int64_t *threshold = m_revocations.get(credentialKey(C::credentialType(), remoteCredential.id()));
return ((!threshold)||(ts > *threshold));
}
return false;
}
template<typename C>
ZT_INLINE void _cleanCredImpl(const NetworkConfig &nconf,Map<uint32_t,C> &remoteCreds)
ZT_INLINE void m_cleanCredImpl(const NetworkConfig &nconf, Map<uint32_t,C> &remoteCreds)
{
for(typename Map<uint32_t,C>::iterator i(remoteCreds.begin());i!=remoteCreds.end();) {
if (!_isCredentialTimestampValid(nconf,i->second))
if (!m_isCredentialTimestampValid(nconf, i->second))
remoteCreds.erase(i++);
else ++i;
}
}
// Revocation threshold for COM or 0 if none
int64_t _comRevocationThreshold;
int64_t m_comRevocationThreshold;
// Time we last pushed credentials
int64_t _lastPushedCredentials;
int64_t m_lastPushedCredentials;
// COM timestamps at which we last agreed-- used to memo-ize agreement and avoid having to recompute constantly.
int64_t _comAgreementLocalTimestamp,_comAgreementRemoteTimestamp;
int64_t m_comAgreementLocalTimestamp,m_comAgreementRemoteTimestamp;
// Remote member's latest network COM
CertificateOfMembership _com;
CertificateOfMembership m_com;
// Revocations by credentialKey()
Map< uint64_t,int64_t > _revocations;
Map<uint64_t,int64_t> m_revocations;
// Remote credentials that we have received from this member (and that are valid)
Map< uint32_t,Tag > _remoteTags;
Map< uint32_t,Capability > _remoteCaps;
Map< uint32_t,CertificateOfOwnership > _remoteCoos;
Map<uint32_t,Tag> m_remoteTags;
Map<uint32_t,Capability> m_remoteCaps;
Map<uint32_t,CertificateOfOwnership> m_remoteCoos;
public:
class CapabilityIterator
{
public:
ZT_INLINE CapabilityIterator(Membership &m,const NetworkConfig &nconf) noexcept :
_hti(m._remoteCaps.begin()),
_m(m),
_nconf(nconf)
m_hti(m.m_remoteCaps.begin()),
m_parent(m),
m_nconf(nconf)
{
}
ZT_INLINE Capability *next() noexcept
{
while (_hti != _m._remoteCaps.end()) {
Map< uint32_t,Capability >::iterator i(_hti++); // NOLINT(hicpp-use-auto,modernize-use-auto)
if (_m._isCredentialTimestampValid(_nconf,i->second))
while (m_hti != m_parent.m_remoteCaps.end()) {
Map< uint32_t,Capability >::iterator i(m_hti++); // NOLINT(hicpp-use-auto,modernize-use-auto)
if (m_parent.m_isCredentialTimestampValid(m_nconf, i->second))
return &(i->second);
}
return nullptr;
}
private:
Map< uint32_t,Capability >::iterator _hti;
Membership &_m;
const NetworkConfig &_nconf;
Map< uint32_t,Capability >::iterator m_hti;
Membership &m_parent;
const NetworkConfig &m_nconf;
};
};

View file

@ -57,10 +57,10 @@ public:
// the log size and then if it's a new bucket setting it or otherwise adding
// to it.
const unsigned long bucket = ((unsigned long)(now / TUNIT)) % LSIZE;
if (_bucket.exchange(bucket) != bucket) {
_totalExclCounts.fetch_add(_counts[bucket].exchange(count));
if (m_bucket.exchange(bucket) != bucket) {
m_totalExclCounts.fetch_add(m_counts[bucket].exchange(count));
} else {
_counts[bucket].fetch_add(count);
m_counts[bucket].fetch_add(count);
}
}
@ -75,15 +75,15 @@ public:
{
total = 0;
for(unsigned long i=0;i<LSIZE;++i)
total += _counts[i].load();
total += m_counts[i].load();
rate = (double)total / (double)LSIZE;
total += _totalExclCounts.load();
total += m_totalExclCounts.load();
}
private:
std::atomic<uint64_t> _counts[LSIZE];
std::atomic<uint64_t> _totalExclCounts;
std::atomic<unsigned long> _bucket;
std::atomic<uint64_t> m_counts[LSIZE];
std::atomic<uint64_t> m_totalExclCounts;
std::atomic<unsigned long> m_bucket;
};
} // namespace ZeroTier

View file

@ -42,8 +42,8 @@ namespace ZeroTier {
class MulticastGroup : public TriviallyCopyable
{
public:
ZT_INLINE MulticastGroup() noexcept : _mac(),_adi(0) {}
ZT_INLINE MulticastGroup(const MAC &m,uint32_t a) noexcept : _mac(m),_adi(a) {}
ZT_INLINE MulticastGroup() noexcept : m_mac(), m_adi(0) {}
ZT_INLINE MulticastGroup(const MAC &m,uint32_t a) noexcept : m_mac(m), m_adi(a) {}
/**
* Derive the multicast group used for address resolution (ARP/NDP) for an IP
@ -73,32 +73,32 @@ public:
/**
* @return Ethernet MAC portion of multicast group
*/
ZT_INLINE const MAC &mac() const noexcept { return _mac; }
ZT_INLINE const MAC &mac() const noexcept { return m_mac; }
/**
* @return Additional distinguishing information, which is normally zero except for IPv4 ARP where it's the IPv4 address
*/
ZT_INLINE uint32_t adi() const { return _adi; }
ZT_INLINE uint32_t adi() const { return m_adi; }
ZT_INLINE bool operator==(const MulticastGroup &g) const noexcept { return ((_mac == g._mac) && (_adi == g._adi)); }
ZT_INLINE bool operator!=(const MulticastGroup &g) const noexcept { return ((_mac != g._mac) || (_adi != g._adi)); }
ZT_INLINE bool operator==(const MulticastGroup &g) const noexcept { return ((m_mac == g.m_mac) && (m_adi == g.m_adi)); }
ZT_INLINE bool operator!=(const MulticastGroup &g) const noexcept { return ((m_mac != g.m_mac) || (m_adi != g.m_adi)); }
ZT_INLINE bool operator<(const MulticastGroup &g) const noexcept
{
if (_mac < g._mac)
if (m_mac < g.m_mac)
return true;
else if (_mac == g._mac)
return (_adi < g._adi);
else if (m_mac == g.m_mac)
return (m_adi < g.m_adi);
return false;
}
ZT_INLINE bool operator>(const MulticastGroup &g) const noexcept { return (g < *this); }
ZT_INLINE bool operator<=(const MulticastGroup &g) const noexcept { return !(g < *this); }
ZT_INLINE bool operator>=(const MulticastGroup &g) const noexcept { return !(*this < g); }
ZT_INLINE unsigned long hashCode() const noexcept { return (_mac.hashCode() + (unsigned long)_adi); }
ZT_INLINE unsigned long hashCode() const noexcept { return (m_mac.hashCode() + (unsigned long)m_adi); }
private:
MAC _mac;
uint32_t _adi;
MAC m_mac;
uint32_t m_adi;
};
} // namespace ZeroTier

View file

@ -535,20 +535,20 @@ const ZeroTier::MulticastGroup Network::BROADCAST(ZeroTier::MAC(0xffffffffffffUL
Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,const Fingerprint &controllerFingerprint,void *uptr,const NetworkConfig *nconf) :
RR(renv),
_uPtr(uptr),
_id(nwid),
_mac(renv->identity.address(),nwid),
_portInitialized(false),
_lastConfigUpdate(0),
_destroyed(false),
m_uPtr(uptr),
m_id(nwid),
m_mac(renv->identity.address(), nwid),
m_portInitialized(false),
m_lastConfigUpdate(0),
m_destroyed(false),
_netconfFailure(NETCONF_FAILURE_NONE)
{
if (controllerFingerprint)
_controllerFingerprint = controllerFingerprint;
m_controllerFingerprint = controllerFingerprint;
if (nconf) {
this->setConfiguration(tPtr,*nconf,false);
_lastConfigUpdate = 0; // still want to re-request since it's likely outdated
m_lastConfigUpdate = 0; // still want to re-request since it's likely outdated
} else {
uint64_t tmp[2];
tmp[0] = nwid; tmp[1] = 0;
@ -564,7 +564,7 @@ Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,const F
ScopedPtr<NetworkConfig> nconf2(new NetworkConfig());
if (nconf2->fromDictionary(dict)) {
this->setConfiguration(tPtr,*nconf2,false);
_lastConfigUpdate = 0; // still want to re-request an update since it's likely outdated
m_lastConfigUpdate = 0; // still want to re-request an update since it's likely outdated
got = true;
}
} catch (...) {}
@ -576,29 +576,29 @@ Network::Network(const RuntimeEnvironment *renv,void *tPtr,uint64_t nwid,const F
RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,"\n",1);
}
if (!_portInitialized) {
if (!m_portInitialized) {
ZT_VirtualNetworkConfig ctmp;
_externalConfig(&ctmp);
RR->node->configureVirtualNetworkPort(tPtr,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp);
_portInitialized = true;
m_externalConfig(&ctmp);
RR->node->configureVirtualNetworkPort(tPtr, m_id, &m_uPtr, ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP, &ctmp);
m_portInitialized = true;
}
}
Network::~Network()
{
_memberships_l.lock();
_config_l.lock();
_config_l.unlock();
_memberships_l.unlock();
m_memberships_l.lock();
m_config_l.lock();
m_config_l.unlock();
m_memberships_l.unlock();
ZT_VirtualNetworkConfig ctmp;
_externalConfig(&ctmp);
m_externalConfig(&ctmp);
if (_destroyed) {
if (m_destroyed) {
// This is done in Node::leave() so we can pass tPtr properly
//RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp);
} else {
RR->node->configureVirtualNetworkPort(nullptr,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN,&ctmp);
RR->node->configureVirtualNetworkPort(nullptr, m_id, &m_uPtr, ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DOWN, &ctmp);
}
}
@ -623,20 +623,20 @@ bool Network::filterOutgoingPacket(
unsigned int ccLength = 0;
bool ccWatch = false;
Mutex::Lock l1(_memberships_l);
Mutex::Lock l2(_config_l);
Mutex::Lock l1(m_memberships_l);
Mutex::Lock l2(m_config_l);
Membership *const membership = (ztDest) ? _memberships.get(ztDest) : nullptr;
Membership *const membership = (ztDest) ? m_memberships.get(ztDest) : nullptr;
switch(_doZtFilter(RR,rrl,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch,qosBucket)) {
switch(_doZtFilter(RR, rrl, m_config, membership, false, ztSource, ztFinalDest, macSource, macDest, frameData, frameLen, etherType, vlanId, m_config.rules, m_config.ruleCount, cc, ccLength, ccWatch, qosBucket)) {
case DOZTFILTER_NO_MATCH: {
for(unsigned int c=0;c<_config.capabilityCount;++c) {
for(unsigned int c=0;c < m_config.capabilityCount;++c) {
ztFinalDest = ztDest; // sanity check, shouldn't be possible if there was no match
Address cc2;
unsigned int ccLength2 = 0;
bool ccWatch2 = false;
switch (_doZtFilter(RR,crrl,_config,membership,false,ztSource,ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),cc2,ccLength2,ccWatch2,qosBucket)) {
switch (_doZtFilter(RR, crrl, m_config, membership, false, ztSource, ztFinalDest, macSource, macDest, frameData, frameLen, etherType, vlanId, m_config.capabilities[c].rules(), m_config.capabilities[c].ruleCount(), cc2, ccLength2, ccWatch2, qosBucket)) {
case DOZTFILTER_NO_MATCH:
case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern
break;
@ -670,7 +670,7 @@ bool Network::filterOutgoingPacket(
} break;
case DOZTFILTER_DROP:
RR->t->networkFilter(tPtr,0xadea5a2a,_id,rrl.l,nullptr,0,0,ztSource,ztDest,macSource,macDest,(uint16_t)frameLen,frameData,(uint16_t)etherType,(uint16_t)vlanId,noTee,false,0);
RR->t->networkFilter(tPtr, 0xadea5a2a, m_id, rrl.l, nullptr, 0, 0, ztSource, ztDest, macSource, macDest, (uint16_t)frameLen, frameData, (uint16_t)etherType, (uint16_t)vlanId, noTee, false, 0);
return false;
case DOZTFILTER_REDIRECT: // interpreted as ACCEPT but ztFinalDest will have been changed in _doZtFilter()
@ -719,10 +719,10 @@ bool Network::filterOutgoingPacket(
}
if (localCapabilityIndex >= 0) {
const Capability &cap = _config.capabilities[localCapabilityIndex];
RR->t->networkFilter(tPtr,0x56ff1a93,_id,rrl.l,crrl.l,cap.id(),cap.timestamp(),ztSource,ztDest,macSource,macDest,(uint16_t)frameLen,frameData,(uint16_t)etherType,(uint16_t)vlanId,noTee,false,accept);
const Capability &cap = m_config.capabilities[localCapabilityIndex];
RR->t->networkFilter(tPtr, 0x56ff1a93, m_id, rrl.l, crrl.l, cap.id(), cap.timestamp(), ztSource, ztDest, macSource, macDest, (uint16_t)frameLen, frameData, (uint16_t)etherType, (uint16_t)vlanId, noTee, false, accept);
} else {
RR->t->networkFilter(tPtr,0x112fbbab,_id,rrl.l,nullptr,0,0,ztSource,ztDest,macSource,macDest,(uint16_t)frameLen,frameData,(uint16_t)etherType,(uint16_t)vlanId,noTee,false,accept);
RR->t->networkFilter(tPtr, 0x112fbbab, m_id, rrl.l, nullptr, 0, 0, ztSource, ztDest, macSource, macDest, (uint16_t)frameLen, frameData, (uint16_t)etherType, (uint16_t)vlanId, noTee, false, accept);
}
return (accept != 0);
@ -749,21 +749,21 @@ int Network::filterIncomingPacket(
uint8_t qosBucket = 255; // For incoming packets this is a dummy value
Mutex::Lock l1(_memberships_l);
Mutex::Lock l2(_config_l);
Mutex::Lock l1(m_memberships_l);
Mutex::Lock l2(m_config_l);
Membership &membership = _memberships[sourcePeer->address()];
Membership &membership = m_memberships[sourcePeer->address()];
switch (_doZtFilter(RR,rrl,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,cc,ccLength,ccWatch,qosBucket)) {
switch (_doZtFilter(RR, rrl, m_config, &membership, true, sourcePeer->address(), ztFinalDest, macSource, macDest, frameData, frameLen, etherType, vlanId, m_config.rules, m_config.ruleCount, cc, ccLength, ccWatch, qosBucket)) {
case DOZTFILTER_NO_MATCH: {
Membership::CapabilityIterator mci(membership,_config);
Membership::CapabilityIterator mci(membership, m_config);
while ((c = mci.next())) {
ztFinalDest = ztDest; // sanity check, should be unmodified if there was no match
Address cc2;
unsigned int ccLength2 = 0;
bool ccWatch2 = false;
switch(_doZtFilter(RR,crrl,_config,&membership,true,sourcePeer->address(),ztFinalDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),cc2,ccLength2,ccWatch2,qosBucket)) {
switch(_doZtFilter(RR, crrl, m_config, &membership, true, sourcePeer->address(), ztFinalDest, macSource, macDest, frameData, frameLen, etherType, vlanId, c->rules(), c->ruleCount(), cc2, ccLength2, ccWatch2, qosBucket)) {
case DOZTFILTER_NO_MATCH:
case DOZTFILTER_DROP: // explicit DROP in a capability just terminates its evaluation and is an anti-pattern
break;
@ -853,31 +853,31 @@ int Network::filterIncomingPacket(
void Network::multicastSubscribe(void *tPtr,const MulticastGroup &mg)
{
Mutex::Lock l(_myMulticastGroups_l);
if (!std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg)) {
_myMulticastGroups.insert(std::upper_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg),mg);
Mutex::Lock l2(_memberships_l);
_announceMulticastGroups(tPtr,true);
Mutex::Lock l(m_myMulticastGroups_l);
if (!std::binary_search(m_myMulticastGroups.begin(), m_myMulticastGroups.end(), mg)) {
m_myMulticastGroups.insert(std::upper_bound(m_myMulticastGroups.begin(), m_myMulticastGroups.end(), mg), mg);
Mutex::Lock l2(m_memberships_l);
m_announceMulticastGroups(tPtr, true);
}
}
void Network::multicastUnsubscribe(const MulticastGroup &mg)
{
Mutex::Lock l(_myMulticastGroups_l);
std::vector<MulticastGroup>::iterator i(std::lower_bound(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg));
if ( (i != _myMulticastGroups.end()) && (*i == mg) )
_myMulticastGroups.erase(i);
Mutex::Lock l(m_myMulticastGroups_l);
std::vector<MulticastGroup>::iterator i(std::lower_bound(m_myMulticastGroups.begin(), m_myMulticastGroups.end(), mg));
if ((i != m_myMulticastGroups.end()) && (*i == mg) )
m_myMulticastGroups.erase(i);
}
uint64_t Network::handleConfigChunk(void *tPtr,uint64_t packetId,const SharedPtr<Peer> &source,const Buf &chunk,int ptr,int size)
{
// If the controller's full fingerprint is known or was explicitly specified on join(),
// require that the controller's identity match. Otherwise learn it.
if (_controllerFingerprint) {
if (source->identity().fingerprint() != _controllerFingerprint)
if (m_controllerFingerprint) {
if (source->identity().fingerprint() != m_controllerFingerprint)
return 0;
} else {
_controllerFingerprint = source->identity().fingerprint();
m_controllerFingerprint = source->identity().fingerprint();
}
return 0;
@ -1015,42 +1015,42 @@ uint64_t Network::handleConfigChunk(void *tPtr,uint64_t packetId,const SharedPtr
int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk)
{
if (_destroyed)
if (m_destroyed)
return 0;
// _lock is NOT locked when this is called
try {
if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != _id))
if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != m_id))
return 0; // invalid config that is not for us or not for this network
if ((!Utils::allZero(nconf.issuedToFingerprintHash,ZT_FINGERPRINT_HASH_SIZE)) && (memcmp(nconf.issuedToFingerprintHash,RR->identity.fingerprint().hash(),ZT_FINGERPRINT_HASH_SIZE) != 0))
return 0; // full identity hash is present and does not match
if (_config == nconf)
if (m_config == nconf)
return 1; // OK config, but duplicate of what we already have
ZT_VirtualNetworkConfig ctmp;
bool oldPortInitialized;
{ // do things that require lock here, but unlock before calling callbacks
Mutex::Lock l1(_config_l);
Mutex::Lock l1(m_config_l);
_config = nconf;
_lastConfigUpdate = RR->node->now();
m_config = nconf;
m_lastConfigUpdate = RR->node->now();
_netconfFailure = NETCONF_FAILURE_NONE;
oldPortInitialized = _portInitialized;
_portInitialized = true;
oldPortInitialized = m_portInitialized;
m_portInitialized = true;
_externalConfig(&ctmp);
m_externalConfig(&ctmp);
}
RR->node->configureVirtualNetworkPort(tPtr,_id,&_uPtr,(oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp);
RR->node->configureVirtualNetworkPort(tPtr, m_id, &m_uPtr, (oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP, &ctmp);
if (saveToDisk) {
try {
Dictionary d;
if (nconf.toDictionary(d,false)) {
uint64_t tmp[2];
tmp[0] = _id; tmp[1] = 0;
tmp[0] = m_id; tmp[1] = 0;
std::vector<uint8_t> d2;
d.encode(d2);
RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_NETWORK_CONFIG,tmp,d2.data(),(unsigned int)d2.size());
@ -1065,22 +1065,22 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD
bool Network::gate(void *tPtr,const SharedPtr<Peer> &peer) noexcept
{
Mutex::Lock lc(_config_l);
Mutex::Lock lc(m_config_l);
if (!_config)
if (!m_config)
return false;
if (_config.isPublic())
if (m_config.isPublic())
return true;
try {
Mutex::Lock l(_memberships_l);
Membership *m = _memberships.get(peer->address());
Mutex::Lock l(m_memberships_l);
Membership *m = m_memberships.get(peer->address());
if (m) {
// SECURITY: this method in CertificateOfMembership does a full fingerprint check as well as
// checking certificate agreement. See Membership.hpp.
return m->certificateOfMembershipAgress(_config.com,peer->identity());
return m->certificateOfMembershipAgress(m_config.com, peer->identity());
} else {
m = &(_memberships[peer->address()]);
m = &(m_memberships[peer->address()]);
return false;
}
} catch ( ... ) {}
@ -1090,20 +1090,20 @@ bool Network::gate(void *tPtr,const SharedPtr<Peer> &peer) noexcept
void Network::doPeriodicTasks(void *tPtr,const int64_t now)
{
if (_destroyed)
if (m_destroyed)
return;
if ((now - _lastConfigUpdate) >= ZT_NETWORK_AUTOCONF_DELAY)
_requestConfiguration(tPtr);
if ((now - m_lastConfigUpdate) >= ZT_NETWORK_AUTOCONF_DELAY)
m_requestConfiguration(tPtr);
{
Mutex::Lock l1(_memberships_l);
Mutex::Lock l1(m_memberships_l);
for(Map<Address,Membership>::iterator i(_memberships.begin());i!=_memberships.end();++i)
i->second.clean(now,_config);
for(Map<Address,Membership>::iterator i(m_memberships.begin());i != m_memberships.end();++i)
i->second.clean(now, m_config);
{
Mutex::Lock l2(_myMulticastGroups_l);
Mutex::Lock l2(m_myMulticastGroups_l);
// TODO
/*
@ -1123,17 +1123,17 @@ void Network::doPeriodicTasks(void *tPtr,const int64_t now)
void Network::learnBridgeRoute(const MAC &mac,const Address &addr)
{
Mutex::Lock _l(_remoteBridgeRoutes_l);
_remoteBridgeRoutes[mac] = addr;
Mutex::Lock _l(m_remoteBridgeRoutes_l);
m_remoteBridgeRoutes[mac] = addr;
// Anti-DOS circuit breaker to prevent nodes from spamming us with absurd numbers of bridge routes
while (_remoteBridgeRoutes.size() > ZT_MAX_BRIDGE_ROUTES) {
while (m_remoteBridgeRoutes.size() > ZT_MAX_BRIDGE_ROUTES) {
Map< Address,unsigned long > counts;
Address maxAddr;
unsigned long maxCount = 0;
// Find the address responsible for the most entries
for(Map<MAC,Address>::iterator i(_remoteBridgeRoutes.begin());i!=_remoteBridgeRoutes.end();++i) {
for(Map<MAC,Address>::iterator i(m_remoteBridgeRoutes.begin());i != m_remoteBridgeRoutes.end();++i) {
const unsigned long c = ++counts[i->second];
if (c > maxCount) {
maxCount = c;
@ -1142,9 +1142,9 @@ void Network::learnBridgeRoute(const MAC &mac,const Address &addr)
}
// Kill this address from our table, since it's most likely spamming us
for(Map<MAC,Address>::iterator i(_remoteBridgeRoutes.begin());i!=_remoteBridgeRoutes.end();) {
for(Map<MAC,Address>::iterator i(m_remoteBridgeRoutes.begin());i != m_remoteBridgeRoutes.end();) {
if (i->second == maxAddr)
_remoteBridgeRoutes.erase(i++);
m_remoteBridgeRoutes.erase(i++);
else ++i;
}
}
@ -1152,37 +1152,37 @@ void Network::learnBridgeRoute(const MAC &mac,const Address &addr)
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const CertificateOfMembership &com)
{
if (com.networkId() != _id)
if (com.networkId() != m_id)
return Membership::ADD_REJECTED;
Mutex::Lock _l(_memberships_l);
return _memberships[com.issuedTo().address()].addCredential(RR,tPtr,sourcePeerIdentity,_config,com);
Mutex::Lock _l(m_memberships_l);
return m_memberships[com.issuedTo().address()].addCredential(RR, tPtr, sourcePeerIdentity, m_config, com);
}
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Capability &cap)
{
if (cap.networkId() != _id)
if (cap.networkId() != m_id)
return Membership::ADD_REJECTED;
Mutex::Lock _l(_memberships_l);
return _memberships[cap.issuedTo()].addCredential(RR,tPtr,sourcePeerIdentity,_config,cap);
Mutex::Lock _l(m_memberships_l);
return m_memberships[cap.issuedTo()].addCredential(RR, tPtr, sourcePeerIdentity, m_config, cap);
}
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Tag &tag)
{
if (tag.networkId() != _id)
if (tag.networkId() != m_id)
return Membership::ADD_REJECTED;
Mutex::Lock _l(_memberships_l);
return _memberships[tag.issuedTo()].addCredential(RR,tPtr,sourcePeerIdentity,_config,tag);
Mutex::Lock _l(m_memberships_l);
return m_memberships[tag.issuedTo()].addCredential(RR, tPtr, sourcePeerIdentity, m_config, tag);
}
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const Revocation &rev)
{
if (rev.networkId() != _id)
if (rev.networkId() != m_id)
return Membership::ADD_REJECTED;
Mutex::Lock l1(_memberships_l);
Membership &m = _memberships[rev.target()];
Mutex::Lock l1(m_memberships_l);
Membership &m = m_memberships[rev.target()];
const Membership::AddCredentialResult result = m.addCredential(RR,tPtr,sourcePeerIdentity,_config,rev);
const Membership::AddCredentialResult result = m.addCredential(RR, tPtr, sourcePeerIdentity, m_config, rev);
if ((result == Membership::ADD_ACCEPTED_NEW)&&(rev.fastPropagate())) {
// TODO
@ -1210,50 +1210,50 @@ Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Identity &sourcePeerIdentity,const CertificateOfOwnership &coo)
{
if (coo.networkId() != _id)
if (coo.networkId() != m_id)
return Membership::ADD_REJECTED;
Mutex::Lock _l(_memberships_l);
return _memberships[coo.issuedTo()].addCredential(RR,tPtr,sourcePeerIdentity,_config,coo);
Mutex::Lock _l(m_memberships_l);
return m_memberships[coo.issuedTo()].addCredential(RR, tPtr, sourcePeerIdentity, m_config, coo);
}
void Network::pushCredentials(void *tPtr,const SharedPtr<Peer> &to,const int64_t now)
{
const int64_t tout = std::min(_config.credentialTimeMaxDelta,_config.com.timestampMaxDelta());
Mutex::Lock _l(_memberships_l);
Membership &m = _memberships[to->address()];
const int64_t tout = std::min(m_config.credentialTimeMaxDelta, m_config.com.timestampMaxDelta());
Mutex::Lock _l(m_memberships_l);
Membership &m = m_memberships[to->address()];
if (((now - m.lastPushedCredentials()) + 5000) >= tout) {
m.pushCredentials(RR,tPtr,now,to,_config);
m.pushCredentials(RR, tPtr, now, to, m_config);
}
}
void Network::destroy()
{
_memberships_l.lock();
_config_l.lock();
_destroyed = true;
_config_l.unlock();
_memberships_l.unlock();
m_memberships_l.lock();
m_config_l.lock();
m_destroyed = true;
m_config_l.unlock();
m_memberships_l.unlock();
}
void Network::externalConfig(ZT_VirtualNetworkConfig *ec) const
{
Mutex::Lock _l(_config_l);
_externalConfig(ec);
Mutex::Lock _l(m_config_l);
m_externalConfig(ec);
}
void Network::_requestConfiguration(void *tPtr)
void Network::m_requestConfiguration(void *tPtr)
{
if (_destroyed)
if (m_destroyed)
return;
if ((_id >> 56U) == 0xff) {
if ((_id & 0xffffffU) == 0) {
const uint16_t startPortRange = (uint16_t)((_id >> 40U) & 0xffff);
const uint16_t endPortRange = (uint16_t)((_id >> 24U) & 0xffff);
if ((m_id >> 56U) == 0xff) {
if ((m_id & 0xffffffU) == 0) {
const uint16_t startPortRange = (uint16_t)((m_id >> 40U) & 0xffff);
const uint16_t endPortRange = (uint16_t)((m_id >> 24U) & 0xffff);
if (endPortRange >= startPortRange) {
ScopedPtr<NetworkConfig> nconf(new NetworkConfig());
nconf->networkId = _id;
nconf->networkId = m_id;
nconf->timestamp = RR->node->now();
nconf->credentialTimeMaxDelta = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA;
nconf->revision = 1;
@ -1263,7 +1263,7 @@ void Network::_requestConfiguration(void *tPtr)
nconf->multicastLimit = 0;
nconf->staticIpCount = 1;
nconf->ruleCount = 14;
nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,RR->identity.address().toInt());
nconf->staticIps[0] = InetAddress::makeIpv66plane(m_id, RR->identity.address().toInt());
// Drop everything but IPv6
nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_MATCH_ETHERTYPE | 0x80U; // NOT
@ -1316,13 +1316,13 @@ void Network::_requestConfiguration(void *tPtr)
} else {
this->setNotFound();
}
} else if ((_id & 0xffU) == 0x01) {
} else if ((m_id & 0xffU) == 0x01) {
// ffAAaaaaaaaaaa01 -- where AA is the IPv4 /8 to use and aaaaaaaaaa is the anchor node for multicast gather and replication
const uint64_t myAddress = RR->identity.address().toInt();
const uint64_t networkHub = (_id >> 8U) & 0xffffffffffULL;
const uint64_t networkHub = (m_id >> 8U) & 0xffffffffffULL;
uint8_t ipv4[4];
ipv4[0] = (uint8_t)(_id >> 48U);
ipv4[0] = (uint8_t)(m_id >> 48U);
ipv4[1] = (uint8_t)(myAddress >> 16U);
ipv4[2] = (uint8_t)(myAddress >> 8U);
ipv4[3] = (uint8_t)myAddress;
@ -1332,7 +1332,7 @@ void Network::_requestConfiguration(void *tPtr)
ScopedPtr<NetworkConfig> nconf(new NetworkConfig());
nconf->networkId = _id;
nconf->networkId = m_id;
nconf->timestamp = RR->node->now();
nconf->credentialTimeMaxDelta = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA;
nconf->revision = 1;
@ -1347,7 +1347,7 @@ void Network::_requestConfiguration(void *tPtr)
if (networkHub != 0)
nconf->specialists[0] = networkHub;
nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,myAddress);
nconf->staticIps[0] = InetAddress::makeIpv66plane(m_id, myAddress);
nconf->staticIps[1].set(ipv4,4,8);
nconf->rules[0].t = (uint8_t)ZT_NETWORK_RULE_ACTION_ACCEPT;
@ -1390,11 +1390,11 @@ void Network::_requestConfiguration(void *tPtr)
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_FLAGS,(uint64_t)0);
rmd.add(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_RULES_ENGINE_REV,(uint64_t)ZT_RULES_ENGINE_REVISION);
RR->t->networkConfigRequestSent(tPtr,0x335bb1a2,_id);
RR->t->networkConfigRequestSent(tPtr, 0x335bb1a2, m_id);
if (ctrl == RR->identity.address()) {
if (RR->localNetworkController) {
RR->localNetworkController->request(_id,InetAddress(),0xffffffffffffffffULL,RR->identity,rmd);
RR->localNetworkController->request(m_id, InetAddress(), 0xffffffffffffffffULL, RR->identity, rmd);
} else {
this->setNotFound();
}
@ -1420,7 +1420,7 @@ void Network::_requestConfiguration(void *tPtr)
*/
}
ZT_VirtualNetworkStatus Network::_status() const
ZT_VirtualNetworkStatus Network::m_status() const
{
switch(_netconfFailure) {
case NETCONF_FAILURE_ACCESS_DENIED:
@ -1428,36 +1428,36 @@ ZT_VirtualNetworkStatus Network::_status() const
case NETCONF_FAILURE_NOT_FOUND:
return ZT_NETWORK_STATUS_NOT_FOUND;
case NETCONF_FAILURE_NONE:
return ((_config) ? ZT_NETWORK_STATUS_OK : ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION);
return ((m_config) ? ZT_NETWORK_STATUS_OK : ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION);
default:
return ZT_NETWORK_STATUS_REQUESTING_CONFIGURATION;
}
}
void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
void Network::m_externalConfig(ZT_VirtualNetworkConfig *ec) const
{
// assumes _config_l is locked
ec->nwid = _id;
ec->mac = _mac.toInt();
if (_config)
Utils::scopy(ec->name,sizeof(ec->name),_config.name);
ec->nwid = m_id;
ec->mac = m_mac.toInt();
if (m_config)
Utils::scopy(ec->name, sizeof(ec->name), m_config.name);
else ec->name[0] = (char)0;
ec->status = _status();
ec->type = (_config) ? (_config.isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) : ZT_NETWORK_TYPE_PRIVATE;
ec->mtu = (_config) ? _config.mtu : ZT_DEFAULT_MTU;
ec->status = m_status();
ec->type = (m_config) ? (m_config.isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) : ZT_NETWORK_TYPE_PRIVATE;
ec->mtu = (m_config) ? m_config.mtu : ZT_DEFAULT_MTU;
std::vector<Address> ab;
for(unsigned int i=0;i<_config.specialistCount;++i) {
if ((_config.specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)
ab.push_back(Address(_config.specialists[i]));
for(unsigned int i=0;i < m_config.specialistCount;++i) {
if ((m_config.specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)
ab.push_back(Address(m_config.specialists[i]));
}
ec->bridge = (std::find(ab.begin(),ab.end(),RR->identity.address()) != ab.end()) ? 1 : 0;
ec->broadcastEnabled = (_config) ? (_config.enableBroadcast() ? 1 : 0) : 0;
ec->netconfRevision = (_config) ? (unsigned long)_config.revision : 0;
ec->broadcastEnabled = (m_config) ? (m_config.enableBroadcast() ? 1 : 0) : 0;
ec->netconfRevision = (m_config) ? (unsigned long)m_config.revision : 0;
ec->assignedAddressCount = 0;
for(unsigned int i=0;i<ZT_MAX_ZT_ASSIGNED_ADDRESSES;++i) {
if (i < _config.staticIpCount) {
Utils::copy<sizeof(struct sockaddr_storage)>(&(ec->assignedAddresses[i]),&(_config.staticIps[i]));
if (i < m_config.staticIpCount) {
Utils::copy<sizeof(struct sockaddr_storage)>(&(ec->assignedAddresses[i]),&(m_config.staticIps[i]));
++ec->assignedAddressCount;
} else {
Utils::zero<sizeof(struct sockaddr_storage)>(&(ec->assignedAddresses[i]));
@ -1466,8 +1466,8 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
ec->routeCount = 0;
for(unsigned int i=0;i<ZT_MAX_NETWORK_ROUTES;++i) {
if (i < _config.routeCount) {
Utils::copy<sizeof(ZT_VirtualNetworkRoute)>(&(ec->routes[i]),&(_config.routes[i]));
if (i < m_config.routeCount) {
Utils::copy<sizeof(ZT_VirtualNetworkRoute)>(&(ec->routes[i]),&(m_config.routes[i]));
++ec->routeCount;
} else {
Utils::zero<sizeof(ZT_VirtualNetworkRoute)>(&(ec->routes[i]));
@ -1475,11 +1475,11 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
}
}
void Network::_announceMulticastGroups(void *tPtr,bool force)
void Network::m_announceMulticastGroups(void *tPtr, bool force)
{
// Assumes _myMulticastGroups_l and _memberships_l are locked
const std::vector<MulticastGroup> groups(_allMulticastGroups());
_announceMulticastGroupsTo(tPtr,controller(),groups);
const Vector<MulticastGroup> groups(m_allMulticastGroups());
m_announceMulticastGroupsTo(tPtr, controller(), groups);
// TODO
/*
@ -1497,7 +1497,7 @@ void Network::_announceMulticastGroups(void *tPtr,bool force)
}
void Network::_announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups)
void Network::m_announceMulticastGroupsTo(void *tPtr, const Address &peer, const Vector<MulticastGroup> &allMulticastGroups)
{
#if 0
// Assumes _myMulticastGroups_l and _memberships_l are locked
@ -1523,15 +1523,15 @@ void Network::_announceMulticastGroupsTo(void *tPtr,const Address &peer,const st
#endif
}
std::vector<MulticastGroup> Network::_allMulticastGroups() const
Vector<MulticastGroup> Network::m_allMulticastGroups() const
{
// Assumes _myMulticastGroups_l is locked
std::vector<MulticastGroup> mgs;
mgs.reserve(_myMulticastGroups.size() + _multicastGroupsBehindMe.size() + 1);
mgs.insert(mgs.end(),_myMulticastGroups.begin(),_myMulticastGroups.end());
for(Map< MulticastGroup,uint64_t >::const_iterator i(_multicastGroupsBehindMe.begin());i!=_multicastGroupsBehindMe.end();++i)
Vector<MulticastGroup> mgs;
mgs.reserve(m_myMulticastGroups.size() + m_multicastGroupsBehindMe.size() + 1);
mgs.insert(mgs.end(), m_myMulticastGroups.begin(), m_myMulticastGroups.end());
for(Map<MulticastGroup,uint64_t>::const_iterator i(m_multicastGroupsBehindMe.begin());i != m_multicastGroupsBehindMe.end();++i)
mgs.push_back(i->first);
if ((_config)&&(_config.enableBroadcast()))
if ((m_config) && (m_config.enableBroadcast()))
mgs.push_back(Network::BROADCAST);
std::sort(mgs.begin(),mgs.end());
mgs.erase(std::unique(mgs.begin(),mgs.end()),mgs.end());

View file

@ -75,14 +75,14 @@ public:
~Network();
ZT_INLINE uint64_t id() const noexcept { return _id; }
ZT_INLINE Address controller() const noexcept { return Address(_id >> 24U); }
ZT_INLINE bool multicastEnabled() const noexcept { return (_config.multicastLimit > 0); }
ZT_INLINE bool hasConfig() const noexcept { return (_config); }
ZT_INLINE uint64_t lastConfigUpdate() const noexcept { return _lastConfigUpdate; }
ZT_INLINE ZT_VirtualNetworkStatus status() const noexcept { return _status(); }
ZT_INLINE const NetworkConfig &config() const noexcept { return _config; }
ZT_INLINE const MAC &mac() const noexcept { return _mac; }
ZT_INLINE uint64_t id() const noexcept { return m_id; }
ZT_INLINE Address controller() const noexcept { return Address(m_id >> 24U); }
ZT_INLINE bool multicastEnabled() const noexcept { return (m_config.multicastLimit > 0); }
ZT_INLINE bool hasConfig() const noexcept { return (m_config); }
ZT_INLINE uint64_t lastConfigUpdate() const noexcept { return m_lastConfigUpdate; }
ZT_INLINE ZT_VirtualNetworkStatus status() const noexcept { return m_status(); }
ZT_INLINE const NetworkConfig &config() const noexcept { return m_config; }
ZT_INLINE const MAC &mac() const noexcept { return m_mac; }
/**
* Apply filters to an outgoing packet
@ -156,11 +156,11 @@ public:
*/
ZT_INLINE bool subscribedToMulticastGroup(const MulticastGroup &mg,const bool includeBridgedGroups) const
{
Mutex::Lock l(_myMulticastGroups_l);
if (std::binary_search(_myMulticastGroups.begin(),_myMulticastGroups.end(),mg))
Mutex::Lock l(m_myMulticastGroups_l);
if (std::binary_search(m_myMulticastGroups.begin(), m_myMulticastGroups.end(), mg))
return true;
else if (includeBridgedGroups)
return (_multicastGroupsBehindMe.find(mg) != _multicastGroupsBehindMe.end());
return (m_multicastGroupsBehindMe.find(mg) != m_multicastGroupsBehindMe.end());
return false;
}
@ -242,8 +242,8 @@ public:
*/
ZT_INLINE Address findBridgeTo(const MAC &mac) const
{
Mutex::Lock _l(_remoteBridgeRoutes_l);
const Address *const br = _remoteBridgeRoutes.get(mac);
Mutex::Lock _l(m_remoteBridgeRoutes_l);
const Address *const br = m_remoteBridgeRoutes.get(mac);
return ((br) ? *br : Address());
}
@ -264,8 +264,8 @@ public:
*/
ZT_INLINE void learnBridgedMulticastGroup(void *tPtr,const MulticastGroup &mg,int64_t now)
{
Mutex::Lock l(_myMulticastGroups_l);
_multicastGroupsBehindMe.set(mg,now);
Mutex::Lock l(m_myMulticastGroups_l);
m_multicastGroupsBehindMe.set(mg, now);
}
/**
@ -325,8 +325,8 @@ public:
template<typename F>
ZT_INLINE void eachMember(F f)
{
Mutex::Lock ml(_memberships_l);
for(Map<Address,Membership>::iterator i(_memberships.begin());i!=_memberships.end();++i) { // NOLINT(modernize-loop-convert,hicpp-use-auto,modernize-use-auto)
Mutex::Lock ml(m_memberships_l);
for(Map<Address,Membership>::iterator i(m_memberships.begin());i != m_memberships.end();++i) { // NOLINT(modernize-loop-convert,hicpp-use-auto,modernize-use-auto)
if (!f(i->first,i->second))
break;
}
@ -335,40 +335,30 @@ public:
/**
* @return Externally usable pointer-to-pointer exported via the core API
*/
ZT_INLINE void **userPtr() noexcept { return &_uPtr; }
ZT_INLINE void **userPtr() noexcept { return &m_uPtr; }
private:
void _requestConfiguration(void *tPtr);
ZT_VirtualNetworkStatus _status() const;
void _externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked
void _announceMulticastGroups(void *tPtr,bool force);
void _announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups);
std::vector<MulticastGroup> _allMulticastGroups() const;
void m_requestConfiguration(void *tPtr);
ZT_VirtualNetworkStatus m_status() const;
void m_externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked
void m_announceMulticastGroups(void *tPtr, bool force);
void m_announceMulticastGroupsTo(void *tPtr, const Address &peer, const Vector<MulticastGroup> &allMulticastGroups);
Vector<MulticastGroup> m_allMulticastGroups() const;
const RuntimeEnvironment *const RR;
void *_uPtr;
const uint64_t _id;
Fingerprint _controllerFingerprint;
MAC _mac; // local MAC address
bool _portInitialized;
void *m_uPtr;
const uint64_t m_id;
Fingerprint m_controllerFingerprint;
MAC m_mac; // local MAC address
bool m_portInitialized;
std::atomic<bool> m_destroyed;
std::vector< MulticastGroup > _myMulticastGroups; // multicast groups that we belong to (according to tap)
Map< MulticastGroup,uint64_t > _multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge)
Map< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
Vector<MulticastGroup> m_myMulticastGroups; // multicast groups that we belong to (according to tap)
Map<MulticastGroup,int64_t> m_multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge)
Map<MAC,Address> m_remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
NetworkConfig _config;
std::atomic<int64_t> _lastConfigUpdate;
struct _IncomingConfigChunk
{
ZT_INLINE _IncomingConfigChunk() : touchCtr(0),updateId(0) {}
uint64_t touchCtr;
uint64_t updateId;
std::map< int,std::vector<uint8_t> > chunks;
};
_IncomingConfigChunk _incomingConfigChunks[ZT_NETWORK_MAX_INCOMING_UPDATES];
volatile bool _destroyed;
NetworkConfig m_config;
std::atomic<int64_t> m_lastConfigUpdate;
volatile enum {
NETCONF_FAILURE_NONE,
@ -377,12 +367,12 @@ private:
NETCONF_FAILURE_INIT_FAILED
} _netconfFailure;
Map<Address,Membership> _memberships;
Map<Address,Membership> m_memberships;
Mutex _myMulticastGroups_l;
Mutex _remoteBridgeRoutes_l;
Mutex _config_l;
Mutex _memberships_l;
Mutex m_myMulticastGroups_l;
Mutex m_remoteBridgeRoutes_l;
Mutex m_config_l;
Mutex m_memberships_l;
std::atomic<int> __refCount;
};

View file

@ -11,10 +11,6 @@
*/
/****/
#include <cstdlib>
#include <cstring>
#include <cstdint>
#include "Constants.hpp"
#include "SharedPtr.hpp"
#include "Node.hpp"
@ -90,7 +86,7 @@ Node::Node(void *uPtr,void *tPtr,const struct ZT_Node_Callbacks *callbacks,int64
{
// Load this node's identity.
uint64_t idtmp[2]; idtmp[0] = 0; idtmp[1] = 0;
std::vector<uint8_t> data(stateObjectGet(tPtr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp));
Vector<uint8_t> data(stateObjectGet(tPtr,ZT_STATE_OBJECT_IDENTITY_SECRET,idtmp));
bool haveIdentity = false;
if (!data.empty()) {
data.push_back(0); // zero-terminate string
@ -528,12 +524,12 @@ void Node::setController(void *networkControllerInstance)
// Methods used only within the core ----------------------------------------------------------------------------------
std::vector<uint8_t> Node::stateObjectGet(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2])
Vector<uint8_t> Node::stateObjectGet(void *const tPtr,ZT_StateObjectType type,const uint64_t id[2])
{
std::vector<uint8_t> r;
Vector<uint8_t> r;
if (m_cb.stateGetFunction) {
void *data = 0;
void (*freeFunc)(void *) = 0;
void *data = nullptr;
void (*freeFunc)(void *) = nullptr;
int l = m_cb.stateGetFunction(
reinterpret_cast<ZT_Node *>(this),
m_uPtr,

View file

@ -226,7 +226,7 @@ public:
* @param id Object ID
* @return Vector containing data or empty vector if not found or empty
*/
std::vector<uint8_t> stateObjectGet(void *tPtr,ZT_StateObjectType type,const uint64_t id[2]);
Vector<uint8_t> stateObjectGet(void *tPtr,ZT_StateObjectType type,const uint64_t id[2]);
/**
* Store a state object
@ -299,18 +299,6 @@ public:
*/
ZT_INLINE bool natMustDie() const noexcept { return m_natMustDie; }
/**
* Wake peer by calling its alarm() method at or after a given time.
*
* @param peer Identity fingerprint of peer to wake
* @param triggerTime Time alarm should go off
*/
ZT_INLINE void setPeerAlarm(const Fingerprint &peer,const int64_t triggerTime)
{
Mutex::Lock l(_peerAlarms_l);
_peerAlarms[peer] = triggerTime;
}
/**
* Check whether a local controller has authorized a member on a network
*

View file

@ -194,4 +194,7 @@ typedef unsigned uint128_t __attribute__((mode(TI)));
#endif
#endif
// Macro to print very verbose tracing information to standard error.
#define ZT_SPEW(f,...) fprintf(stderr,"%s(%d): " f ZT_EOL_S,__FILE__,__LINE__,__VA_ARGS__)
#endif

View file

@ -20,13 +20,7 @@
#include "Utils.hpp"
#include "Mutex.hpp"
#include "Meter.hpp"
#include <cstdint>
#include <cstring>
#include <cstdlib>
#include <stdexcept>
#include <algorithm>
#include <set>
#include "Containers.hpp"
namespace ZeroTier {
@ -151,7 +145,7 @@ private:
// These fields belong to Defragmenter but are kept in Path for performance
// as it's much faster this way than having Defragmenter maintain another
// mapping from paths to inbound message IDs.
std::set<uint64_t> _inboundFragmentedMessages;
Set<uint64_t> _inboundFragmentedMessages;
Mutex _inboundFragmentedMessages_l;
std::atomic<int> __refCount;

View file

@ -86,6 +86,32 @@ public:
return m_locator;
}
/**
* Set this peer's probe token
*
* This doesn't update the mapping in Topology. The caller must do
* this, which is the HELLO handler in VL1.
*
* @param t New probe token
* @return Old probe token
*/
ZT_INLINE uint32_t setProbeToken(const uint32_t t) const noexcept
{
RWMutex::Lock l(m_lock);
const uint32_t pt = m_probe;
m_probe = t;
return pt;
}
/**
* @return This peer's probe token or 0 if unknown
*/
ZT_INLINE uint32_t probeToken() const noexcept
{
RWMutex::RLock l(m_lock);
return m_probe;
}
/**
* Log receipt of an authenticated packet
*
@ -415,7 +441,7 @@ private:
List<p_TryQueueItem> m_tryQueue;
List<p_TryQueueItem>::iterator m_tryQueuePtr; // loops over _tryQueue like a circular buffer
// 32-bit probe or 0 if unknown.
// 32-bit probe token or 0 if unknown.
uint32_t m_probe;
uint16_t m_vProto;

114
node/PeerList.hpp Normal file
View file

@ -0,0 +1,114 @@
/*
* Copyright (c)2013-2020 ZeroTier, Inc.
*
* Use of this software is governed by the Business Source License included
* in the LICENSE.TXT file in the project's root directory.
*
* Change Date: 2024-01-01
*
* On the date above, in accordance with the Business Source License, use
* of this software will be governed by version 2.0 of the Apache License.
*/
/****/
#ifndef ZT_PEERLIST_HPP
#define ZT_PEERLIST_HPP
#include "Constants.hpp"
#include "SharedPtr.hpp"
#include "Peer.hpp"
namespace ZeroTier {
/**
* A list of peers
*
* This is a simple vector optimized for the case where there will almost always
* be zero or one element. In that case it doesn't allocate. If there's more than
* one element, it will grow to include all elements.
*
* It's used to return lookups in Topology where there will almost always be zero
* or one peers returned but where there technically (but very rarely) can be more.
*/
class PeerList
{
public:
ZT_INLINE PeerList() noexcept :
m_onePeer(),
m_peers(&m_onePeer),
m_peerCount(0)
{}
ZT_INLINE PeerList(const PeerList &pl)
{
const unsigned int pc = pl.m_peerCount;
if (likely(pc <= 1)) {
m_onePeer = pl.m_onePeer;
m_peers = &m_onePeer;
} else {
m_peers = new SharedPtr<Peer>[pc];
for (unsigned int i=0;i<pc;++i)
m_peers[i] = pl.m_peers[i];
}
m_peerCount = pc;
}
ZT_INLINE ~PeerList()
{
if (unlikely(m_peers != &m_onePeer))
delete [] m_peers;
}
ZT_INLINE PeerList &operator=(const PeerList &pl)
{
if (&pl != this) {
if (unlikely(m_peers != &m_onePeer))
delete [] m_peers;
if (likely(pl.m_peerCount <= 1)) {
m_onePeer = pl.m_onePeer;
m_peers = &m_onePeer;
} else {
m_onePeer.zero();
m_peers = new SharedPtr<Peer>[pl.m_peerCount];
for (unsigned int i = 0;i < pl.m_peerCount;++i)
m_peers[i] = pl.m_peers[i];
}
m_peerCount = pl.m_peerCount;
}
return *this;
}
/**
* Resize the peer list to store a given number of members
*
* To populate the list, this must be called first followed by each member
* being set with the [] operator. List content after this call is undefined
* and may contain old data if the object is being re-used.
*
* @param s New size of list
*/
ZT_INLINE void resize(const unsigned int s)
{
if (unlikely(m_peers != &m_onePeer))
delete [] m_peers;
m_peerCount = s;
if (likely(s <= 1)) {
m_peers = &m_onePeer;
} else {
m_peers = new SharedPtr<Peer>[s];
}
}
ZT_INLINE SharedPtr<Peer> &operator[](const unsigned int i) noexcept { return m_peers[i]; }
ZT_INLINE const SharedPtr<Peer> &operator[](const unsigned int i) const noexcept { return m_peers[i]; }
ZT_INLINE unsigned int size() const noexcept { return m_peerCount; }
private:
SharedPtr<Peer> m_onePeer;
SharedPtr<Peer> *m_peers;
unsigned int m_peerCount;
};
} // namespace ZeroTier
#endif

View file

@ -251,14 +251,16 @@
#define ZT_PROTO_HELLO_NODE_META_INSTANCE_ID "i"
#define ZT_PROTO_HELLO_NODE_META_LOCATOR "l"
#define ZT_PROTO_HELLO_NODE_META_PROBE_TOKEN "p"
#define ZT_PROTO_HELLO_NODE_META_NEIGHBORS "n"
#define ZT_PROTO_HELLO_NODE_META_SOFTWARE_VENDOR "s"
#define ZT_PROTO_HELLO_NODE_META_SOFTWARE_VERSION "v"
#define ZT_PROTO_HELLO_NODE_META_PHYSICAL_DEST "d"
#define ZT_PROTO_HELLO_NODE_META_COMPLIANCE "c"
#define ZT_PROTO_HELOO_NODE_META_EPHEMERAL_C25519 "0"
#define ZT_PROTO_HELOO_NODE_META_EPHEMERAL_P384 "1"
#define ZT_PROTO_HELOO_NODE_META_EPHEMERAL_REMOTE "R"
#define ZT_PROTO_HELLO_NODE_META_EPHEMERAL_C25519 "0"
#define ZT_PROTO_HELLO_NODE_META_EPHEMERAL_P384 "1"
#define ZT_PROTO_HELLO_NODE_META_EPHEMERAL_REMOTE "R"
static_assert(ZT_PROTO_MAX_PACKET_LENGTH < ZT_BUF_MEM_SIZE,"maximum packet length won't fit in Buf");
static_assert(ZT_PROTO_PACKET_ENCRYPTED_SECTION_START == (ZT_PROTO_MIN_PACKET_LENGTH-1),"encrypted packet section must start right before protocol verb at one less than minimum packet size");
namespace ZeroTier {
namespace Protocol {
@ -356,7 +358,6 @@ enum Verb
*
* NAME - arbitrary short user-defined name for this node
* CONTACT - arbitrary short contact information string for this node
* NEIGHBORS - addresses of node(s) to whom we'll relay (mesh-like routing)
* SOFTWARE_VENDOR - short name or description of vendor, such as a URL
* SOFTWARE_VERSION - major, minor, revision, and build (packed 64-bit int)
* PHYSICAL_DEST - serialized Endpoint to which this message was sent
@ -425,21 +426,28 @@ enum Verb
/**
* Relay-mediated NAT traversal or firewall punching initiation:
* <[1] flags (unused, currently 0)>
* <[5] ZeroTier address of peer that might be found at this address>
* <[5] ZeroTier address of other peer>
* <[2] 16-bit number of endpoints where peer might be reached>
* <[...] endpoints to attempt>
*
* Legacy packet format for pre-2.x peers:
* <[1] flags (unused, currently 0)>
* <[5] ZeroTier address of other peer>
* <[2] 16-bit protocol address port>
* <[1] protocol address length / type>
* <[...] protocol address (network byte order)>
*
* This is sent by a third party node to inform a node of where another
* may be located. These are currently only allowed from roots.
* When a root or other peer is relaying messages, it can periodically send
* RENDEZVOUS to assist peers in establishing direct communication.
*
* The protocol address format differs from the standard InetAddress
* encoding for legacy reasons, but it's not hard to decode. The following
* values are valid for the protocol address length (type) field:
* Peers also directly exchange information via HELLO, so this serves as
* a second way for peers to learn about their possible locations.
*
* 4 - IPv4 IP address
* 16 - IPv6 IP address
* 255 - Endpoint object, unmarshaled in place (port ignored)
* It also serves another function: temporal coordination of NAT traversal
* attempts. Some NATs traverse better if both sides first send "firewall
* opener" packets and then send real packets and if this exchange is
* coordinated in time so that the packets effectively pass each other in
* flight.
*
* No OK or ERROR is generated.
*/
@ -627,46 +635,7 @@ enum Verb
*/
VERB_MULTICAST_GATHER = 0x0d,
/** *** DEPRECATED ***
* Multicast frame:
* <[8] 64-bit network ID>
* <[1] flags>
* [<[4] 32-bit implicit gather limit>]
* [<[6] source MAC>]
* <[6] destination MAC (multicast address)>
* <[4] 32-bit multicast ADI (multicast address extension)>
* <[2] 16-bit ethertype>
* <[...] ethernet payload>
*
* Flags:
* 0x01 - Network certificate of membership attached (DEPRECATED)
* 0x02 - Implicit gather limit field is present
* 0x04 - Source MAC is specified -- otherwise it's computed from sender
* 0x08 - Please replicate (sent to multicast replicators)
*
* OK and ERROR responses are optional. OK may be generated if there are
* implicit gather results or if the recipient wants to send its own
* updated certificate of network membership to the sender. ERROR may be
* generated if a certificate is needed or if multicasts to this group
* are no longer wanted (multicast unsubscribe).
*
* OK response payload:
* <[8] 64-bit network ID>
* <[6] MAC address of multicast group>
* <[4] 32-bit ADI for multicast group>
* <[1] flags>
* [<[...] network certificate of membership (DEPRECATED)>]
* [<[...] implicit gather results if flag 0x01 is set>]
*
* OK flags (same bits as request flags):
* 0x01 - OK includes certificate of network membership (DEPRECATED)
* 0x02 - OK includes implicit gather results
*
* ERROR response payload:
* <[8] 64-bit network ID>
* <[6] multicast group MAC>
* <[4] 32-bit multicast group ADI>
*/
// Deprecated multicast frame message type.
VERB_MULTICAST_FRAME_deprecated = 0x0e,
/**
@ -676,14 +645,19 @@ enum Verb
*
* Path record format:
* <[1] 8-bit path flags>
* <[2] length of extended path data or 0 for none>
* <[...] extended path data>
* <[1] address type>
* <[1] address record length in bytes>
* <[...] address>
* <[2] length of endpoint record>
* <[...] endpoint>
*
* The following fields are also included if the node is pre-2.x:
* <[1] address type (LEGACY)>
* <[1] address length in bytes (LEGACY)>
* <[...] address (LEGACY)>
*
* Path flags:
* 0x01 - BFG1024 symmetric NAT-t requested
* Path record flags:
* 0x01 - reserved (legacy)
* 0x02 - reserved (legacy)
* 0x04 - Symmetric NAT detected at sender side
* 0x08 - Request aggressive symmetric NAT traversal
*
* OK and ERROR are not generated.
*/
@ -704,19 +678,6 @@ enum Verb
*/
VERB_USER_MESSAGE = 0x14,
/**
* Encapsulate a ZeroTier packet for multicast distribution:
* [... begin signed portion ...]
* <[1] 8-bit flags>
* <[5] 40-bit ZeroTier address of sender>
* <[2] 16-bit length of inner payload>
* <[1] inner payload verb>
* <[...] inner payload data>
* [... end signed portion ...]
* <[2] 16-bit length of signature or 0 if un-signed>
* [<[...] optional signature of multicast>]
* <[...] address (min prefix) list>
*/
VERB_MULTICAST = 0x16,
/**
@ -807,220 +768,6 @@ enum NetworkConfigFlag
NETWORK_CONFIG_FLAG_FAST_PROPAGATE = 0x01
};
/****************************************************************************/
/*
* These are bit-packed structures for rapid parsing of packets or at least
* the fixed size headers thereof. Not all packet types have these as some
* are full of variable length fields are are more easily parsed through
* incremental decoding.
*
* All fields larger than one byte are in big-endian byte order on the wire.
*/
/**
* Normal packet header
*
* @tparam PT Packet payload type (default: uint8_t[])
*/
ZT_PACKED_STRUCT(struct Header
{
uint64_t packetId;
uint8_t destination[5];
uint8_t source[5];
uint8_t flags;
uint64_t mac;
// --- begin encrypted envelope ---
uint8_t verb;
});
/**
* Packet fragment header
*/
ZT_PACKED_STRUCT(struct FragmentHeader
{
uint64_t packetId;
uint8_t destination[5];
uint8_t fragmentIndicator; // always 0xff for fragments
uint8_t counts; // total: most significant four bits, number: least significant four bits
uint8_t hops; // top 5 bits unused and must be zero
});
ZT_PACKED_STRUCT(struct HELLO
{
Header h;
uint8_t versionProtocol;
uint8_t versionMajor;
uint8_t versionMinor;
uint16_t versionRev;
uint64_t timestamp;
});
ZT_PACKED_STRUCT(struct RENDEZVOUS
{
Header h;
uint8_t flags;
uint8_t peerAddress[5];
uint16_t port;
uint8_t addressLength;
});
ZT_PACKED_STRUCT(struct FRAME
{
Header h;
uint64_t networkId;
uint16_t etherType;
});
ZT_PACKED_STRUCT(struct EXT_FRAME
{
Header h;
uint64_t networkId;
uint8_t flags;
});
ZT_PACKED_STRUCT(struct PUSH_DIRECT_PATHS
{
Header h;
uint16_t numPaths;
});
ZT_PACKED_STRUCT(struct MULTICAST_LIKE
{
ZT_PACKED_STRUCT(struct Entry
{
uint64_t networkId;
uint8_t mac[6];
uint32_t adi;
});
Header h;
});
namespace OK {
/**
* OK response header
*
* @tparam PT OK payload type (default: uint8_t[])
*/
ZT_PACKED_STRUCT(struct Header
{
Protocol::Header h;
uint8_t inReVerb;
uint64_t inRePacketId;
});
ZT_PACKED_STRUCT(struct WHOIS
{
OK::Header h;
});
ZT_PACKED_STRUCT(struct ECHO
{
OK::Header h;
});
ZT_PACKED_STRUCT(struct HELLO
{
OK::Header h;
uint64_t timestampEcho;
uint8_t versionProtocol;
uint8_t versionMajor;
uint8_t versionMinor;
uint16_t versionRev;
});
ZT_PACKED_STRUCT(struct EXT_FRAME
{
OK::Header h;
uint64_t networkId;
uint8_t flags;
uint8_t destMac[6];
uint8_t sourceMac[6];
uint16_t etherType;
});
ZT_PACKED_STRUCT(struct NETWORK_CONFIG
{
OK::Header h;
uint64_t networkId;
uint64_t configUpdateId;
});
} // namespace OK
namespace ERROR {
/**
* Error header
*
* The error header comes after the packet header but before type-specific payloads.
*
* @tparam PT Error payload type (default: uint8_t[])
*/
ZT_PACKED_STRUCT(struct Header
{
Protocol::Header h;
int8_t inReVerb;
uint64_t inRePacketId;
uint8_t error;
});
ZT_PACKED_STRUCT(struct NEED_MEMBERSHIP_CERTIFICATE
{
ERROR::Header h;
uint64_t networkId;
});
ZT_PACKED_STRUCT(struct UNSUPPORTED_OPERATION__NETWORK_CONFIG_REQUEST
{
ERROR::Header h;
uint64_t networkId;
});
} // namespace ERROR
/****************************************************************************/
static_assert(sizeof(Protocol::Header) == ZT_PROTO_MIN_PACKET_LENGTH,"Protocol::Header struct packing error");
static_assert(sizeof(Protocol::FragmentHeader) == ZT_PROTO_MIN_FRAGMENT_LENGTH,"Protocol::FragmentHeader struct packing error");
static_assert(ZT_PROTO_MAX_PACKET_LENGTH < ZT_BUF_MEM_SIZE,"maximum packet length won't fit in Buf");
static_assert(ZT_PROTO_PACKET_ENCRYPTED_SECTION_START == (ZT_PROTO_MIN_PACKET_LENGTH-1),"encrypted packet section must start right before protocol verb at one less than minimum packet size");
/**
* Convenience function to pull packet ID from a raw buffer
*
* @param pkt Packet to read first 8 bytes from
* @param packetSize Packet's actual size in bytes
* @return Packet ID or 0 if packet size is less than 8
*/
static ZT_INLINE uint64_t packetId(const Buf &pkt,const unsigned int packetSize) noexcept { return (packetSize >= 8) ? Utils::loadBigEndian<uint64_t>(pkt.unsafeData) : 0ULL; }
/**
* @param Packet to extract hops from
* @param packetSize Packet's actual size in bytes
* @return 3-bit hops field embedded in packet flags field
*/
static ZT_INLINE uint8_t packetHops(const Buf &pkt,const unsigned int packetSize) noexcept { return (packetSize >= ZT_PROTO_PACKET_FLAGS_INDEX) ? (pkt.unsafeData[ZT_PROTO_PACKET_FLAGS_INDEX] & ZT_PROTO_FLAG_FIELD_HOPS_MASK) : 0; }
/**
* @param Packet to extract cipher ID from
* @param packetSize Packet's actual size in bytes
* @return 3-bit cipher field embedded in packet flags field
*/
static ZT_INLINE uint8_t packetCipher(const Buf &pkt,const unsigned int packetSize) noexcept { return (packetSize >= ZT_PROTO_PACKET_FLAGS_INDEX) ? ((pkt.unsafeData[ZT_PROTO_PACKET_FLAGS_INDEX] >> 3U) & 0x07U) : 0; }
/**
* @return 3-bit hops field embedded in packet flags field
*/
static ZT_INLINE uint8_t packetHops(const Header &ph) noexcept { return (ph.flags & 0x07U); }
/**
* @return 3-bit cipher field embedded in packet flags field
*/
static ZT_INLINE uint8_t packetCipher(const Header &ph) noexcept { return ((ph.flags >> 3U) & 0x07U); }
/**
* Deterministically mangle a 256-bit crypto key based on packet characteristics
*

View file

@ -55,7 +55,7 @@ public:
secretIdentityStr[0] = (char)0;
}
ZT_INLINE ~RuntimeEnvironment()
ZT_INLINE ~RuntimeEnvironment() noexcept
{
Utils::burn(secretIdentityStr,sizeof(secretIdentityStr));
}

View file

@ -17,8 +17,7 @@
#include "Topology.hpp"
#include "Peer.hpp"
#include "Trace.hpp"
#include <set>
#include "Containers.hpp"
// Entry timeout -- make it fairly long since this is just to prevent stale buildup
#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 300000
@ -67,7 +66,7 @@ void SelfAwareness::iam(void *tPtr,const Identity &reporter,const int64_t receiv
// Erase all entries in this scope that were not reported from this remote address to prevent 'thrashing'
// due to multiple reports of endpoint change.
// Don't use 'entry' after this since hash table gets modified.
for(Map<p_PhySurfaceKey,p_PhySurfaceEntry>::iterator i(m_phy.begin());i != m_phy.end();) { // NOLINT(modernize-loop-convert,modernize-use-auto,hicpp-use-auto)
for(Map<p_PhySurfaceKey,p_PhySurfaceEntry>::iterator i(m_phy.begin());i != m_phy.end();) {
if ((i->first.scope == scope)&&(i->first.reporterPhysicalAddress != reporterPhysicalAddress))
m_phy.erase(i++);
else ++i;
@ -89,27 +88,29 @@ void SelfAwareness::iam(void *tPtr,const Identity &reporter,const int64_t receiv
void SelfAwareness::clean(int64_t now)
{
Mutex::Lock l(m_phy_l);
for(Map<p_PhySurfaceKey,p_PhySurfaceEntry>::iterator i(m_phy.begin());i != m_phy.end();) { // NOLINT(modernize-loop-convert,modernize-use-auto,hicpp-use-auto)
for(Map<p_PhySurfaceKey,p_PhySurfaceEntry>::iterator i(m_phy.begin());i != m_phy.end();) {
if ((now - i->second.ts) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT)
m_phy.erase(i++);
else ++i;
}
}
SelfAwareness::ExternalAddressList SelfAwareness::externalAddresses(const int64_t now) const
MultiMap<unsigned int,InetAddress> SelfAwareness::externalAddresses(const int64_t now) const
{
SelfAwareness::ExternalAddressList r;
Map<InetAddress,unsigned long> counts;
MultiMap<unsigned int,InetAddress> r;
// Count endpoints reporting each IP/port combo
Map<InetAddress,unsigned long> counts;
{
Mutex::Lock l(m_phy_l);
for(Map<p_PhySurfaceKey,p_PhySurfaceEntry>::const_iterator i(m_phy.begin());i != m_phy.end();++i) { // NOLINT(modernize-loop-convert,modernize-use-auto,hicpp-use-auto)
for(Map<p_PhySurfaceKey,p_PhySurfaceEntry>::const_iterator i(m_phy.begin());i != m_phy.end();++i) {
if ((now - i->second.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT)
++counts[i->second.mySurface];
}
}
for(Map<InetAddress,unsigned long>::iterator i(counts.begin());i!=counts.end();++i) // NOLINT(modernize-loop-convert,modernize-use-auto,hicpp-use-auto)
// Invert to create a map from count to address
for(Map<InetAddress,unsigned long>::iterator i(counts.begin());i!=counts.end();++i)
r.insert(std::pair<unsigned long,InetAddress>(i->second,i->first));
return r;

View file

@ -33,8 +33,6 @@ class RuntimeEnvironment;
class SelfAwareness
{
public:
typedef std::multimap< unsigned long,InetAddress,std::less<unsigned long>,Utils::Mallocator< std::pair<const unsigned long,InetAddress> > > ExternalAddressList;
explicit SelfAwareness(const RuntimeEnvironment *renv);
/**
@ -62,7 +60,7 @@ public:
* @param now Current time
* @return Map of count to IP/port representing how many endpoints reported each address
*/
ExternalAddressList externalAddresses(int64_t now) const;
MultiMap<unsigned int,InetAddress> externalAddresses(int64_t now) const;
private:
struct p_PhySurfaceKey

View file

@ -127,7 +127,31 @@ public:
if (m_ptr) {
if (--m_ptr->__refCount <= 0)
delete m_ptr;
m_ptr = (T *)0;
m_ptr = nullptr;
}
}
/**
* Set pointer to NULL and delete object if reference count is only 1
*
* This can be called periodically to implement something like a weak
* reference as it exists in other more managed languages like Java,
* but with the caveat that it only works if there is only one remaining
* SharedPtr to be treated as weak.
*
* @return True if object was in fact deleted or was already zero/NULL
*/
ZT_INLINE bool weakGC()
{
if (m_ptr) {
if (m_ptr->__refCount.compare_exchange_strong(1,0)) {
delete m_ptr;
m_ptr = nullptr;
return true;
}
return false;
} else {
return true;
}
}

View file

@ -15,31 +15,12 @@
namespace ZeroTier {
const uint64_t Topology::s_pathHashSalt = Utils::getSecureRandomU64();
// Sorts roots so as to put the lowest latency alive root first.
struct _RootSortComparisonOperator
{
ZT_INLINE _RootSortComparisonOperator(const int64_t now) : _now(now) {}
ZT_INLINE bool operator()(const SharedPtr<Peer> &a,const SharedPtr<Peer> &b)
{
const int64_t now = _now;
if (a->active(now)) {
if (b->active(now))
return (a->latency() < b->latency());
return true;
}
return a->lastReceive() < b->lastReceive();
}
const int64_t _now;
};
Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) :
RR(renv),
m_numConfiguredPhysicalPaths(0)
{
uint64_t idtmp[2]; idtmp[0] = 0; idtmp[1] = 0;
std::vector<uint8_t> data(RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_ROOTS,idtmp));
Vector<uint8_t> data(RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_ROOTS,idtmp));
if (!data.empty()) {
uint8_t *dptr = data.data();
int drem = (int)data.size();
@ -50,57 +31,66 @@ Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) :
m_roots.insert(id);
dptr += l;
drem -= l;
ZT_SPEW("recalled root %s",id.address().toString().c_str());
}
}
}
for(std::set<Identity>::const_iterator r(m_roots.begin());r != m_roots.end();++r) {
for(Set<Identity>::const_iterator r(m_roots.begin());r != m_roots.end();++r) {
SharedPtr<Peer> p;
m_loadCached(tPtr, r->address(), p);
m_loadCached(tPtr,r->address(),p);
if ((!p)||(p->identity() != *r)) {
p.set(new Peer(RR));
p->init(*r);
}
m_rootPeers.push_back(p);
m_peers[p->address()] = p;
m_peersByIncomingProbe[p->incomingProbe()] = p;
m_peersByIdentityHash[p->identity().fingerprint()] = p;
}
}
Topology::~Topology()
{
}
SharedPtr<Peer> Topology::add(void *tPtr,const SharedPtr<Peer> &peer)
{
RWMutex::Lock _l(m_peers_l);
SharedPtr<Peer> &hp = m_peers[peer->address()];
if (hp)
return hp;
m_loadCached(tPtr, peer->address(), hp);
if (hp) {
m_peersByIncomingProbe[peer->incomingProbe()] = hp;
m_peersByIdentityHash[peer->identity().fingerprint()] = hp;
m_loadCached(tPtr,peer->address(),hp);
if (hp)
return hp;
}
hp = peer;
m_peersByIncomingProbe[peer->incomingProbe()] = peer;
m_peersByIdentityHash[peer->identity().fingerprint()] = peer;
return peer;
}
void Topology::getAllPeers(std::vector< SharedPtr<Peer> > &allPeers) const
PeerList Topology::peersByProbeToken(const uint32_t probeToken) const
{
RWMutex::RLock l(m_peers_l);
allPeers.clear();
allPeers.reserve(m_peers.size());
for(Map< Address,SharedPtr<Peer> >::const_iterator i(m_peers.begin());i != m_peers.end();++i)
allPeers.push_back(i->second);
Mutex::Lock l(m_peersByProbeToken_l);
std::pair< MultiMap< uint32_t,SharedPtr<Peer> >::const_iterator,MultiMap< uint32_t,SharedPtr<Peer> >::const_iterator > r(m_peersByProbeToken.equal_range(probeToken));
PeerList pl;
if (r.first == r.second)
return pl;
const unsigned int cnt = (unsigned int)std::distance(r.first,r.second);
pl.resize(cnt);
MultiMap< uint32_t,SharedPtr<Peer> >::const_iterator pi(r.first);
for(unsigned int i=0;i<cnt;++i) {
pl[i] = pi->second;
++pi;
}
return pl;
}
void Topology::updateProbeToken(const SharedPtr<Peer> &peer,const uint32_t oldToken,const uint32_t newToken)
{
Mutex::Lock l(m_peersByProbeToken_l);
if (oldToken != 0) {
std::pair< MultiMap< uint32_t,SharedPtr<Peer> >::iterator,MultiMap< uint32_t,SharedPtr<Peer> >::iterator > r(m_peersByProbeToken.equal_range(oldToken));
for(MultiMap< uint32_t,SharedPtr<Peer> >::iterator i(r.first);i!=r.second;) {
if (i->second == peer)
m_peersByProbeToken.erase(i++);
else ++i;
}
}
if (newToken != 0)
m_peersByProbeToken.insert(std::pair< uint32_t,SharedPtr<Peer> >(newToken,peer));
}
void Topology::setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig)
@ -137,11 +127,25 @@ void Topology::setPhysicalPathConfiguration(const struct sockaddr_storage *pathN
}
}
void Topology::addRoot(void *tPtr,const Identity &id,const InetAddress &bootstrap)
struct p_RootSortComparisonOperator
{
if (id == RR->identity) return; // sanity check
ZT_INLINE bool operator()(const SharedPtr<Peer> &a,const SharedPtr<Peer> &b) const noexcept
{
// Sort in inverse order of latency with lowest latency first (and -1 last).
const int bb = b->latency();
if (bb < 0)
return true;
return bb < a->latency();
}
};
void Topology::addRoot(void *const tPtr,const Identity &id,const InetAddress &bootstrap)
{
if (id == RR->identity)
return;
RWMutex::Lock l1(m_peers_l);
std::pair< std::set<Identity>::iterator,bool > ir(m_roots.insert(id));
std::pair< Set<Identity>::iterator,bool > ir(m_roots.insert(id));
if (ir.second) {
SharedPtr<Peer> &p = m_peers[id.address()];
if (!p) {
@ -149,68 +153,56 @@ void Topology::addRoot(void *tPtr,const Identity &id,const InetAddress &bootstra
p->init(id);
if (bootstrap)
p->setBootstrap(Endpoint(bootstrap));
m_peersByIncomingProbe[p->incomingProbe()] = p;
m_peersByIdentityHash[p->identity().fingerprint()] = p;
}
m_rootPeers.push_back(p);
uint8_t *const roots = (uint8_t *)malloc(ZT_IDENTITY_MARSHAL_SIZE_MAX * m_roots.size());
if (roots) {
int p = 0;
for(std::set<Identity>::const_iterator i(m_roots.begin());i != m_roots.end();++i) {
int pp = i->marshal(roots + p,false);
if (pp > 0)
p += pp;
}
uint64_t id[2];
id[0] = 0;
id[1] = 0;
RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_ROOTS,id,roots,(unsigned int)p);
free(roots);
}
std::sort(m_rootPeers.begin(),m_rootPeers.end(),p_RootSortComparisonOperator());
m_writeRootList(tPtr);
}
}
bool Topology::removeRoot(const Identity &id)
bool Topology::removeRoot(void *const tPtr,const Identity &id)
{
RWMutex::Lock l1(m_peers_l);
std::set<Identity>::iterator r(m_roots.find(id));
Set<Identity>::iterator r(m_roots.find(id));
if (r != m_roots.end()) {
for(std::vector< SharedPtr<Peer> >::iterator p(m_rootPeers.begin());p != m_rootPeers.end();++p) {
for(Vector< SharedPtr<Peer> >::iterator p(m_rootPeers.begin());p != m_rootPeers.end();++p) {
if ((*p)->identity() == id) {
m_rootPeers.erase(p);
break;
}
}
m_roots.erase(r);
m_writeRootList(tPtr);
return true;
}
return false;
}
void Topology::rankRoots(const int64_t now)
void Topology::rankRoots()
{
RWMutex::Lock l1(m_peers_l);
std::sort(m_rootPeers.begin(), m_rootPeers.end(), _RootSortComparisonOperator(now));
std::sort(m_rootPeers.begin(),m_rootPeers.end(),p_RootSortComparisonOperator());
}
void Topology::doPeriodicTasks(void *tPtr,const int64_t now)
{
// Delete peers that haven't said anything in ZT_PEER_ALIVE_TIMEOUT.
{
RWMutex::Lock l1(m_peers_l);
for(Map< Address,SharedPtr<Peer> >::iterator i(m_peers.begin());i != m_peers.end();) {
if ( (!i->second->alive(now)) && (m_roots.count(i->second->identity()) == 0) ) {
if ( ((now - i->second->lastReceive()) > ZT_PEER_ALIVE_TIMEOUT) && (m_roots.count(i->second->identity()) == 0) ) {
updateProbeToken(i->second,i->second->probeToken(),0);
i->second->save(tPtr);
m_peersByIncomingProbe.erase(i->second->incomingProbe());
m_peersByIdentityHash.erase(i->second->identity().fingerprint());
m_peers.erase(i++);
} else ++i;
}
}
// Delete paths that are no longer held by anyone else ("weak reference" type behavior).
{
RWMutex::Lock l1(m_paths_l);
for(Map< uint64_t,SharedPtr<Path> >::iterator i(m_paths.begin());i != m_paths.end();) {
if ((i->second.references() <= 1)&&(!i->second->alive(now)))
if (i->second.weakGC())
m_paths.erase(i++);
else ++i;
}
@ -220,7 +212,7 @@ void Topology::doPeriodicTasks(void *tPtr,const int64_t now)
void Topology::saveAll(void *tPtr)
{
RWMutex::RLock l(m_peers_l);
for(Map< Address,SharedPtr<Peer> >::iterator i(m_peers.begin());i != m_peers.end();++i)
for(Map< Address,SharedPtr<Peer> >::iterator i(m_peers.begin());i!=m_peers.end();++i)
i->second->save(tPtr);
}
@ -230,7 +222,7 @@ void Topology::m_loadCached(void *tPtr, const Address &zta, SharedPtr<Peer> &pee
uint64_t id[2];
id[0] = zta.toInt();
id[1] = 0;
std::vector<uint8_t> data(RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,id));
Vector<uint8_t> data(RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,id));
if (data.size() > 8) {
const uint8_t *d = data.data();
int dl = (int)data.size();
@ -253,4 +245,23 @@ void Topology::m_loadCached(void *tPtr, const Address &zta, SharedPtr<Peer> &pee
}
}
void Topology::m_writeRootList(void *tPtr)
{
// assumes m_peers_l is locked
uint8_t *const roots = (uint8_t *)malloc(ZT_IDENTITY_MARSHAL_SIZE_MAX * m_roots.size());
if (roots) { // sanity check
int p = 0;
for(Set<Identity>::const_iterator i(m_roots.begin());i != m_roots.end();++i) {
const int pp = i->marshal(roots + p,false);
if (pp > 0)
p += pp;
}
uint64_t id[2];
id[0] = 0;
id[1] = 0;
RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_ROOTS,id,roots,(unsigned int)p);
free(roots);
}
}
} // namespace ZeroTier

View file

@ -14,12 +14,6 @@
#ifndef ZT_TOPOLOGY_HPP
#define ZT_TOPOLOGY_HPP
#include <cstring>
#include <vector>
#include <algorithm>
#include <utility>
#include <set>
#include "Constants.hpp"
#include "Address.hpp"
#include "Identity.hpp"
@ -31,6 +25,7 @@
#include "ScopedPtr.hpp"
#include "Fingerprint.hpp"
#include "Containers.hpp"
#include "PeerList.hpp"
namespace ZeroTier {
@ -43,7 +38,6 @@ class Topology
{
public:
Topology(const RuntimeEnvironment *renv,void *tPtr);
~Topology();
/**
* Add peer to database
@ -89,34 +83,21 @@ public:
}
/**
* Get a peer by its 384-bit identity public key hash
* Get peer(s) by 32-bit probe token
*
* @param hash Identity hash
* @return Peer or NULL if no peer is currently in memory for this hash (cache is not checked in this case)
* @param probeToken Probe token
* @return List of peers
*/
ZT_INLINE SharedPtr<Peer> peerByHash(const Fingerprint &hash)
{
RWMutex::RLock _l(m_peers_l);
const SharedPtr<Peer> *const ap = m_peersByIdentityHash.get(hash);
if (ap)
return *ap;
return SharedPtr<Peer>();
}
PeerList peersByProbeToken(uint32_t probeToken) const;
/**
* Get a peer by its incoming short probe packet payload
* Set or update the probe token associated with a peer
*
* @param probe Short probe payload (in big-endian byte order)
* @return Peer or NULL if no peer is currently in memory matching this probe (cache is not checked in this case)
* @param peer Peer to update
* @param oldToken Old probe token or 0 if none
* @param newToken New probe token or 0 to erase old mapping but not set a new token
*/
ZT_INLINE SharedPtr<Peer> peerByProbe(const uint64_t probe)
{
RWMutex::RLock _l(m_peers_l);
const SharedPtr<Peer> *const ap = m_peersByIncomingProbe.get(probe);
if (ap)
return *ap;
return SharedPtr<Peer>();
}
void updateProbeToken(const SharedPtr<Peer> &peer,uint32_t oldToken,uint32_t newToken);
/**
* Get a Path object for a given local and remote physical address, creating if needed
@ -163,7 +144,7 @@ public:
ZT_INLINE bool isRoot(const Identity &id) const
{
RWMutex::RLock l(m_peers_l);
return (m_roots.count(id) > 0);
return (m_roots.find(id) != m_roots.end());
}
/**
@ -209,24 +190,17 @@ public:
} catch ( ... ) {} // should not throw
}
/**
* Iterate through all paths in the system
*
* @tparam F Function to call for each path
* @param f
*/
template<typename F>
ZT_INLINE void eachPath(F f) const
{
RWMutex::RLock l(m_paths_l);
for(Map< uint64_t,SharedPtr<Path> >::const_iterator i(m_paths.begin());i != m_paths.end();++i) // NOLINT(modernize-loop-convert,hicpp-use-auto,modernize-use-auto)
f(i->second);
}
/**
* @param allPeers vector to fill with all current peers
*/
void getAllPeers(std::vector< SharedPtr<Peer> > &allPeers) const;
ZT_INLINE void getAllPeers(Vector< SharedPtr<Peer> > &allPeers) const
{
RWMutex::RLock l(m_peers_l);
allPeers.clear();
allPeers.reserve(m_peers.size());
for(Map< Address,SharedPtr<Peer> >::const_iterator i(m_peers.begin());i != m_peers.end();++i)
allPeers.push_back(i->second);
}
/**
* Get info about a path
@ -295,17 +269,18 @@ public:
/**
* Remove a root server's identity from the root server set
*
* @param tPtr Thread pointer
* @param id Root server identity
* @return True if root found and removed, false if not found
*/
bool removeRoot(const Identity &id);
bool removeRoot(void *tPtr,const Identity &id);
/**
* Sort roots in asecnding order of apparent latency
*
* @param now Current time
*/
void rankRoots(int64_t now);
void rankRoots();
/**
* Do periodic tasks such as database cleanup
@ -318,47 +293,45 @@ public:
void saveAll(void *tPtr);
private:
// Load cached peer and set 'peer' to it, if one is found.
void m_loadCached(void *tPtr, const Address &zta, SharedPtr<Peer> &peer);
// This is a secure random integer created at startup to salt the calculation of path hash map keys
static const uint64_t s_pathHashSalt;
void m_writeRootList(void *tPtr);
// This gets an integer key from an InetAddress for looking up paths.
static ZT_INLINE uint64_t s_getPathKey(int64_t l, const InetAddress &r)
static ZT_INLINE uint64_t s_getPathKey(const int64_t l,const InetAddress &r)
{
if (r.family() == AF_INET) {
return s_pathHashSalt + (uint64_t)(reinterpret_cast<const struct sockaddr_in *>(&r)->sin_addr.s_addr) + (uint64_t)Utils::ntoh(reinterpret_cast<const struct sockaddr_in *>(&r)->sin_port) + (uint64_t)l;
return ((uint64_t)(reinterpret_cast<const sockaddr_in *>(&r)->sin_addr.s_addr) << 24U) +
((uint64_t)reinterpret_cast<const sockaddr_in *>(&r)->sin_port << 8U) +
(uint64_t)l;
} else if (r.family() == AF_INET6) {
#ifdef ZT_NO_UNALIGNED_ACCESS
uint64_t h = s_pathHashSalt;
for(int i=0;i<16;++i) {
h += (uint64_t)((reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr)[i]);
h += (h << 10U);
h ^= (h >> 6U);
}
uint64_t htmp[2];
Utils::copy<16>(htmp,reinterpret_cast<const sockaddr_in6 *>(&r)->sin6_addr.s6_addr);
const uint64_t h = htmp[0] ^ htmp[1];
#else
uint64_t h = s_pathHashSalt + (reinterpret_cast<const uint64_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr)[0] + reinterpret_cast<const uint64_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr)[1]);
const uint64_t h = reinterpret_cast<const uint64_t *>(reinterpret_cast<const sockaddr_in6 *>(&r)->sin6_addr.s6_addr)[0] ^
reinterpret_cast<const uint64_t *>(reinterpret_cast<const sockaddr_in6 *>(&r)->sin6_addr.s6_addr)[1];
#endif
return h + (uint64_t)Utils::ntoh(reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_port) + (uint64_t)l;
return h + (uint64_t)Utils::ntoh(reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_port) ^ (uint64_t)l;
} else {
return Utils::fnv1a32(reinterpret_cast<const void *>(&r),sizeof(InetAddress)) + (uint64_t)l;
return (uint64_t)Utils::fnv1a32(reinterpret_cast<const void *>(&r),sizeof(InetAddress)) + (uint64_t)l;
}
}
const RuntimeEnvironment *const RR;
RWMutex m_peers_l;
RWMutex m_paths_l;
Mutex m_peersByProbeToken_l;
RWMutex m_peers_l;
std::pair< InetAddress,ZT_PhysicalPathConfiguration > m_physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS];
unsigned int m_numConfiguredPhysicalPaths;
Map< uint64_t,SharedPtr<Path> > m_paths;
MultiMap< uint32_t,SharedPtr<Peer> > m_peersByProbeToken;
Map< Address,SharedPtr<Peer> > m_peers;
Map< uint64_t,SharedPtr<Peer> > m_peersByIncomingProbe;
Map< Fingerprint,SharedPtr<Peer> > m_peersByIdentityHash;
Set< Identity > m_roots;
Vector< SharedPtr<Peer> > m_rootPeers;
};

View file

@ -18,10 +18,6 @@
#include "Path.hpp"
#include "InetAddress.hpp"
#include <cstdio>
#include <cstdlib>
#include <cstdarg>
// NOTE: packet IDs are always handled in network byte order, so no need to convert them.
namespace ZeroTier {

View file

@ -20,11 +20,7 @@
#include "InetAddress.hpp"
#include "Address.hpp"
#include "MAC.hpp"
#include <cstdint>
#include <cstring>
#include <cstdlib>
#include <vector>
#include "Containers.hpp"
#define ZT_TRACE_F_VL1 0x01U
#define ZT_TRACE_F_VL2 0x02U

View file

@ -17,9 +17,6 @@
#include "Constants.hpp"
#include "Utils.hpp"
#include <cstring>
#include <cstdlib>
namespace ZeroTier {
/**

View file

@ -23,8 +23,6 @@
#include "FCV.hpp"
#include "Containers.hpp"
#include <vector>
namespace ZeroTier {
class RuntimeEnvironment;

View file

@ -20,6 +20,7 @@
#include "Protocol.hpp"
#include "Mutex.hpp"
#include "FCV.hpp"
#include "Containers.hpp"
namespace ZeroTier {