mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-05 20:13:44 +02:00
A bunch of cleanup, bug fix, just use unordered_map, etc.
This commit is contained in:
parent
0d05e4bcae
commit
9428fc53f6
31 changed files with 449 additions and 447 deletions
|
@ -1370,7 +1370,7 @@ void EmbeddedNetworkController::_request(
|
|||
++caprc;
|
||||
}
|
||||
}
|
||||
nc->capabilities[nc->capabilityCount] = Capability((uint32_t)capId,nwid,now,1,capr,caprc);
|
||||
nc->capabilities[nc->capabilityCount] = Capability((uint32_t)capId,nwid,now,capr,caprc);
|
||||
if (nc->capabilities[nc->capabilityCount].sign(_signingId,identity.address()))
|
||||
++nc->capabilityCount;
|
||||
if (nc->capabilityCount >= ZT_MAX_NETWORK_CAPABILITIES)
|
||||
|
|
|
@ -51,7 +51,7 @@ ZT_INLINE void s_bmul64(const uint64_t x,const uint64_t y,uint64_t &r_high,uint6
|
|||
r |= z & m4;
|
||||
z = (x1 * y5) ^ (x2 * y4) ^ (x3 * y3) ^ (x4 * y2) ^ (x5 * y1);
|
||||
r |= z & m5;
|
||||
r_high = (uint64_t)(r >> 64);
|
||||
r_high = (uint64_t)(r >> 64U);
|
||||
r_low = (uint64_t)r;
|
||||
}
|
||||
|
||||
|
|
100
node/AES.hpp
100
node/AES.hpp
|
@ -130,6 +130,7 @@ public:
|
|||
}
|
||||
|
||||
class GMACSIVEncryptor;
|
||||
class GMACSIVDecryptor;
|
||||
|
||||
/**
|
||||
* Streaming GMAC calculator
|
||||
|
@ -137,6 +138,7 @@ public:
|
|||
class GMAC
|
||||
{
|
||||
friend class GMACSIVEncryptor;
|
||||
friend class GMACSIVDecryptor;
|
||||
|
||||
public:
|
||||
/**
|
||||
|
@ -209,6 +211,7 @@ public:
|
|||
class CTR
|
||||
{
|
||||
friend class GMACSIVEncryptor;
|
||||
friend class GMACSIVDecryptor;
|
||||
|
||||
public:
|
||||
ZT_INLINE CTR(const AES &aes) noexcept : _aes(aes) {}
|
||||
|
@ -250,7 +253,7 @@ public:
|
|||
};
|
||||
|
||||
/**
|
||||
* Encrypt with AES-GMAC-SIV
|
||||
* Encryptor for GMAC-SIV
|
||||
*/
|
||||
class GMACSIVEncryptor
|
||||
{
|
||||
|
@ -374,6 +377,101 @@ public:
|
|||
AES::CTR _ctr;
|
||||
};
|
||||
|
||||
/**
|
||||
* Decryptor for GMAC-SIV
|
||||
*/
|
||||
class GMACSIVDecryptor
|
||||
{
|
||||
public:
|
||||
ZT_INLINE GMACSIVDecryptor(const AES &k0,const AES &k1) noexcept :
|
||||
_ctr(k1),
|
||||
_gmac(k0) {}
|
||||
|
||||
/**
|
||||
* Initialize decryptor for a new message
|
||||
*
|
||||
* @param tag 128-bit combined IV/MAC originally created by GMAC-SIV encryption
|
||||
* @param output Buffer in which to write output plaintext (must be large enough!)
|
||||
*/
|
||||
ZT_INLINE void init(const uint64_t tag[2],void *const output) noexcept
|
||||
{
|
||||
// Init CTR with the most significant 96 bits of the tag (as in encryption).
|
||||
uint64_t tmp[2];
|
||||
tmp[0] = tag[0];
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
tmp[1] = tag[1] & 0xffffffff00000000ULL;
|
||||
#else
|
||||
tmp[1] = tag[1] & 0x00000000ffffffffULL;
|
||||
#endif
|
||||
_ctr.init(reinterpret_cast<const uint8_t *>(tmp),output);
|
||||
|
||||
// Decrypt the opaque tag to yield the original IV and 64-bit truncated MAC.
|
||||
_ctr._aes.decrypt(tag,_ivMac);
|
||||
|
||||
// Initialize GMAC with the original IV.
|
||||
tmp[0] = _ivMac[0];
|
||||
tmp[1] = 0;
|
||||
_gmac.init(reinterpret_cast<const uint8_t *>(tmp));
|
||||
|
||||
_output = output;
|
||||
_decryptedLen = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process AAD (additional authenticated data) that wasn't encrypted
|
||||
*
|
||||
* @param aad Additional authenticated data
|
||||
* @param len Length of AAD in bytes
|
||||
*/
|
||||
ZT_INLINE void aad(const void *const aad,unsigned int len) noexcept
|
||||
{
|
||||
_gmac.update(aad,len);
|
||||
len &= 0xfU;
|
||||
if (len != 0)
|
||||
_gmac.update(Utils::ZERO256,16 - len);
|
||||
}
|
||||
|
||||
/**
|
||||
* Feed ciphertext into the decryptor
|
||||
*
|
||||
* Unlike encryption, GMAC-SIV decryption requires only one pass.
|
||||
*
|
||||
* @param input Input ciphertext
|
||||
* @param len Length of ciphertext
|
||||
*/
|
||||
ZT_INLINE void update(const void *const input,const unsigned int len) noexcept
|
||||
{
|
||||
_ctr.crypt(input,len);
|
||||
_decryptedLen += len;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flush decryption, compute MAC, and verify
|
||||
*
|
||||
* @return True if resulting plaintext (and AAD) pass message authentication check
|
||||
*/
|
||||
ZT_INLINE bool finish() noexcept
|
||||
{
|
||||
// Flush any remaining bytes from CTR.
|
||||
_ctr.finish();
|
||||
|
||||
// Feed plaintext through GMAC.
|
||||
_gmac.update(_output,_decryptedLen);
|
||||
uint64_t gmacTag[2];
|
||||
_gmac.finish(reinterpret_cast<uint8_t *>(gmacTag));
|
||||
|
||||
// MAC passes if its first 64 bits equals the MAC we got by decrypting the tag.
|
||||
return gmacTag[0] == _ivMac[1];
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t _ivMac[2];
|
||||
AES::CTR _ctr;
|
||||
AES::GMAC _gmac;
|
||||
void *_output;
|
||||
unsigned int _decryptedLen;
|
||||
};
|
||||
|
||||
private:
|
||||
static const uint32_t Te0[256];
|
||||
static const uint32_t Te1[256];
|
||||
|
|
10
node/Buf.hpp
10
node/Buf.hpp
|
@ -329,7 +329,7 @@ public:
|
|||
template<typename T>
|
||||
ZT_INLINE int rO(int &ii,T &obj) const noexcept
|
||||
{
|
||||
if (ii < ZT_BUF_MEM_SIZE) {
|
||||
if (likely(ii < ZT_BUF_MEM_SIZE)) {
|
||||
int ms = obj.unmarshal(unsafeData + ii,ZT_BUF_MEM_SIZE - ii);
|
||||
if (ms > 0)
|
||||
ii += ms;
|
||||
|
@ -353,7 +353,7 @@ public:
|
|||
{
|
||||
const char *const s = (const char *)(unsafeData + ii);
|
||||
const int sii = ii;
|
||||
while (ii < ZT_BUF_MEM_SIZE) {
|
||||
while (likely(ii < ZT_BUF_MEM_SIZE)) {
|
||||
if (unsafeData[ii++] == 0) {
|
||||
Utils::copy(buf,s,ii - sii);
|
||||
return buf;
|
||||
|
@ -398,7 +398,7 @@ public:
|
|||
*/
|
||||
ZT_INLINE uint8_t *rB(int &ii,void *const bytes,const unsigned int len) const noexcept
|
||||
{
|
||||
if ((ii += (int)len) <= ZT_BUF_MEM_SIZE) {
|
||||
if (likely(((ii += (int)len) <= ZT_BUF_MEM_SIZE))) {
|
||||
Utils::copy(bytes,unsafeData + ii,len);
|
||||
return reinterpret_cast<uint8_t *>(bytes);
|
||||
}
|
||||
|
@ -586,7 +586,7 @@ public:
|
|||
ZT_INLINE void wO(int &ii,T &t) noexcept
|
||||
{
|
||||
const int s = ii;
|
||||
if ((s + T::marshalSizeMax()) <= ZT_BUF_MEM_SIZE) {
|
||||
if (likely((s + T::marshalSizeMax()) <= ZT_BUF_MEM_SIZE)) {
|
||||
int ms = t.marshal(unsafeData + s);
|
||||
if (ms > 0)
|
||||
ii += ms;
|
||||
|
@ -624,7 +624,7 @@ public:
|
|||
ZT_INLINE void wB(int &ii,const void *const bytes,const unsigned int len) noexcept
|
||||
{
|
||||
const int s = ii;
|
||||
if ((ii += (int)len) <= ZT_BUF_MEM_SIZE)
|
||||
if (likely((ii += (int)len) <= ZT_BUF_MEM_SIZE))
|
||||
Utils::copy(unsafeData + s,bytes,len);
|
||||
}
|
||||
|
||||
|
|
|
@ -2474,24 +2474,28 @@ void C25519::_calcPubDH(uint8_t pub[ZT_C25519_PUBLIC_KEY_LEN],const uint8_t priv
|
|||
|
||||
void C25519::_calcPubED(uint8_t pub[ZT_C25519_PUBLIC_KEY_LEN],const uint8_t priv[ZT_C25519_PRIVATE_KEY_LEN])
|
||||
{
|
||||
unsigned char extsk[64];
|
||||
sc25519 scsk;
|
||||
ge25519 gepk;
|
||||
struct {
|
||||
uint8_t extsk[64];
|
||||
sc25519 scsk;
|
||||
ge25519 gepk;
|
||||
} s;
|
||||
|
||||
// Second 32 bytes of pub and priv are the keys for ed25519
|
||||
// signing and verification.
|
||||
SHA512(extsk,priv + 32,32);
|
||||
extsk[0] &= 248;
|
||||
extsk[31] &= 127;
|
||||
extsk[31] |= 64;
|
||||
sc25519_from32bytes(&scsk,extsk);
|
||||
ge25519_scalarmult_base(&gepk,&scsk);
|
||||
ge25519_pack(pub + 32,&gepk);
|
||||
SHA512(s.extsk,priv + 32,32);
|
||||
s.extsk[0] &= 248U;
|
||||
s.extsk[31] &= 127U;
|
||||
s.extsk[31] |= 64U;
|
||||
sc25519_from32bytes(&s.scsk,s.extsk);
|
||||
ge25519_scalarmult_base(&s.gepk,&s.scsk);
|
||||
ge25519_pack(pub + 32,&s.gepk);
|
||||
|
||||
// In NaCl, the public key is crammed into the next 32 bytes
|
||||
// of the private key for signing since both keys are required
|
||||
// to sign. In this version we just get it from kp.pub, so we
|
||||
// leave that out of private.
|
||||
|
||||
Utils::burn(&s,sizeof(s));
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
|
@ -17,12 +17,12 @@ set(core_headers
|
|||
Expect.hpp
|
||||
FCV.hpp
|
||||
Fingerprint.hpp
|
||||
FlatMap.hpp
|
||||
Identity.hpp
|
||||
InetAddress.hpp
|
||||
Locator.hpp
|
||||
LZ4.hpp
|
||||
MAC.hpp
|
||||
Map.hpp
|
||||
Membership.hpp
|
||||
MulticastGroup.hpp
|
||||
Mutex.hpp
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include "Mutex.hpp"
|
||||
#include "Path.hpp"
|
||||
#include "FCV.hpp"
|
||||
#include "FlatMap.hpp"
|
||||
#include "Map.hpp"
|
||||
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
@ -164,7 +164,7 @@ public:
|
|||
std::vector<std::pair<int64_t,uint64_t> > messagesByLastUsedTime;
|
||||
messagesByLastUsedTime.reserve(_messages.size());
|
||||
|
||||
for(typename FlatMap< uint64_t,_E >::const_iterator i(_messages.begin());i!=_messages.end();++i)
|
||||
for(typename Map< uint64_t,_E >::const_iterator i(_messages.begin());i!=_messages.end();++i)
|
||||
messagesByLastUsedTime.push_back(std::pair<int64_t,uint64_t>(i->second.lastUsed,i->first));
|
||||
std::sort(messagesByLastUsedTime.begin(),messagesByLastUsedTime.end());
|
||||
|
||||
|
@ -286,6 +286,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
// _E is an entry in the message queue.
|
||||
struct _E
|
||||
{
|
||||
ZT_INLINE _E() noexcept :
|
||||
|
@ -312,6 +313,19 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
ZT_INLINE _E &operator=(const _E &e)
|
||||
{
|
||||
if (this != &e) {
|
||||
id = e.id;
|
||||
lastUsed = e.lastUsed;
|
||||
totalFragmentsExpected = e.totalFragmentsExpected;
|
||||
fragmentsReceived = e.fragmentsReceived;
|
||||
via = e.via;
|
||||
message = e.message;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
uint64_t id;
|
||||
volatile int64_t lastUsed;
|
||||
unsigned int totalFragmentsExpected;
|
||||
|
@ -321,7 +335,7 @@ private:
|
|||
Mutex lock;
|
||||
};
|
||||
|
||||
FlatMap< uint64_t,_E > _messages;
|
||||
Map< uint64_t,_E > _messages;
|
||||
RWMutex _messages_l;
|
||||
};
|
||||
|
||||
|
|
|
@ -15,19 +15,6 @@
|
|||
|
||||
namespace ZeroTier {
|
||||
|
||||
static uint64_t _toKey(const char *k)
|
||||
{
|
||||
uint64_t n = 0;
|
||||
unsigned int i = 0;
|
||||
for(;;) {
|
||||
char c = k[i];
|
||||
if (!c) break;
|
||||
reinterpret_cast<uint8_t *>(&n)[i & 7U] ^= (uint8_t)c;
|
||||
++i;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
Dictionary::Dictionary()
|
||||
{
|
||||
}
|
||||
|
@ -80,7 +67,7 @@ void Dictionary::add(const char *k,uint64_t v)
|
|||
void Dictionary::add(const char *k,const Address &v)
|
||||
{
|
||||
std::vector<uint8_t> &e = (*this)[k];
|
||||
e.resize(11);
|
||||
e.resize(ZT_ADDRESS_STRING_SIZE_MAX);
|
||||
v.toString((char *)e.data());
|
||||
}
|
||||
|
||||
|
@ -109,7 +96,6 @@ void Dictionary::add(const char *k,const void *data,unsigned int len)
|
|||
|
||||
bool Dictionary::getB(const char *k,bool dfl) const
|
||||
{
|
||||
bool v = dfl;
|
||||
const std::vector<uint8_t> &e = (*this)[k];
|
||||
if (!e.empty()) {
|
||||
switch ((char)e[0]) {
|
||||
|
@ -123,7 +109,7 @@ bool Dictionary::getB(const char *k,bool dfl) const
|
|||
return false;
|
||||
}
|
||||
}
|
||||
return v;
|
||||
return dfl;
|
||||
}
|
||||
|
||||
uint64_t Dictionary::getUI(const char *k,uint64_t dfl) const
|
||||
|
@ -173,7 +159,6 @@ void Dictionary::encode(std::vector<uint8_t> &out) const
|
|||
for(std::map< uint64_t,std::vector<uint8_t> >::const_iterator ti(_t.begin());ti!=_t.end();++ti) {
|
||||
str[0] = ti->first;
|
||||
const char *k = (const char *)str;
|
||||
|
||||
for(;;) {
|
||||
char kc = *(k++);
|
||||
if (!kc) break;
|
||||
|
|
|
@ -30,7 +30,7 @@ namespace ZeroTier {
|
|||
*
|
||||
* This data structure is used for network configurations, node meta-data,
|
||||
* and other open-definition protocol objects. It consists of a key-value
|
||||
* store with short (under 8 characters) keys that map to strings, blobs,
|
||||
* store with short (max: 8 characters) keys that map to strings, blobs,
|
||||
* or integers with the latter being by convention in hex format.
|
||||
*
|
||||
* If this seems a little odd, it is. It dates back to the very first alpha
|
||||
|
@ -168,6 +168,18 @@ public:
|
|||
bool decode(const void *data,unsigned int len);
|
||||
|
||||
private:
|
||||
// This just packs up to 8 character bytes into a 64-bit word. There is no need
|
||||
// for this to be portable in terms of endian-ness. It's just for fast key lookup.
|
||||
static ZT_INLINE uint64_t _toKey(const char *k)
|
||||
{
|
||||
uint64_t key = 0;
|
||||
for(int i=0;i<8;++i) {
|
||||
if ((reinterpret_cast<uint8_t *>(&key)[i] = *(k++)) == 0)
|
||||
break;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
|
||||
std::map< uint64_t,std::vector<uint8_t> > _t;
|
||||
};
|
||||
|
||||
|
|
|
@ -80,7 +80,7 @@ private:
|
|||
const uint64_t _salt;
|
||||
|
||||
// Each bucket contains a timestamp in units of the expect duration.
|
||||
std::atomic<int32_t> _packetIdSent[ZT_EXPECT_TTL];
|
||||
std::atomic<int32_t> _packetIdSent[ZT_EXPECT_BUCKETS];
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
245
node/FlatMap.hpp
245
node/FlatMap.hpp
|
@ -1,245 +0,0 @@
|
|||
/*
|
||||
* 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_FLATMAP_HPP
|
||||
#define ZT_FLATMAP_HPP
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <utility>
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* A very simple and fast flat hash table
|
||||
*
|
||||
* This is designed to prioritize performance over memory, though with
|
||||
* endpoint ZeroTier nodes this is used in cases where the data set is not
|
||||
* that large (e.g. networks, peers) and so memory consumption should not
|
||||
* be much.
|
||||
*
|
||||
* It creates a flat hash table that maps keys to values and doubles its
|
||||
* size whenever a collision occurs. The size is always a power of two so
|
||||
* that only very fast operations like add, XOR, and bit mask can be used
|
||||
* for hash table lookup.
|
||||
*
|
||||
* It also saves actual key/value pairs in a linked list for relatively
|
||||
* fast iteration compared to a hash table where you have to iterate through
|
||||
* a bunch of empty buckets. Iteration order should be considered undefined.
|
||||
*
|
||||
* @tparam K Key type
|
||||
* @tparam V Value type
|
||||
* @tparam IC Initial capacity (must be a power of two)
|
||||
*/
|
||||
template<typename K,typename V,unsigned long IC = 16>
|
||||
class FlatMap
|
||||
{
|
||||
public:
|
||||
typedef K key_type;
|
||||
typedef V mapped_type;
|
||||
typedef std::pair<K,V> value_type;
|
||||
typedef typename std::list< std::pair<K,V> >::iterator iterator;
|
||||
typedef typename std::list< std::pair<K,V> >::const_iterator const_iterator;
|
||||
|
||||
ZT_INLINE FlatMap() :
|
||||
_d(),
|
||||
_null(),
|
||||
_b(new iterator[IC]),
|
||||
_s(IC),
|
||||
_m(IC - 1)
|
||||
{
|
||||
}
|
||||
|
||||
ZT_INLINE FlatMap(const FlatMap &m) :
|
||||
_d(m._d),
|
||||
_null(),
|
||||
_b(new iterator[m._s]),
|
||||
_s(m._s),
|
||||
_m(m._m)
|
||||
{
|
||||
try {
|
||||
for (iterator i=_d.begin();i!=_d.end();++i)
|
||||
_b[_hc(i->first) & _m] = i;
|
||||
} catch ( ... ) {
|
||||
delete [] _b;
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
ZT_INLINE ~FlatMap()
|
||||
{
|
||||
delete [] _b;
|
||||
}
|
||||
|
||||
ZT_INLINE FlatMap &operator=(const FlatMap &m)
|
||||
{
|
||||
_d = m._d;
|
||||
delete [] _b;
|
||||
_b = nullptr;
|
||||
_b = new iterator[m._s];
|
||||
_s = m._s;
|
||||
_m = m._m;
|
||||
for(iterator i=_d.begin();i!=_d.end();++i)
|
||||
_b[_hc(i->first) & _m] = i;
|
||||
}
|
||||
|
||||
ZT_INLINE void clear()
|
||||
{
|
||||
_d.clear();
|
||||
delete [] _b;
|
||||
_b = nullptr;
|
||||
_b = new iterator[IC];
|
||||
_s = IC;
|
||||
_m = IC - 1;
|
||||
}
|
||||
|
||||
ZT_INLINE V *get(const K &key) noexcept
|
||||
{
|
||||
const unsigned long hb = _hc(key) & _m;
|
||||
if ((_b[hb] != _null)&&(_b[hb]->first == key))
|
||||
return &(_b[hb]->second);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ZT_INLINE const V *get(const K &key) const noexcept
|
||||
{
|
||||
const unsigned long hb = _hc(key) & _m;
|
||||
if ((_b[hb] != _null)&&(_b[hb]->first == key))
|
||||
return &(_b[hb]->second);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ZT_INLINE iterator find(const K &key) noexcept
|
||||
{
|
||||
const unsigned long hb = _hc(key) & _m;
|
||||
if ((_b[hb] != _null)&&(_b[hb]->first == key))
|
||||
return _b[hb];
|
||||
return _d.end();
|
||||
}
|
||||
|
||||
ZT_INLINE const_iterator find(const K &key) const noexcept
|
||||
{
|
||||
const unsigned long hb = _hc(key) & _m;
|
||||
if ((_b[hb] != _null)&&(_b[hb]->first == key))
|
||||
return _b[hb];
|
||||
return _d.end();
|
||||
}
|
||||
|
||||
ZT_INLINE V &set(const K &key,const V &value)
|
||||
{
|
||||
unsigned long hb = _hc(key) & _m;
|
||||
if (_b[hb] == _null) {
|
||||
#ifdef __CPP11__
|
||||
_d.emplace_back(key,value);
|
||||
#else
|
||||
_d.push_back(std::pair<K,V>(key,value));
|
||||
#endif
|
||||
return (_b[hb] = --_d.end())->second;
|
||||
} else {
|
||||
if (_b[hb]->first == key) {
|
||||
_b[hb]->second = value;
|
||||
return _b[hb]->second;
|
||||
}
|
||||
#ifdef __CPP11__
|
||||
_d.emplace_back(key,value);
|
||||
#else
|
||||
_d.push_back(std::pair<K,V>(key,value));
|
||||
#endif
|
||||
_grow();
|
||||
return _b[_hc(key) & _m]->second;
|
||||
}
|
||||
}
|
||||
|
||||
ZT_INLINE V &operator[](const K &key)
|
||||
{
|
||||
unsigned long hb = _hc(key) & _m;
|
||||
if (_b[hb] == _null) {
|
||||
#ifdef __CPP11__
|
||||
_d.emplace_back(key,V());
|
||||
#else
|
||||
_d.push_back(std::pair<K,V>(key,V()));
|
||||
#endif
|
||||
return (_b[hb] = --_d.end())->second;
|
||||
} else {
|
||||
if (_b[hb]->first == key)
|
||||
return _b[hb]->second;
|
||||
#ifdef __CPP11__
|
||||
_d.emplace_back(key,V());
|
||||
#else
|
||||
_d.push_back(std::pair<K,V>(key,V()));
|
||||
#endif
|
||||
_grow();
|
||||
return _b[_hc(key) & _m]->second;
|
||||
}
|
||||
}
|
||||
|
||||
ZT_INLINE void erase(const iterator &i)
|
||||
{
|
||||
_b[_hc(i->first) & _m] = _null;
|
||||
_d.erase(i);
|
||||
}
|
||||
|
||||
ZT_INLINE void erase(const K &key)
|
||||
{
|
||||
iterator e(find(key));
|
||||
if (e != end())
|
||||
erase(e);
|
||||
}
|
||||
|
||||
ZT_INLINE iterator begin() noexcept { return _d.begin(); }
|
||||
ZT_INLINE iterator end() noexcept { return _d.end(); }
|
||||
ZT_INLINE const_iterator begin() const noexcept { return _d.begin(); }
|
||||
ZT_INLINE const_iterator end() const noexcept { return _d.end(); }
|
||||
|
||||
ZT_INLINE unsigned long size() const { return (unsigned long)_d.size(); }
|
||||
ZT_INLINE bool empty() const { return _d.empty(); }
|
||||
ZT_INLINE unsigned long hashSize() const { return _s; }
|
||||
|
||||
private:
|
||||
template<typename O>
|
||||
static ZT_INLINE unsigned long _hc(const O &obj) { return (unsigned long)obj.hashCode(); }
|
||||
static ZT_INLINE unsigned long _hc(const uint64_t i) noexcept { return (unsigned long)(i + (i >> 32U)); }
|
||||
static ZT_INLINE unsigned long _hc(const int64_t i) noexcept { return (unsigned long)((uint64_t)i + ((uint64_t)i >> 32U)); }
|
||||
static ZT_INLINE unsigned long _hc(const uint32_t i) noexcept { return Utils::hash32(i); }
|
||||
|
||||
ZT_INLINE void _grow()
|
||||
{
|
||||
unsigned long hb;
|
||||
enlarge_again:
|
||||
delete [] _b;
|
||||
_b = nullptr; // in case 'new' throws
|
||||
_b = new iterator[_s <<= 1U];
|
||||
_m = _s - 1;
|
||||
for(iterator i=_d.begin();i!=_d.end();++i) {
|
||||
hb = _hc(i->first) & _m;
|
||||
if (_b[hb] == _null) {
|
||||
_b[hb] = i;
|
||||
} else {
|
||||
goto enlarge_again;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::list< std::pair<K,V> > _d;
|
||||
const iterator _null; // prototype of a "null" / default iterator
|
||||
iterator *_b;
|
||||
unsigned long _s;
|
||||
unsigned long _m;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
|
@ -85,16 +85,9 @@ struct identityV0ProofOfWorkCriteria
|
|||
bool identityV1ProofOfWorkCriteria(const void *in,const unsigned int len)
|
||||
{
|
||||
uint64_t b[98304]; // 768 KiB of working memory
|
||||
uint64_t polykey[4];
|
||||
|
||||
SHA512(b,in,len);
|
||||
|
||||
// Poly1305 key, used in final hash at the end.
|
||||
polykey[0] = b[0];
|
||||
polykey[1] = b[1];
|
||||
polykey[2] = b[2];
|
||||
polykey[3] = b[3];
|
||||
|
||||
#if __BYTE_ORDER == __BIG_ENDIAN
|
||||
b[0] = Utils::swapBytes(b[0]);
|
||||
b[1] = Utils::swapBytes(b[1]);
|
||||
|
@ -152,9 +145,7 @@ bool identityV1ProofOfWorkCriteria(const void *in,const unsigned int len)
|
|||
}
|
||||
#endif
|
||||
|
||||
// Use poly1305 to compute a very fast digest of 'b'. This doesn't have to be
|
||||
// cryptographic per se, just have good hashing properties.
|
||||
poly1305(b,b,sizeof(b),polykey);
|
||||
SHA384(b,b,sizeof(b),in,len);
|
||||
|
||||
// Criterion: add two 64-bit components of poly1305 hash, must be zero mod 180.
|
||||
// As with the rest of this bits are used in little-endian byte order. The value
|
||||
|
|
94
node/Map.hpp
Normal file
94
node/Map.hpp
Normal file
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* 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_MAP_HPP
|
||||
#define ZT_MAP_HPP
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Utils.hpp"
|
||||
|
||||
#ifdef __CPP11__
|
||||
#include <unordered_map>
|
||||
#else
|
||||
#include <map>
|
||||
#endif
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
#ifdef __CPP11__
|
||||
struct _MapHasher
|
||||
{
|
||||
template<typename O>
|
||||
std::size_t operator()(const O &obj) const noexcept { return (std::size_t)obj.hashCode() ^ (std::size_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>
|
||||
{
|
||||
public:
|
||||
ZT_INLINE V *get(const K &key) noexcept
|
||||
{
|
||||
typename Map::iterator i(this->find(key));
|
||||
if (i == this->end())
|
||||
return nullptr;
|
||||
return &(i->second);
|
||||
}
|
||||
|
||||
ZT_INLINE const V *get(const K &key) const noexcept
|
||||
{
|
||||
typename Map::const_iterator i(this->find(key));
|
||||
if (i == this->end())
|
||||
return nullptr;
|
||||
return &(i->second);
|
||||
}
|
||||
|
||||
ZT_INLINE void set(const K &key,const V &value)
|
||||
{
|
||||
this->emplace(key,value);
|
||||
}
|
||||
};
|
||||
#else
|
||||
template<typename K,typename V>
|
||||
class Map : public std::map<K,V>
|
||||
{
|
||||
public:
|
||||
ZT_INLINE V *get(const K &key) noexcept
|
||||
{
|
||||
typename Map::iterator i(this->find(key));
|
||||
if (i == this->end())
|
||||
return nullptr;
|
||||
return &(i->second);
|
||||
}
|
||||
|
||||
ZT_INLINE const V *get(const K &key) const noexcept
|
||||
{
|
||||
typename Map::const_iterator i(this->find(key));
|
||||
if (i == this->end())
|
||||
return nullptr;
|
||||
return &(i->second);
|
||||
}
|
||||
|
||||
ZT_INLINE void set(const K &key,const V &value)
|
||||
{
|
||||
this->emplace(key,value);
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
} // ZeroTier
|
||||
|
||||
#endif
|
|
@ -159,8 +159,8 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
|
|||
// 3/5 of the credential types have identical addCredential() code
|
||||
template<typename C>
|
||||
static ZT_INLINE Membership::AddCredentialResult _addCredImpl(
|
||||
FlatMap<uint32_t,C> &remoteCreds,
|
||||
const FlatMap<uint64_t,int64_t> &revocations,
|
||||
Map<uint32_t,C> &remoteCreds,
|
||||
const Map<uint64_t,int64_t> &revocations,
|
||||
const RuntimeEnvironment *const RR,
|
||||
void *const tPtr,
|
||||
const Identity &sourcePeerIdentity,
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
|
||||
#include "Constants.hpp"
|
||||
#include "Credential.hpp"
|
||||
#include "FlatMap.hpp"
|
||||
#include "Map.hpp"
|
||||
#include "CertificateOfMembership.hpp"
|
||||
#include "Capability.hpp"
|
||||
#include "Tag.hpp"
|
||||
|
@ -106,7 +106,7 @@ public:
|
|||
{
|
||||
if (_isUnspoofableAddress(nconf,r))
|
||||
return true;
|
||||
for(FlatMap< uint32_t,CertificateOfOwnership >::const_iterator i(_remoteCoos.begin());i!=_remoteCoos.end();++i) {
|
||||
for(Map< uint32_t,CertificateOfOwnership >::const_iterator i(_remoteCoos.begin());i!=_remoteCoos.end();++i) {
|
||||
if (_isCredentialTimestampValid(nconf,i->second)&&(i->second.owns(r)))
|
||||
return true;
|
||||
}
|
||||
|
@ -176,9 +176,9 @@ private:
|
|||
}
|
||||
|
||||
template<typename C>
|
||||
ZT_INLINE void _cleanCredImpl(const NetworkConfig &nconf,FlatMap<uint32_t,C> &remoteCreds)
|
||||
ZT_INLINE void _cleanCredImpl(const NetworkConfig &nconf,Map<uint32_t,C> &remoteCreds)
|
||||
{
|
||||
for(typename FlatMap<uint32_t,C>::iterator i(remoteCreds.begin());i!=remoteCreds.end();) {
|
||||
for(typename Map<uint32_t,C>::iterator i(remoteCreds.begin());i!=remoteCreds.end();) {
|
||||
if (!_isCredentialTimestampValid(nconf,i->second))
|
||||
remoteCreds.erase(i++);
|
||||
else ++i;
|
||||
|
@ -198,12 +198,12 @@ private:
|
|||
CertificateOfMembership _com;
|
||||
|
||||
// Revocations by credentialKey()
|
||||
FlatMap< uint64_t,int64_t > _revocations;
|
||||
Map< uint64_t,int64_t > _revocations;
|
||||
|
||||
// Remote credentials that we have received from this member (and that are valid)
|
||||
FlatMap< uint32_t,Tag > _remoteTags;
|
||||
FlatMap< uint32_t,Capability > _remoteCaps;
|
||||
FlatMap< uint32_t,CertificateOfOwnership > _remoteCoos;
|
||||
Map< uint32_t,Tag > _remoteTags;
|
||||
Map< uint32_t,Capability > _remoteCaps;
|
||||
Map< uint32_t,CertificateOfOwnership > _remoteCoos;
|
||||
|
||||
public:
|
||||
class CapabilityIterator
|
||||
|
@ -219,7 +219,7 @@ public:
|
|||
ZT_INLINE Capability *next() noexcept
|
||||
{
|
||||
while (_hti != _m._remoteCaps.end()) {
|
||||
FlatMap< uint32_t,Capability >::iterator i(_hti++);
|
||||
Map< uint32_t,Capability >::iterator i(_hti++);
|
||||
if (_m._isCredentialTimestampValid(_nconf,i->second))
|
||||
return &(i->second);
|
||||
}
|
||||
|
@ -227,7 +227,7 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
FlatMap< uint32_t,Capability >::iterator _hti;
|
||||
Map< uint32_t,Capability >::iterator _hti;
|
||||
Membership &_m;
|
||||
const NetworkConfig &_nconf;
|
||||
};
|
||||
|
|
|
@ -1099,7 +1099,7 @@ void Network::doPeriodicTasks(void *tPtr,const int64_t now)
|
|||
{
|
||||
Mutex::Lock l1(_memberships_l);
|
||||
|
||||
for(FlatMap<Address,Membership>::iterator i(_memberships.begin());i!=_memberships.end();++i)
|
||||
for(Map<Address,Membership>::iterator i(_memberships.begin());i!=_memberships.end();++i)
|
||||
i->second.clean(now,_config);
|
||||
|
||||
{
|
||||
|
@ -1128,12 +1128,12 @@ void Network::learnBridgeRoute(const MAC &mac,const Address &addr)
|
|||
|
||||
// Anti-DOS circuit breaker to prevent nodes from spamming us with absurd numbers of bridge routes
|
||||
while (_remoteBridgeRoutes.size() > ZT_MAX_BRIDGE_ROUTES) {
|
||||
FlatMap< Address,unsigned long > counts;
|
||||
Map< Address,unsigned long > counts;
|
||||
Address maxAddr;
|
||||
unsigned long maxCount = 0;
|
||||
|
||||
// Find the address responsible for the most entries
|
||||
for(FlatMap<MAC,Address>::iterator i(_remoteBridgeRoutes.begin());i!=_remoteBridgeRoutes.end();++i) {
|
||||
for(Map<MAC,Address>::iterator i(_remoteBridgeRoutes.begin());i!=_remoteBridgeRoutes.end();++i) {
|
||||
const unsigned long c = ++counts[i->second];
|
||||
if (c > maxCount) {
|
||||
maxCount = c;
|
||||
|
@ -1142,7 +1142,7 @@ void Network::learnBridgeRoute(const MAC &mac,const Address &addr)
|
|||
}
|
||||
|
||||
// Kill this address from our table, since it's most likely spamming us
|
||||
for(FlatMap<MAC,Address>::iterator i(_remoteBridgeRoutes.begin());i!=_remoteBridgeRoutes.end();) {
|
||||
for(Map<MAC,Address>::iterator i(_remoteBridgeRoutes.begin());i!=_remoteBridgeRoutes.end();) {
|
||||
if (i->second == maxAddr)
|
||||
_remoteBridgeRoutes.erase(i++);
|
||||
else ++i;
|
||||
|
@ -1529,7 +1529,7 @@ std::vector<MulticastGroup> Network::_allMulticastGroups() const
|
|||
std::vector<MulticastGroup> mgs;
|
||||
mgs.reserve(_myMulticastGroups.size() + _multicastGroupsBehindMe.size() + 1);
|
||||
mgs.insert(mgs.end(),_myMulticastGroups.begin(),_myMulticastGroups.end());
|
||||
for(FlatMap< MulticastGroup,uint64_t >::const_iterator i(_multicastGroupsBehindMe.begin());i!=_multicastGroupsBehindMe.end();++i)
|
||||
for(Map< MulticastGroup,uint64_t >::const_iterator i(_multicastGroupsBehindMe.begin());i!=_multicastGroupsBehindMe.end();++i)
|
||||
mgs.push_back(i->first);
|
||||
if ((_config)&&(_config.enableBroadcast()))
|
||||
mgs.push_back(Network::BROADCAST);
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
#include "Membership.hpp"
|
||||
#include "NetworkConfig.hpp"
|
||||
#include "CertificateOfMembership.hpp"
|
||||
#include "FlatMap.hpp"
|
||||
#include "Map.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <string>
|
||||
|
@ -326,7 +326,7 @@ public:
|
|||
ZT_INLINE void eachMember(F f)
|
||||
{
|
||||
Mutex::Lock ml(_memberships_l);
|
||||
for(FlatMap<Address,Membership>::iterator i(_memberships.begin());i!=_memberships.end();++i) {
|
||||
for(Map<Address,Membership>::iterator i(_memberships.begin());i!=_memberships.end();++i) {
|
||||
if (!f(i->first,i->second))
|
||||
break;
|
||||
}
|
||||
|
@ -353,8 +353,8 @@ private:
|
|||
bool _portInitialized;
|
||||
|
||||
std::vector< MulticastGroup > _myMulticastGroups; // multicast groups that we belong to (according to tap)
|
||||
FlatMap< MulticastGroup,uint64_t > _multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we last saw them (if we are a bridge)
|
||||
FlatMap< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
|
||||
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)
|
||||
|
||||
NetworkConfig _config;
|
||||
std::atomic<int64_t> _lastConfigUpdate;
|
||||
|
@ -377,7 +377,7 @@ private:
|
|||
NETCONF_FAILURE_INIT_FAILED
|
||||
} _netconfFailure;
|
||||
|
||||
FlatMap<Address,Membership> _memberships;
|
||||
Map<Address,Membership> _memberships;
|
||||
|
||||
Mutex _myMulticastGroups_l;
|
||||
Mutex _remoteBridgeRoutes_l;
|
||||
|
|
|
@ -268,7 +268,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tPtr, int64_t now, volatile int
|
|||
_lastHousekeepingRun = now;
|
||||
{
|
||||
RWMutex::RLock l(_networks_m);
|
||||
for(FlatMap< uint64_t,SharedPtr<Network> >::const_iterator i(_networks.begin());i!=_networks.end();++i)
|
||||
for(Map< uint64_t,SharedPtr<Network> >::const_iterator i(_networks.begin());i!=_networks.end();++i)
|
||||
i->second->doPeriodicTasks(tPtr,now);
|
||||
}
|
||||
}
|
||||
|
@ -281,7 +281,7 @@ ZT_ResultCode Node::processBackgroundTasks(void *tPtr, int64_t now, volatile int
|
|||
// or trust nodes without doing an extra cert check.
|
||||
{
|
||||
_localControllerAuthorizations_m.lock();
|
||||
for(FlatMap<_LocalControllerAuth,int64_t>::iterator i(_localControllerAuthorizations.begin());i!=_localControllerAuthorizations.end();) {
|
||||
for(Map<_LocalControllerAuth,int64_t>::iterator i(_localControllerAuthorizations.begin());i!=_localControllerAuthorizations.end();) {
|
||||
if ((i->second - now) > (ZT_NETWORK_AUTOCONF_DELAY * 3))
|
||||
_localControllerAuthorizations.erase(i++);
|
||||
else ++i;
|
||||
|
@ -353,7 +353,7 @@ ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr)
|
|||
ZT_VirtualNetworkConfig ctmp;
|
||||
|
||||
_networks_m.lock();
|
||||
FlatMap< uint64_t,SharedPtr<Network> >::iterator nwi(_networks.find(nwid));
|
||||
Map< uint64_t,SharedPtr<Network> >::iterator nwi(_networks.find(nwid));
|
||||
if (nwi == _networks.end()) {
|
||||
_networks_m.unlock();
|
||||
return ZT_RESULT_OK;
|
||||
|
@ -507,7 +507,7 @@ ZT_VirtualNetworkList *Node::networks() const
|
|||
nl->networks = (ZT_VirtualNetworkConfig *)(buf + sizeof(ZT_VirtualNetworkList));
|
||||
|
||||
nl->networkCount = 0;
|
||||
for(FlatMap< uint64_t,SharedPtr<Network> >::const_iterator i(_networks.begin());i!=_networks.end();++i)
|
||||
for(Map< uint64_t,SharedPtr<Network> >::const_iterator i(_networks.begin());i!=_networks.end();++i)
|
||||
i->second->externalConfig(&(nl->networks[nl->networkCount++]));
|
||||
|
||||
return nl;
|
||||
|
@ -596,7 +596,7 @@ bool Node::shouldUsePathForZeroTierTraffic(void *tPtr,const Identity &id,const i
|
|||
{
|
||||
{
|
||||
RWMutex::RLock l(_networks_m);
|
||||
for (FlatMap< uint64_t,SharedPtr<Network> >::iterator i(_networks.begin()); i != _networks.end(); ++i) {
|
||||
for (Map< uint64_t,SharedPtr<Network> >::iterator i(_networks.begin()); i != _networks.end(); ++i) {
|
||||
for (unsigned int k = 0,j = i->second->config().staticIpCount; k < j; ++k) {
|
||||
if (i->second->config().staticIps[k].containsAddress(remoteAddress))
|
||||
return false;
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "Salsa20.hpp"
|
||||
#include "NetworkController.hpp"
|
||||
#include "Buf.hpp"
|
||||
#include "FlatMap.hpp"
|
||||
#include "Map.hpp"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
|
@ -361,13 +361,14 @@ private:
|
|||
ZT_INLINE unsigned long hashCode() const noexcept { return (unsigned long)(nwid + address); }
|
||||
ZT_INLINE bool operator==(const _LocalControllerAuth &a) const noexcept { return ((a.nwid == nwid) && (a.address == address)); }
|
||||
ZT_INLINE bool operator!=(const _LocalControllerAuth &a) const noexcept { return ((a.nwid != nwid) || (a.address != address)); }
|
||||
ZT_INLINE bool operator<(const _LocalControllerAuth &a) const noexcept { return ((a.nwid < nwid) || ((a.nwid == nwid)&&(a.address < address))); }
|
||||
};
|
||||
FlatMap<_LocalControllerAuth,int64_t> _localControllerAuthorizations;
|
||||
Map<_LocalControllerAuth,int64_t> _localControllerAuthorizations;
|
||||
Mutex _localControllerAuthorizations_m;
|
||||
|
||||
// Networks are stored in a flat hash table that is resized on any network ID collision. This makes
|
||||
// network lookup by network ID a few bitwise ops and an array index.
|
||||
FlatMap< uint64_t,SharedPtr<Network> > _networks;
|
||||
Map< uint64_t,SharedPtr<Network> > _networks;
|
||||
RWMutex _networks_m;
|
||||
|
||||
// These are local interface addresses that have been configured via the API
|
||||
|
|
|
@ -69,7 +69,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(FlatMap<PhySurfaceKey,PhySurfaceEntry>::iterator i(_phy.begin());i!=_phy.end();) {
|
||||
for(Map<PhySurfaceKey,PhySurfaceEntry>::iterator i(_phy.begin());i!=_phy.end();) {
|
||||
if ((i->first.scope == scope)&&(i->first.reporterPhysicalAddress != reporterPhysicalAddress))
|
||||
_phy.erase(i++);
|
||||
else ++i;
|
||||
|
@ -91,7 +91,7 @@ void SelfAwareness::iam(void *tPtr,const Identity &reporter,const int64_t receiv
|
|||
void SelfAwareness::clean(int64_t now)
|
||||
{
|
||||
Mutex::Lock l(_phy_l);
|
||||
for(FlatMap<PhySurfaceKey,PhySurfaceEntry>::iterator i(_phy.begin());i!=_phy.end();) {
|
||||
for(Map<PhySurfaceKey,PhySurfaceEntry>::iterator i(_phy.begin());i!=_phy.end();) {
|
||||
if ((now - i->second.ts) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT)
|
||||
_phy.erase(i++);
|
||||
else ++i;
|
||||
|
@ -101,17 +101,17 @@ void SelfAwareness::clean(int64_t now)
|
|||
std::multimap<unsigned long,InetAddress> SelfAwareness::externalAddresses(const int64_t now) const
|
||||
{
|
||||
std::multimap<unsigned long,InetAddress> r;
|
||||
FlatMap<InetAddress,unsigned long,256> counts;
|
||||
Map<InetAddress,unsigned long> counts;
|
||||
|
||||
{
|
||||
Mutex::Lock l(_phy_l);
|
||||
for(FlatMap<PhySurfaceKey,PhySurfaceEntry>::const_iterator i(_phy.begin());i!=_phy.end();++i) {
|
||||
for(Map<PhySurfaceKey,PhySurfaceEntry>::const_iterator i(_phy.begin());i!=_phy.end();++i) {
|
||||
if ((now - i->second.ts) < ZT_SELFAWARENESS_ENTRY_TIMEOUT)
|
||||
++counts[i->second.mySurface];
|
||||
}
|
||||
}
|
||||
|
||||
for(FlatMap<InetAddress,unsigned long,256>::iterator i(counts.begin());i!=counts.end();++i)
|
||||
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;
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
|
||||
#include "Constants.hpp"
|
||||
#include "InetAddress.hpp"
|
||||
#include "FlatMap.hpp"
|
||||
#include "Map.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "Mutex.hpp"
|
||||
|
||||
|
@ -72,13 +72,30 @@ private:
|
|||
InetAddress reporterPhysicalAddress;
|
||||
InetAddress::IpScope scope;
|
||||
|
||||
ZT_INLINE PhySurfaceKey() {}
|
||||
ZT_INLINE PhySurfaceKey(const Address &r,const int64_t rol,const InetAddress &ra,InetAddress::IpScope s) : reporter(r),receivedOnLocalSocket(rol),reporterPhysicalAddress(ra),scope(s) {}
|
||||
ZT_INLINE PhySurfaceKey() noexcept {}
|
||||
ZT_INLINE PhySurfaceKey(const Address &r,const int64_t rol,const InetAddress &ra,InetAddress::IpScope s) noexcept : reporter(r),receivedOnLocalSocket(rol),reporterPhysicalAddress(ra),scope(s) {}
|
||||
|
||||
ZT_INLINE unsigned long hashCode() const { return ((unsigned long)reporter.toInt() + (unsigned long)receivedOnLocalSocket + (unsigned long)scope); }
|
||||
ZT_INLINE unsigned long hashCode() const noexcept { return ((unsigned long)reporter.toInt() + (unsigned long)receivedOnLocalSocket + (unsigned long)scope); }
|
||||
|
||||
ZT_INLINE bool operator==(const PhySurfaceKey &k) const { return ((reporter == k.reporter) && (receivedOnLocalSocket == k.receivedOnLocalSocket) && (reporterPhysicalAddress == k.reporterPhysicalAddress) && (scope == k.scope)); }
|
||||
ZT_INLINE bool operator!=(const PhySurfaceKey &k) const { return (!(*this == k)); }
|
||||
ZT_INLINE bool operator==(const PhySurfaceKey &k) const noexcept { return ((reporter == k.reporter) && (receivedOnLocalSocket == k.receivedOnLocalSocket) && (reporterPhysicalAddress == k.reporterPhysicalAddress) && (scope == k.scope)); }
|
||||
ZT_INLINE bool operator!=(const PhySurfaceKey &k) const noexcept { return (!(*this == k)); }
|
||||
ZT_INLINE bool operator<(const PhySurfaceKey &k) const noexcept
|
||||
{
|
||||
if (reporter < k.reporter) {
|
||||
return true;
|
||||
} else if (reporter == k.reporter) {
|
||||
if (receivedOnLocalSocket < k.receivedOnLocalSocket) {
|
||||
return true;
|
||||
} else if (receivedOnLocalSocket == k.receivedOnLocalSocket) {
|
||||
if (reporterPhysicalAddress < k.reporterPhysicalAddress) {
|
||||
return true;
|
||||
} else if (reporterPhysicalAddress == k.reporterPhysicalAddress) {
|
||||
return scope < k.scope;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
struct PhySurfaceEntry
|
||||
|
@ -87,12 +104,12 @@ private:
|
|||
uint64_t ts;
|
||||
bool trusted;
|
||||
|
||||
ZT_INLINE PhySurfaceEntry() : mySurface(),ts(0),trusted(false) {}
|
||||
ZT_INLINE PhySurfaceEntry(const InetAddress &a,const uint64_t t) : mySurface(a),ts(t),trusted(false) {}
|
||||
ZT_INLINE PhySurfaceEntry() noexcept : mySurface(),ts(0),trusted(false) {}
|
||||
ZT_INLINE PhySurfaceEntry(const InetAddress &a,const uint64_t t) noexcept : mySurface(a),ts(t),trusted(false) {}
|
||||
};
|
||||
|
||||
const RuntimeEnvironment *RR;
|
||||
FlatMap< PhySurfaceKey,PhySurfaceEntry > _phy;
|
||||
Map< PhySurfaceKey,PhySurfaceEntry > _phy;
|
||||
Mutex _phy_l;
|
||||
};
|
||||
|
||||
|
|
|
@ -25,6 +25,10 @@ namespace ZeroTier {
|
|||
* Speck does not specify a mandatory endian-ness. This implementation is
|
||||
* little-endian for higher performance on the majority of platforms.
|
||||
*
|
||||
* This is only used as part of the work function for V1 identity generation
|
||||
* and for the built-in secure random source on systems that lack AES
|
||||
* hardware acceleration.
|
||||
*
|
||||
* @tparam R Number of rounds (default: 32)
|
||||
*/
|
||||
template<int R = 32>
|
||||
|
@ -96,7 +100,10 @@ public:
|
|||
}
|
||||
|
||||
/**
|
||||
* Encrypt 512 bits in parallel with the same key
|
||||
* Encrypt 512 bits in parallel with the same key.
|
||||
*
|
||||
* Parallel in this case assumes instruction level parallelism, but even without that
|
||||
* it may be faster due to cache/memory effects.
|
||||
*/
|
||||
ZT_INLINE void encryptXYXYXYXY(uint64_t &x0,uint64_t &y0,uint64_t &x1,uint64_t &y1,uint64_t &x2,uint64_t &y2,uint64_t &x3,uint64_t &y3) const noexcept
|
||||
{
|
||||
|
|
|
@ -38,7 +38,7 @@
|
|||
#include "SHA512.hpp"
|
||||
#include "Defragmenter.hpp"
|
||||
#include "Fingerprint.hpp"
|
||||
#include "FlatMap.hpp"
|
||||
#include "Map.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
|
@ -176,7 +176,7 @@ static const C25519TestVector C25519_TEST_VECTORS[ZT_NUM_C25519_TEST_VECTORS] =
|
|||
};
|
||||
|
||||
#define IDENTITY_V0_KNOWN_GOOD_0 "8e4df28b72:0:ac3d46abe0c21f3cfe7a6c8d6a85cfcffcb82fbd55af6a4d6350657c68200843fa2e16f9418bbd9702cae365f2af5fb4c420908b803a681d4daef6114d78a2d7:bd8dd6e4ce7022d2f812797a80c6ee8ad180dc4ebf301dec8b06d1be08832bddd63a2f1cfa7b2c504474c75bdc8898ba476ef92e8e2d0509f8441985171ff16e"
|
||||
#define IDENTITY_V1_KNOWN_GOOD_0 "8013cb9738:1:avsyitc474r2ylspwjkjvlermiiouaxy3bzzlqtcvafo2gv3abpeyov2zjfyx4vbkxghcoidpjidszt2ibsn4nmmvtpj42clzsxkyt5dajljk2i3x56picaeapayrv5xvd6x6ucgzvei7773xnoj6tyxwcjvqwbhz3joxeb74kdrfq2247hm7ly:54cckqx5fmd54zkmxt6lz2bxn2elws2ju2kv44cqpy7b22n5dlz256iz7j44jc4wyqj4mppyhknbayf2iulu7g4mysgeee5zrtp4zfwqtjnqkn2xpemap5cfm33kldc5kpukg33nqaizcgvekobj6omt3uwro5xboopvgiwdejwmgmpfevja"
|
||||
#define IDENTITY_V1_KNOWN_GOOD_0 "2d48f7a238:1:gltupn4yrt226o3vebl7m7m5hpndhvfz66nzx6gwgtgbsgs5xr7dpz5aiv636zijrxayuu2ydpff4zgho7o6gpvx62njwkavqordxcceajs2fif4y2ytofpyr25mmxmanbf4fmdiitiq2b53nmx4ckjcmtyqrkqye2jkdainmkqbtil3dhyuiwa:xg73bkrxptymo7kyyd6efu2o7ziemyu3lpgtip53ejsqukt6l2gebq5uofzt6cd2455st5iwrdgc2ft3twkdzrkunu6x5imdz6jt27qopsvqpdijx5cqgukpjxrtyx73j42socym5pi5hy2ir5yma7by4gmtjgvvu3sxbb3qv2yuicykyz2q"
|
||||
|
||||
// --------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -466,34 +466,41 @@ extern "C" const char *ZTT_general()
|
|||
}
|
||||
|
||||
{
|
||||
ZT_T_PRINTF("[general] Testing FlatMap... ");
|
||||
FlatMap<uint64_t,uint64_t> tm;
|
||||
for(uint64_t i=0;i<10000;++i)
|
||||
ZT_T_PRINTF("[general] Testing Map... ");
|
||||
Map<uint64_t,uint64_t> tm;
|
||||
for(uint64_t i=0;i<100000;++i)
|
||||
tm.set(i,i);
|
||||
for(uint64_t i=0;i<10000;++i) {
|
||||
for(uint64_t i=0;i<100000;++i) {
|
||||
uint64_t *v = tm.get(i);
|
||||
if ((!v)||(*v != i)) {
|
||||
ZT_T_PRINTF("FAILED (get() failed)" ZT_EOL_S);
|
||||
return "FlatMap::get() failed";
|
||||
return "Map::get() failed";
|
||||
}
|
||||
}
|
||||
for(FlatMap<uint64_t,uint64_t>::iterator i(tm.begin());i!=tm.end();) {
|
||||
for(Map<uint64_t,uint64_t>::iterator i(tm.begin());i!=tm.end();) {
|
||||
if ((i->first & 1U) == 0)
|
||||
tm.erase(i++);
|
||||
else ++i;
|
||||
}
|
||||
if (tm.size() != 5000) {
|
||||
if (tm.size() != 50000) {
|
||||
ZT_T_PRINTF("FAILED (erase() failed (1))" ZT_EOL_S);
|
||||
return "FlatMap::erase() failed (1)";
|
||||
return "Map::erase() failed (1)";
|
||||
}
|
||||
for(uint64_t i=0;i<10000;++i) {
|
||||
for(uint64_t i=0;i<100000;++i) {
|
||||
uint64_t *v = tm.get(i);
|
||||
if (((i & 1U) == 0)&&(v)) {
|
||||
ZT_T_PRINTF("FAILED (erase() failed (2))" ZT_EOL_S);
|
||||
return "FlatMap::erase() failed (2)";
|
||||
if ((i & 1U) == 0) {
|
||||
if (v) {
|
||||
ZT_T_PRINTF("FAILED (erase() failed (2))" ZT_EOL_S);
|
||||
return "Map::erase() failed (2)";
|
||||
}
|
||||
} else {
|
||||
if (!v) {
|
||||
ZT_T_PRINTF("FAILED (erase() failed (3))" ZT_EOL_S);
|
||||
return "Map::erase() failed (3)";
|
||||
}
|
||||
}
|
||||
}
|
||||
ZT_T_PRINTF("OK (hash size: %lu)" ZT_EOL_S,tm.hashSize());
|
||||
ZT_T_PRINTF("OK" ZT_EOL_S);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -99,7 +99,7 @@ void Topology::getAllPeers(std::vector< SharedPtr<Peer> > &allPeers) const
|
|||
RWMutex::RLock l(_peers_l);
|
||||
allPeers.clear();
|
||||
allPeers.reserve(_peers.size());
|
||||
for(FlatMap< Address,SharedPtr<Peer> >::const_iterator i(_peers.begin());i!=_peers.end();++i)
|
||||
for(Map< Address,SharedPtr<Peer> >::const_iterator i(_peers.begin());i!=_peers.end();++i)
|
||||
allPeers.push_back(i->second);
|
||||
}
|
||||
|
||||
|
@ -198,7 +198,7 @@ void Topology::doPeriodicTasks(void *tPtr,const int64_t now)
|
|||
{
|
||||
{
|
||||
RWMutex::Lock l1(_peers_l);
|
||||
for(FlatMap< Address,SharedPtr<Peer> >::iterator i(_peers.begin());i!=_peers.end();) {
|
||||
for(Map< Address,SharedPtr<Peer> >::iterator i(_peers.begin());i!=_peers.end();) {
|
||||
if ( (!i->second->alive(now)) && (_roots.count(i->second->identity()) == 0) ) {
|
||||
i->second->save(tPtr);
|
||||
_peersByIncomingProbe.erase(i->second->incomingProbe());
|
||||
|
@ -209,7 +209,7 @@ void Topology::doPeriodicTasks(void *tPtr,const int64_t now)
|
|||
}
|
||||
{
|
||||
RWMutex::Lock l1(_paths_l);
|
||||
for(FlatMap< uint64_t,SharedPtr<Path> >::iterator i(_paths.begin());i!=_paths.end();) {
|
||||
for(Map< uint64_t,SharedPtr<Path> >::iterator i(_paths.begin());i!=_paths.end();) {
|
||||
if ((i->second.references() <= 1)&&(!i->second->alive(now)))
|
||||
_paths.erase(i++);
|
||||
else ++i;
|
||||
|
@ -220,7 +220,7 @@ void Topology::doPeriodicTasks(void *tPtr,const int64_t now)
|
|||
void Topology::saveAll(void *tPtr)
|
||||
{
|
||||
RWMutex::RLock l(_peers_l);
|
||||
for(FlatMap< Address,SharedPtr<Peer> >::iterator i(_peers.begin());i!=_peers.end();++i)
|
||||
for(Map< Address,SharedPtr<Peer> >::iterator i(_peers.begin());i!=_peers.end();++i)
|
||||
i->second->save(tPtr);
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
#include "SharedPtr.hpp"
|
||||
#include "ScopedPtr.hpp"
|
||||
#include "Fingerprint.hpp"
|
||||
#include "FlatMap.hpp"
|
||||
#include "Map.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
|
@ -127,7 +127,7 @@ public:
|
|||
*/
|
||||
ZT_INLINE SharedPtr<Path> path(const int64_t l,const InetAddress &r)
|
||||
{
|
||||
const uint64_t k = _pathHash(l,r);
|
||||
const uint64_t k = _getPathKey(l,r);
|
||||
{
|
||||
RWMutex::RLock lck(_paths_l);
|
||||
SharedPtr<Path> *const p = _paths.get(k);
|
||||
|
@ -179,7 +179,7 @@ public:
|
|||
ZT_INLINE void eachPeer(F f) const
|
||||
{
|
||||
RWMutex::RLock l(_peers_l);
|
||||
for(FlatMap< Address,SharedPtr<Peer> >::const_iterator i(_peers.begin());i!=_peers.end();++i)
|
||||
for(Map< Address,SharedPtr<Peer> >::const_iterator i(_peers.begin());i!=_peers.end();++i)
|
||||
f(i->second);
|
||||
}
|
||||
|
||||
|
@ -204,7 +204,7 @@ public:
|
|||
std::sort(rootPeerPtrs.begin(),rootPeerPtrs.end());
|
||||
|
||||
try {
|
||||
for(FlatMap< Address,SharedPtr<Peer> >::const_iterator i(_peers.begin());i!=_peers.end();++i)
|
||||
for(Map< Address,SharedPtr<Peer> >::const_iterator i(_peers.begin());i!=_peers.end();++i)
|
||||
f(i->second,std::binary_search(rootPeerPtrs.begin(),rootPeerPtrs.end(),(uintptr_t)i->second.ptr()));
|
||||
} catch ( ... ) {} // should not throw
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ public:
|
|||
ZT_INLINE void eachPath(F f) const
|
||||
{
|
||||
RWMutex::RLock l(_paths_l);
|
||||
for(FlatMap< uint64_t,SharedPtr<Path> >::const_iterator i(_paths.begin());i!=_paths.end();++i)
|
||||
for(Map< uint64_t,SharedPtr<Path> >::const_iterator i(_paths.begin());i!=_paths.end();++i)
|
||||
f(i->second);
|
||||
}
|
||||
|
||||
|
@ -324,11 +324,11 @@ private:
|
|||
// This is a secure random integer created at startup to salt the calculation of path hash map keys
|
||||
static const uint64_t s_pathHashSalt;
|
||||
|
||||
// Get a hash key for looking up paths by their local port and destination address
|
||||
ZT_INLINE uint64_t _pathHash(int64_t l,const InetAddress &r) const
|
||||
// This gets an integer key from an InetAddress for looking up paths.
|
||||
ZT_INLINE uint64_t _getPathKey(int64_t l,const InetAddress &r) const
|
||||
{
|
||||
if (r.family() == AF_INET) {
|
||||
return Utils::hash64(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 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;
|
||||
} else if (r.family() == AF_INET6) {
|
||||
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||
uint64_t h = s_pathHashSalt;
|
||||
|
@ -338,7 +338,7 @@ private:
|
|||
h ^= (h >> 6U);
|
||||
}
|
||||
#else
|
||||
uint64_t h = Utils::hash64(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]));
|
||||
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]);
|
||||
#endif
|
||||
return h + (uint64_t)Utils::ntoh(reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_port) + (uint64_t)l;
|
||||
} else {
|
||||
|
@ -354,10 +354,10 @@ private:
|
|||
std::pair< InetAddress,ZT_PhysicalPathConfiguration > _physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS];
|
||||
unsigned int _numConfiguredPhysicalPaths;
|
||||
|
||||
FlatMap< Address,SharedPtr<Peer> > _peers;
|
||||
FlatMap< uint64_t,SharedPtr<Peer> > _peersByIncomingProbe;
|
||||
FlatMap< Fingerprint,SharedPtr<Peer> > _peersByIdentityHash;
|
||||
FlatMap< uint64_t,SharedPtr<Path> > _paths;
|
||||
Map< Address,SharedPtr<Peer> > _peers;
|
||||
Map< uint64_t,SharedPtr<Peer> > _peersByIncomingProbe;
|
||||
Map< Fingerprint,SharedPtr<Peer> > _peersByIdentityHash;
|
||||
Map< uint64_t,SharedPtr<Path> > _paths;
|
||||
std::set< Identity > _roots; // locked by _peers_l
|
||||
std::vector< SharedPtr<Peer> > _rootPeers; // locked by _peers_l
|
||||
};
|
||||
|
|
102
node/Utils.cpp
102
node/Utils.cpp
|
@ -19,6 +19,7 @@
|
|||
#include "Mutex.hpp"
|
||||
#include "AES.hpp"
|
||||
#include "SHA512.hpp"
|
||||
#include "Speck128.hpp"
|
||||
|
||||
#ifdef __UNIX_LIKE__
|
||||
#include <unistd.h>
|
||||
|
@ -59,6 +60,7 @@ const CPUIDRegisters CPUID;
|
|||
|
||||
const uint64_t ZERO256[4] = { 0,0,0,0 };
|
||||
const char HEXCHARS[16] = { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
|
||||
const uint64_t s_mapNonce = getSecureRandomU64();
|
||||
|
||||
bool secureEq(const void *a,const void *b,unsigned int len) noexcept
|
||||
{
|
||||
|
@ -223,32 +225,40 @@ unsigned int unhex(const char *h,unsigned int hlen,void *buf,unsigned int buflen
|
|||
return l;
|
||||
}
|
||||
|
||||
void getSecureRandom(void *buf,unsigned int bytes) noexcept
|
||||
#define ZT_GETSECURERANDOM_STATE_SIZE 64
|
||||
#define ZT_GETSECURERANDOM_BUF_SIZE 4096
|
||||
|
||||
void getSecureRandom(void *const buf,const unsigned int bytes) noexcept
|
||||
{
|
||||
static Mutex globalLock;
|
||||
static bool initialized = false;
|
||||
static uint64_t randomState[16]; // secret state
|
||||
static uint64_t randomBuf[8192]; // next batch of random bytes
|
||||
static uint64_t randomState[ZT_GETSECURERANDOM_STATE_SIZE]; // secret state
|
||||
static uint64_t randomBuf[ZT_GETSECURERANDOM_BUF_SIZE]; // next batch of random bytes
|
||||
static unsigned long randomPtr = sizeof(randomBuf); // refresh on first iteration
|
||||
|
||||
// This secure random function gets entropy from the system random source (e.g. /dev/urandom),
|
||||
// CPU random instructions if present, and other sources and uses them to initialize a SHA/AES
|
||||
// based CSPRNG with a large state. System random sources are not used directly to mitigate
|
||||
// against cases where the system random source is broken in some way, which does happen from
|
||||
// time to time.
|
||||
|
||||
Mutex::Lock gl(globalLock);
|
||||
|
||||
// This could be a lot faster if we're not going to need a new block.
|
||||
if ((randomPtr + (unsigned long)bytes) <= sizeof(randomBuf)) {
|
||||
Utils::copy(buf,reinterpret_cast<uint8_t *>(randomBuf) + randomPtr,bytes);
|
||||
randomPtr += bytes;
|
||||
return;
|
||||
}
|
||||
|
||||
for(unsigned int i=0;i<bytes;++i) {
|
||||
if (randomPtr >= sizeof(randomBuf)) {
|
||||
// Generate a new block of random data if we're at the end of the current block.
|
||||
// Note that randomPtr is a byte pointer not a word pointer so we compare with sizeof.
|
||||
if (randomPtr >= (unsigned long)sizeof(randomBuf)) {
|
||||
randomPtr = 0;
|
||||
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
|
||||
// Fill both randomState and randomBuf from system random source. Failure here
|
||||
// is fatal to the running application and indicates a serious system problem.
|
||||
// This is some of the only OS-specific code in the core.
|
||||
Utils::memoryLock(randomState,sizeof(randomState));
|
||||
Utils::memoryLock(randomBuf,sizeof(randomBuf));
|
||||
|
||||
// Fill randomState with entropy from the system. If this doesn't work this is a hard fail.
|
||||
Utils::zero<sizeof(randomState)>(randomState);
|
||||
#ifdef __WINDOWS__
|
||||
HCRYPTPROV cryptProvider = NULL;
|
||||
if (!CryptAcquireContextA(&cryptProvider,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) {
|
||||
|
@ -259,10 +269,6 @@ void getSecureRandom(void *buf,unsigned int bytes) noexcept
|
|||
fprintf(stderr,"FATAL: Utils::getSecureRandom() CryptGenRandom failed!\r\n");
|
||||
exit(1);
|
||||
}
|
||||
if (!CryptGenRandom(cryptProvider,(DWORD)sizeof(randomBuf),(BYTE *)randomBuf)) {
|
||||
fprintf(stderr,"FATAL: Utils::getSecureRandom() CryptGenRandom failed!\r\n");
|
||||
exit(1);
|
||||
}
|
||||
CryptReleaseContext(cryptProvider,0);
|
||||
#else
|
||||
int devURandomFd = ::open("/dev/urandom",O_RDONLY);
|
||||
|
@ -275,25 +281,20 @@ void getSecureRandom(void *buf,unsigned int bytes) noexcept
|
|||
fprintf(stderr,"FATAL: Utils::getSecureRandom() unable to read from /dev/urandom\n");
|
||||
exit(1);
|
||||
}
|
||||
if ((long)::read(devURandomFd,randomBuf,sizeof(randomBuf)) != (long)sizeof(randomBuf)) {
|
||||
::close(devURandomFd);
|
||||
fprintf(stderr,"FATAL: Utils::getSecureRandom() unable to read from /dev/urandom\n");
|
||||
exit(1);
|
||||
}
|
||||
close(devURandomFd);
|
||||
#endif
|
||||
|
||||
// Mix in additional entropy from time, the address of 'buf', rdrand if present, etc.
|
||||
randomState[0] ^= (uint64_t)time(nullptr);
|
||||
randomState[1] ^= (uint64_t)((uintptr_t)buf);
|
||||
// Mix in additional entropy from time, the address of 'buf', CPU RDRAND if present, etc.
|
||||
randomState[0] += (uint64_t)time(nullptr);
|
||||
randomState[1] += (uint64_t)((uintptr_t)buf);
|
||||
#ifdef __UNIX_LIKE__
|
||||
randomState[2] ^= (uint64_t)getpid();
|
||||
randomState[3] ^= (uint64_t)getppid();
|
||||
randomState[2] += (uint64_t)getpid();
|
||||
randomState[3] += (uint64_t)getppid();
|
||||
#endif
|
||||
#ifdef ZT_ARCH_X64
|
||||
if (CPUID.rdrand) {
|
||||
uint64_t tmp = 0;
|
||||
for(int k=0;k<16;++k) {
|
||||
for(int k=0;k<ZT_GETSECURERANDOM_STATE_SIZE;++k) {
|
||||
_rdrand64_step((unsigned long long *)&tmp);
|
||||
randomState[k] ^= tmp;
|
||||
}
|
||||
|
@ -301,25 +302,31 @@ void getSecureRandom(void *buf,unsigned int bytes) noexcept
|
|||
#endif
|
||||
}
|
||||
|
||||
// Generate a new randomBuf:
|
||||
//
|
||||
// (1) Generate next randomState by perturbing, hashing, and replacing the first 384 bits with the hash.
|
||||
// (2) Initialize AES using the first 256 bits of the new randomState as its key.
|
||||
// (3) Initialize a 128-bit counter field using the following 128 bits of randomState.
|
||||
// (4) Encrypt randomBuf with AES-CTR (machine-endian counter since spec conformance doesn't matter).
|
||||
// Perturb state, hash, and overwrite the first 64 bytes with this hash.
|
||||
++randomState[ZT_GETSECURERANDOM_STATE_SIZE-1];
|
||||
SHA512(randomState,randomState,sizeof(randomState));
|
||||
|
||||
++randomState[15];
|
||||
SHA384(randomState,randomState,sizeof(randomState));
|
||||
|
||||
AES aes(randomState);
|
||||
uint64_t ctr[2],tmp[2];
|
||||
ctr[0] = randomState[4];
|
||||
ctr[1] = randomState[5]; // AES key + CTR/nonce = part replaced each time by SHA384
|
||||
for(int k=0;k<8192;k+=2) {
|
||||
++ctr[0];
|
||||
aes.encrypt(ctr,tmp);
|
||||
randomBuf[k] ^= tmp[0];
|
||||
randomBuf[k+1] ^= tmp[1];
|
||||
// Use the part of the state that was overwritten with new state to key a
|
||||
// stream cipher and re-fill the buffer. Use AES if we're HW accel or use
|
||||
// Speck if not since it's way faster on tiny chips without AES units.
|
||||
if (AES::accelerated()) {
|
||||
AES aes(randomState);
|
||||
uint64_t ctr[2];
|
||||
ctr[0] = randomState[4];
|
||||
ctr[1] = randomState[5];
|
||||
for (int k = 0;k < ZT_GETSECURERANDOM_BUF_SIZE;k += 2) {
|
||||
++ctr[0];
|
||||
aes.encrypt(ctr,randomBuf + k);
|
||||
}
|
||||
} else {
|
||||
Speck128<> speck(randomState);
|
||||
uint64_t ctr[2];
|
||||
ctr[0] = randomState[4];
|
||||
ctr[1] = randomState[5];
|
||||
for (int k = 0;k < ZT_GETSECURERANDOM_BUF_SIZE;k += 2) {
|
||||
++ctr[0];
|
||||
speck.encrypt(ctr,randomBuf + k);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -336,7 +343,7 @@ uint64_t getSecureRandomU64() noexcept
|
|||
|
||||
int b32e(const uint8_t *data,int length,char *result,int bufSize) noexcept
|
||||
{
|
||||
if (length < 0 || length > (1 << 28)) {
|
||||
if (length < 0 || length > (1 << 28U)) {
|
||||
result[0] = (char)0;
|
||||
return -1;
|
||||
}
|
||||
|
@ -413,6 +420,7 @@ int b32d(const char *encoded,uint8_t *result,int bufSize) noexcept
|
|||
uint64_t random() noexcept
|
||||
{
|
||||
// https://en.wikipedia.org/wiki/Xorshift#xoshiro256**
|
||||
|
||||
static volatile uint64_t s_s0 = getSecureRandomU64();
|
||||
static volatile uint64_t s_s1 = getSecureRandomU64();
|
||||
static volatile uint64_t s_s2 = getSecureRandomU64();
|
||||
|
|
|
@ -68,6 +68,11 @@ extern const uint64_t ZERO256[4];
|
|||
*/
|
||||
extern const char HEXCHARS[16];
|
||||
|
||||
/**
|
||||
* A random integer generated at startup for Map's hash bucket calculation.
|
||||
*/
|
||||
extern const uint64_t s_mapNonce;
|
||||
|
||||
/**
|
||||
* Lock memory to prevent swapping out to secondary storage (if possible)
|
||||
*
|
||||
|
@ -228,7 +233,11 @@ int b32e(const uint8_t *data,int length,char *result,int bufSize) noexcept;
|
|||
int b32d(const char *encoded, uint8_t *result, int bufSize) noexcept;
|
||||
|
||||
/**
|
||||
* Get a non-cryptographic random integer
|
||||
* Get a non-cryptographic random integer.
|
||||
*
|
||||
* This should never be used for cryptographic use cases, not even for choosing
|
||||
* message nonce/IV values if they should not repeat. It should only be used when
|
||||
* a fast and potentially "dirty" random source is needed.
|
||||
*/
|
||||
uint64_t random() noexcept;
|
||||
|
||||
|
@ -246,7 +255,7 @@ uint64_t random() noexcept;
|
|||
bool scopy(char *dest,unsigned int len,const char *src) noexcept;
|
||||
|
||||
/**
|
||||
* Mix bits in a 64-bit integer (non-cryptographic)
|
||||
* Mix bits in a 64-bit integer (non-cryptographic, for hash tables)
|
||||
*
|
||||
* https://nullprogram.com/blog/2018/07/31/
|
||||
*
|
||||
|
@ -264,16 +273,20 @@ static ZT_INLINE uint64_t hash64(uint64_t x) noexcept
|
|||
}
|
||||
|
||||
/**
|
||||
* Mix bits in a 32-bit integer
|
||||
* Mix bits in a 32-bit integer (non-cryptographic, for hash tables)
|
||||
*
|
||||
* https://nullprogram.com/blog/2018/07/31/
|
||||
*
|
||||
* @param x Integer to mix
|
||||
* @return Hashed value
|
||||
*/
|
||||
static ZT_INLINE uint32_t hash32(uint32_t x) noexcept
|
||||
{
|
||||
x = ((x >> 16U) ^ x) * 0x45d9f3b;
|
||||
x = ((x >> 16U) ^ x) * 0x45d9f3b;
|
||||
x = (x >> 16U) ^ x;
|
||||
x ^= x >> 16U;
|
||||
x *= 0x7feb352dU;
|
||||
x ^= x >> 15U;
|
||||
x *= 0x846ca68bU;
|
||||
x ^= x >> 16U;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
@ -598,7 +611,7 @@ static ZT_INLINE void storeLittleEndian(void *const p,const I i) noexcept
|
|||
}
|
||||
|
||||
/**
|
||||
* Copy memory block whose size is known at compile time
|
||||
* Copy memory block whose size is known at compile time.
|
||||
*
|
||||
* @tparam L Size of memory
|
||||
* @param dest Destination memory
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
*/
|
||||
/****/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -24,7 +23,7 @@ static const uint8_t ARP_REQUEST_HEADER[8] = { 0x00,0x01,0x08,0x00,0x06,0x04,0x0
|
|||
static const uint8_t ARP_RESPONSE_HEADER[8] = { 0x00,0x01,0x08,0x00,0x06,0x04,0x00,0x02 };
|
||||
|
||||
Arp::Arp() :
|
||||
_cache(256),
|
||||
_cache(),
|
||||
_lastCleaned(OSUtils::now())
|
||||
{
|
||||
}
|
||||
|
@ -78,12 +77,10 @@ uint32_t Arp::processIncomingArp(const void *arp,unsigned int len,void *response
|
|||
|
||||
if ((now - _lastCleaned) >= ZT_ARP_EXPIRE) {
|
||||
_lastCleaned = now;
|
||||
Hashtable< uint32_t,_ArpEntry >::Iterator i(_cache);
|
||||
uint32_t *k = (uint32_t *)0;
|
||||
_ArpEntry *v = (_ArpEntry *)0;
|
||||
while (i.next(k,v)) {
|
||||
if ((!v->local)&&((now - v->lastResponseReceived) >= ZT_ARP_EXPIRE))
|
||||
_cache.erase(*k);
|
||||
for(Map< uint32_t,_ArpEntry >::iterator i(_cache.begin());i!=_cache.end();) {
|
||||
if ((!i->second.local)&&((now - i->second.lastResponseReceived) >= ZT_ARP_EXPIRE))
|
||||
_cache.erase(i++);
|
||||
else ++i;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
#include <vector>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
#include "../node/Hashtable.hpp"
|
||||
#include "../node/Map.hpp"
|
||||
#include "../node/MAC.hpp"
|
||||
|
||||
/**
|
||||
|
@ -135,7 +135,7 @@ private:
|
|||
bool local; // True if this is a local ARP entry
|
||||
};
|
||||
|
||||
Hashtable< uint32_t,_ArpEntry > _cache;
|
||||
Map< uint32_t,_ArpEntry > _cache;
|
||||
uint64_t _lastCleaned;
|
||||
};
|
||||
|
||||
|
|
|
@ -156,7 +156,7 @@ struct _neighbor_advertisement {
|
|||
};
|
||||
|
||||
NeighborDiscovery::NeighborDiscovery()
|
||||
: _cache(256)
|
||||
: _cache()
|
||||
, _lastCleaned(OSUtils::now())
|
||||
{}
|
||||
|
||||
|
@ -211,13 +211,12 @@ sockaddr_storage NeighborDiscovery::processIncomingND(const uint8_t *nd, unsigne
|
|||
|
||||
if ((now - _lastCleaned) >= ZT_ND_EXPIRE) {
|
||||
_lastCleaned = now;
|
||||
Hashtable<InetAddress, _NDEntry>::Iterator i(_cache);
|
||||
InetAddress *k = nullptr;
|
||||
_NDEntry *v = nullptr;
|
||||
while (i.next(k, v)) {
|
||||
if(!v->local && (now - v->lastResponseReceived) >= ZT_ND_EXPIRE) {
|
||||
_cache.erase(*k);
|
||||
}
|
||||
for(Map<InetAddress,_NDEntry>::iterator i(_cache.begin());i!=_cache.end();) {
|
||||
if(!i->second.local && (now - i->second.lastResponseReceived) >= ZT_ND_EXPIRE) {
|
||||
_cache.erase(i++);
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#ifndef ZT_NEIGHBORDISCOVERY_HPP
|
||||
#define ZT_NEIGHBORDISCOVERY_HPP
|
||||
|
||||
#include "../node/Hashtable.hpp"
|
||||
#include "../node/Map.hpp"
|
||||
#include "../node/MAC.hpp"
|
||||
#include "../node/InetAddress.hpp"
|
||||
|
||||
|
@ -58,7 +58,7 @@ private:
|
|||
bool local;
|
||||
};
|
||||
|
||||
Hashtable<InetAddress, _NDEntry> _cache;
|
||||
Map< InetAddress,_NDEntry > _cache;
|
||||
uint64_t _lastCleaned;
|
||||
};
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue