ZeroTier standard .clang-format -- switch to spaces, match indentation of Rust, mostly based on LLVM format.

This commit is contained in:
Adam Ierymenko 2021-04-26 08:55:28 -04:00
parent 2698dab696
commit 12e7546ebc
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
111 changed files with 31629 additions and 26070 deletions

View file

@ -57,7 +57,7 @@ SpacesInCStyleCastParentheses: 'false'
SpacesInContainerLiterals: 'true' SpacesInContainerLiterals: 'true'
SpacesInParentheses: 'false' SpacesInParentheses: 'false'
SpacesInSquareBrackets: 'false' SpacesInSquareBrackets: 'false'
UseTab: ForIndentation UseTab: 'false'
--- ---
Language: Cpp Language: Cpp

View file

@ -11,9 +11,10 @@
*/ */
/****/ /****/
#include "Constants.hpp"
#include "AES.hpp" #include "AES.hpp"
#include "Constants.hpp"
#ifdef __GNUC__ #ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wstrict-aliasing" #pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif #endif
@ -32,39 +33,48 @@ namespace ZeroTier {
namespace { namespace {
#define s_bmul32(N, x, y, rh, rl) \ #define s_bmul32(N, x, y, rh, rl) \
uint32_t x0t_##N = (x) & 0x11111111U; \ uint32_t x0t_##N = (x)&0x11111111U; \
uint32_t x1t_##N = (x) & 0x22222222U; \ uint32_t x1t_##N = (x)&0x22222222U; \
uint32_t x2t_##N = (x) & 0x44444444U; \ uint32_t x2t_##N = (x)&0x44444444U; \
uint32_t x3t_##N = (x) & 0x88888888U; \ uint32_t x3t_##N = (x)&0x88888888U; \
uint32_t y0t_##N = (y) & 0x11111111U; \ uint32_t y0t_##N = (y)&0x11111111U; \
uint32_t y1t_##N = (y) & 0x22222222U; \ uint32_t y1t_##N = (y)&0x22222222U; \
uint32_t y2t_##N = (y) & 0x44444444U; \ uint32_t y2t_##N = (y)&0x44444444U; \
uint32_t y3t_##N = (y) & 0x88888888U; \ uint32_t y3t_##N = (y)&0x88888888U; \
uint64_t z0t_##N = (((uint64_t)x0t_##N * y0t_##N) ^ ((uint64_t)x1t_##N * y3t_##N) ^ ((uint64_t)x2t_##N * y2t_##N) ^ ((uint64_t)x3t_##N * y1t_##N)) & 0x1111111111111111ULL; \ uint64_t z0t_##N = (((uint64_t)x0t_##N * y0t_##N) ^ ((uint64_t)x1t_##N * y3t_##N) ^ ((uint64_t)x2t_##N * y2t_##N) \
uint64_t z1t_##N = (((uint64_t)x0t_##N * y1t_##N) ^ ((uint64_t)x1t_##N * y0t_##N) ^ ((uint64_t)x2t_##N * y3t_##N) ^ ((uint64_t)x3t_##N * y2t_##N)) & 0x2222222222222222ULL; \ ^ ((uint64_t)x3t_##N * y1t_##N)) \
uint64_t z2t_##N = (((uint64_t)x0t_##N * y2t_##N) ^ ((uint64_t)x1t_##N * y1t_##N) ^ ((uint64_t)x2t_##N * y0t_##N) ^ ((uint64_t)x3t_##N * y3t_##N)) & 0x4444444444444444ULL; \ & 0x1111111111111111ULL; \
uint64_t z1t_##N = (((uint64_t)x0t_##N * y1t_##N) ^ ((uint64_t)x1t_##N * y0t_##N) ^ ((uint64_t)x2t_##N * y3t_##N) \
^ ((uint64_t)x3t_##N * y2t_##N)) \
& 0x2222222222222222ULL; \
uint64_t z2t_##N = (((uint64_t)x0t_##N * y2t_##N) ^ ((uint64_t)x1t_##N * y1t_##N) ^ ((uint64_t)x2t_##N * y0t_##N) \
^ ((uint64_t)x3t_##N * y3t_##N)) \
& 0x4444444444444444ULL; \
z0t_##N |= z1t_##N; \ z0t_##N |= z1t_##N; \
z2t_##N |= z0t_##N; \ z2t_##N |= z0t_##N; \
uint64_t zt_##N = z2t_##N | ((((uint64_t)x0t_##N * y3t_##N) ^ ((uint64_t)x1t_##N * y2t_##N) ^ ((uint64_t)x2t_##N * y1t_##N) ^ ((uint64_t)x3t_##N * y0t_##N)) & 0x8888888888888888ULL); \ uint64_t zt_##N = z2t_##N \
| ((((uint64_t)x0t_##N * y3t_##N) ^ ((uint64_t)x1t_##N * y2t_##N) \
^ ((uint64_t)x2t_##N * y1t_##N) ^ ((uint64_t)x3t_##N * y0t_##N)) \
& 0x8888888888888888ULL); \
(rh) = (uint32_t)(zt_##N >> 32U); \ (rh) = (uint32_t)(zt_##N >> 32U); \
(rl) = (uint32_t)zt_##N; (rl) = (uint32_t)zt_##N;
void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t &y0, uint64_t &y1) noexcept void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t& y0, uint64_t& y1) noexcept
{ {
uint32_t hhh = (uint32_t)(hh >> 32U); uint32_t hhh = (uint32_t)(hh >> 32U);
uint32_t hhl = (uint32_t)hh; uint32_t hhl = (uint32_t)hh;
uint32_t hlh = (uint32_t)(hl >> 32U); uint32_t hlh = (uint32_t)(hl >> 32U);
uint32_t hll = (uint32_t)hl; uint32_t hll = (uint32_t)hl;
uint32_t hhXlh = hhh ^hlh; uint32_t hhXlh = hhh ^ hlh;
uint32_t hhXll = hhl ^hll; uint32_t hhXll = hhl ^ hll;
uint64_t yl = Utils::ntoh(y0); uint64_t yl = Utils::ntoh(y0);
uint64_t yh = Utils::ntoh(y1); uint64_t yh = Utils::ntoh(y1);
uint32_t cilh = (uint32_t)(yh >> 32U); uint32_t cilh = (uint32_t)(yh >> 32U);
uint32_t cill = (uint32_t)yh; uint32_t cill = (uint32_t)yh;
uint32_t cihh = (uint32_t)(yl >> 32U); uint32_t cihh = (uint32_t)(yl >> 32U);
uint32_t cihl = (uint32_t)yl; uint32_t cihl = (uint32_t)yl;
uint32_t cihXlh = cihh ^cilh; uint32_t cihXlh = cihh ^ cilh;
uint32_t cihXll = cihl ^cill; uint32_t cihXll = cihl ^ cill;
uint32_t aah, aal, abh, abl, ach, acl; uint32_t aah, aal, abh, abl, ach, acl;
s_bmul32(M0, cihh, hhh, aah, aal); s_bmul32(M0, cihh, hhh, aah, aal);
s_bmul32(M1, cihl, hhl, abh, abl); s_bmul32(M1, cihl, hhl, abh, abl);
@ -94,8 +104,8 @@ void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t &y0, uint64_t &y1) n
cbh ^= bbh ^ abh; cbh ^= bbh ^ abh;
cbl ^= bbl ^ abl; cbl ^= bbl ^ abl;
uint64_t zhh = ((uint64_t)aah << 32U) | aal; uint64_t zhh = ((uint64_t)aah << 32U) | aal;
uint64_t zhl = (((uint64_t)abh << 32U) | abl) ^(((uint64_t)cah << 32U) | cal); uint64_t zhl = (((uint64_t)abh << 32U) | abl) ^ (((uint64_t)cah << 32U) | cal);
uint64_t zlh = (((uint64_t)bah << 32U) | bal) ^(((uint64_t)cbh << 32U) | cbl); uint64_t zlh = (((uint64_t)bah << 32U) | bal) ^ (((uint64_t)cbh << 32U) | cbl);
uint64_t zll = ((uint64_t)bbh << 32U) | bbl; uint64_t zll = ((uint64_t)bbh << 32U) | bbl;
zhh = zhh << 1U | zhl >> 63U; zhh = zhh << 1U | zhl >> 63U;
zhl = zhl << 1U | zlh >> 63U; zhl = zhl << 1U | zlh >> 63U;
@ -110,9 +120,9 @@ void s_gfmul(const uint64_t hh, const uint64_t hl, uint64_t &y0, uint64_t &y1) n
} // anonymous namespace } // anonymous namespace
void AES::GMAC::update(const void *const data, unsigned int len) noexcept void AES::GMAC::update(const void* const data, unsigned int len) noexcept
{ {
const uint8_t *in = reinterpret_cast<const uint8_t *>(data); const uint8_t* in = reinterpret_cast<const uint8_t*>(data);
_len += len; _len += len;
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
@ -136,13 +146,13 @@ void AES::GMAC::update(const void *const data, unsigned int len) noexcept
if (_rp) { if (_rp) {
for (;;) { for (;;) {
if (!len) if (! len)
return; return;
--len; --len;
_r[_rp++] = *(in++); _r[_rp++] = *(in++);
if (_rp == 16) { if (_rp == 16) {
y0 ^= Utils::loadMachineEndian< uint64_t >(_r); y0 ^= Utils::loadMachineEndian<uint64_t>(_r);
y1 ^= Utils::loadMachineEndian< uint64_t >(_r + 8); y1 ^= Utils::loadMachineEndian<uint64_t>(_r + 8);
s_gfmul(h0, h1, y0, y1); s_gfmul(h0, h1, y0, y1);
break; break;
} }
@ -150,8 +160,8 @@ void AES::GMAC::update(const void *const data, unsigned int len) noexcept
} }
while (len >= 16) { while (len >= 16) {
y0 ^= Utils::loadMachineEndian< uint64_t >(in); y0 ^= Utils::loadMachineEndian<uint64_t>(in);
y1 ^= Utils::loadMachineEndian< uint64_t >(in + 8); y1 ^= Utils::loadMachineEndian<uint64_t>(in + 8);
in += 16; in += 16;
s_gfmul(h0, h1, y0, y1); s_gfmul(h0, h1, y0, y1);
len -= 16; len -= 16;
@ -189,8 +199,8 @@ void AES::GMAC::finish(uint8_t tag[16]) noexcept
if (_rp) { if (_rp) {
while (_rp < 16) while (_rp < 16)
_r[_rp++] = 0; _r[_rp++] = 0;
y0 ^= Utils::loadMachineEndian< uint64_t >(_r); y0 ^= Utils::loadMachineEndian<uint64_t>(_r);
y1 ^= Utils::loadMachineEndian< uint64_t >(_r + 8); y1 ^= Utils::loadMachineEndian<uint64_t>(_r + 8);
s_gfmul(h0, h1, y0, y1); s_gfmul(h0, h1, y0, y1);
} }
@ -198,24 +208,24 @@ void AES::GMAC::finish(uint8_t tag[16]) noexcept
s_gfmul(h0, h1, y0, y1); s_gfmul(h0, h1, y0, y1);
uint64_t iv2[2]; uint64_t iv2[2];
Utils::copy< 12 >(iv2, _iv); Utils::copy<12>(iv2, _iv);
#if __BYTE_ORDER == __BIG_ENDIAN #if __BYTE_ORDER == __BIG_ENDIAN
reinterpret_cast<uint32_t *>(iv2)[3] = 0x00000001; reinterpret_cast<uint32_t*>(iv2)[3] = 0x00000001;
#else #else
reinterpret_cast<uint32_t *>(iv2)[3] = 0x01000000; reinterpret_cast<uint32_t*>(iv2)[3] = 0x01000000;
#endif #endif
_aes.encrypt(iv2, iv2); _aes.encrypt(iv2, iv2);
Utils::storeMachineEndian< uint64_t >(tag, iv2[0] ^ y0); Utils::storeMachineEndian<uint64_t>(tag, iv2[0] ^ y0);
Utils::storeMachineEndian< uint64_t >(tag + 8, iv2[1] ^ y1); Utils::storeMachineEndian<uint64_t>(tag + 8, iv2[1] ^ y1);
} }
// AES-CTR ------------------------------------------------------------------------------------------------------------ // AES-CTR ------------------------------------------------------------------------------------------------------------
void AES::CTR::crypt(const void *const input, unsigned int len) noexcept void AES::CTR::crypt(const void* const input, unsigned int len) noexcept
{ {
const uint8_t *in = reinterpret_cast<const uint8_t *>(input); const uint8_t* in = reinterpret_cast<const uint8_t*>(input);
uint8_t *out = _out; uint8_t* out = _out;
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
if (likely(Utils::CPUID.aes)) { if (likely(Utils::CPUID.aes)) {
@ -232,23 +242,23 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
#endif // ZT_AES_NEON #endif // ZT_AES_NEON
uint64_t keyStream[2]; uint64_t keyStream[2];
uint32_t ctr = Utils::ntoh(reinterpret_cast<uint32_t *>(_ctr)[3]); uint32_t ctr = Utils::ntoh(reinterpret_cast<uint32_t*>(_ctr)[3]);
unsigned int totalLen = _len; unsigned int totalLen = _len;
if ((totalLen & 15U)) { if ((totalLen & 15U)) {
for (;;) { for (;;) {
if (!len) { if (! len) {
_len = (totalLen + len); _len = (totalLen + len);
return; return;
} }
--len; --len;
out[totalLen++] = *(in++); out[totalLen++] = *(in++);
if (!(totalLen & 15U)) { if (! (totalLen & 15U)) {
_aes.p_encryptSW(reinterpret_cast<const uint8_t *>(_ctr), reinterpret_cast<uint8_t *>(keyStream)); _aes.p_encryptSW(reinterpret_cast<const uint8_t*>(_ctr), reinterpret_cast<uint8_t*>(keyStream));
reinterpret_cast<uint32_t *>(_ctr)[3] = Utils::hton(++ctr); reinterpret_cast<uint32_t*>(_ctr)[3] = Utils::hton(++ctr);
uint8_t *outblk = out + (totalLen - 16); uint8_t* outblk = out + (totalLen - 16);
for (int i = 0; i < 16; ++i) for (int i = 0; i < 16; ++i)
outblk[i] ^= reinterpret_cast<uint8_t *>(keyStream)[i]; outblk[i] ^= reinterpret_cast<uint8_t*>(keyStream)[i];
break; break;
} }
} }
@ -258,10 +268,10 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
_len = (totalLen + len); _len = (totalLen + len);
if (likely(len >= 16)) { if (likely(len >= 16)) {
const uint32_t *const restrict rk = _aes.p_k.sw.ek; const uint32_t* const restrict rk = _aes.p_k.sw.ek;
const uint32_t ctr0rk0 = Utils::ntoh(reinterpret_cast<const uint32_t *>(_ctr)[0]) ^rk[0]; const uint32_t ctr0rk0 = Utils::ntoh(reinterpret_cast<const uint32_t*>(_ctr)[0]) ^ rk[0];
const uint32_t ctr1rk1 = Utils::ntoh(reinterpret_cast<const uint32_t *>(_ctr)[1]) ^rk[1]; const uint32_t ctr1rk1 = Utils::ntoh(reinterpret_cast<const uint32_t*>(_ctr)[1]) ^ rk[1];
const uint32_t ctr2rk2 = Utils::ntoh(reinterpret_cast<const uint32_t *>(_ctr)[2]) ^rk[2]; const uint32_t ctr2rk2 = Utils::ntoh(reinterpret_cast<const uint32_t*>(_ctr)[2]) ^ rk[2];
const uint32_t m8 = 0x000000ff; const uint32_t m8 = 0x000000ff;
const uint32_t m8_8 = 0x0000ff00; const uint32_t m8_8 = 0x0000ff00;
const uint32_t m8_16 = 0x00ff0000; const uint32_t m8_16 = 0x00ff0000;
@ -274,8 +284,8 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
s2 = ctr2rk2; s2 = ctr2rk2;
s3 = ctr++ ^ rk[3]; s3 = ctr++ ^ rk[3];
const uint64_t in0 = *reinterpret_cast<const uint64_t *>(in); const uint64_t in0 = *reinterpret_cast<const uint64_t*>(in);
const uint64_t in1 = *reinterpret_cast<const uint64_t *>(in + 8); const uint64_t in1 = *reinterpret_cast<const uint64_t*>(in + 8);
in += 16; in += 16;
t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4]; t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4];
@ -330,16 +340,21 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53]; t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53];
t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54]; t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54];
t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55]; t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55];
s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8) ^ (Te1_r(t3 & m8) & m8) ^ rk[56]; s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8)
s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8) ^ (Te1_r(t0 & m8) & m8) ^ rk[57]; ^ (Te1_r(t3 & m8) & m8) ^ rk[56];
s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58]; s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8)
s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59]; ^ (Te1_r(t0 & m8) & m8) ^ rk[57];
s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8)
^ (Te1_r(t1 & m8) & m8) ^ rk[58];
s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8)
^ (Te1_r(t2 & m8) & m8) ^ rk[59];
*reinterpret_cast<uint64_t *>(out) = in0 ^ Utils::hton(((uint64_t)s0 << 32U) | (uint64_t)s1); *reinterpret_cast<uint64_t*>(out) = in0 ^ Utils::hton(((uint64_t)s0 << 32U) | (uint64_t)s1);
*reinterpret_cast<uint64_t *>(out + 8) = in1 ^ Utils::hton(((uint64_t)s2 << 32U) | (uint64_t)s3); *reinterpret_cast<uint64_t*>(out + 8) = in1 ^ Utils::hton(((uint64_t)s2 << 32U) | (uint64_t)s3);
out += 16; out += 16;
} while ((len -= 16) >= 16); } while ((len -= 16) >= 16);
} else { }
else {
do { do {
uint32_t s0, s1, s2, s3, t0, t1, t2, t3; uint32_t s0, s1, s2, s3, t0, t1, t2, t3;
s0 = ctr0rk0; s0 = ctr0rk0;
@ -399,10 +414,14 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53]; t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53];
t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54]; t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54];
t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55]; t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55];
s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8) ^ (Te1_r(t3 & m8) & m8) ^ rk[56]; s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8)
s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8) ^ (Te1_r(t0 & m8) & m8) ^ rk[57]; ^ (Te1_r(t3 & m8) & m8) ^ rk[56];
s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58]; s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8)
s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59]; ^ (Te1_r(t0 & m8) & m8) ^ rk[57];
s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8)
^ (Te1_r(t1 & m8) & m8) ^ rk[58];
s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8)
^ (Te1_r(t2 & m8) & m8) ^ rk[59];
out[0] = in[0] ^ (uint8_t)(s0 >> 24U); out[0] = in[0] ^ (uint8_t)(s0 >> 24U);
out[1] = in[1] ^ (uint8_t)(s0 >> 16U); out[1] = in[1] ^ (uint8_t)(s0 >> 16U);
@ -424,7 +443,7 @@ void AES::CTR::crypt(const void *const input, unsigned int len) noexcept
in += 16; in += 16;
} while ((len -= 16) >= 16); } while ((len -= 16) >= 16);
} }
reinterpret_cast<uint32_t *>(_ctr)[3] = Utils::hton(ctr); reinterpret_cast<uint32_t*>(_ctr)[3] = Utils::hton(ctr);
} }
// Any remaining input is placed in _out. This will be picked up and crypted // Any remaining input is placed in _out. This will be picked up and crypted
@ -449,65 +468,150 @@ void AES::CTR::finish() noexcept
// Software AES and AES key expansion --------------------------------------------------------------------------------- // Software AES and AES key expansion ---------------------------------------------------------------------------------
const uint32_t AES::Te0[256] = {0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193, 0xabd8d873, 0x62313153, const uint32_t AES::Te0[256] = {
0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1, 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd, 0xea75759f, 0xc66363a5, 0xf87c7c84, 0xee777799, 0xf67b7b8d, 0xfff2f20d, 0xd66b6bbd, 0xde6f6fb1, 0x91c5c554, 0x60303050,
0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x02010103, 0xce6767a9, 0x562b2b7d, 0xe7fefe19, 0xb5d7d762, 0x4dababe6, 0xec76769a, 0x8fcaca45, 0x1f82829d,
0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a, 0xfdf3f30e, 0xbfd2d26d, 0x89c9c940, 0xfa7d7d87, 0xeffafa15, 0xb25959eb, 0x8e4747c9, 0xfbf0f00b, 0x41adadec, 0xb3d4d467, 0x5fa2a2fd,
0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0x45afafea, 0x239c9cbf, 0x53a4a4f7, 0xe4727296, 0x9bc0c05b, 0x75b7b7c2, 0xe1fdfd1c, 0x3d9393ae, 0x4c26266a,
0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6c36365a, 0x7e3f3f41, 0xf5f7f702, 0x83cccc4f, 0x6834345c, 0x51a5a5f4, 0xd1e5e534, 0xf9f1f108, 0xe2717193,
0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1, 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22, 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xabd8d873, 0x62313153, 0x2a15153f, 0x0804040c, 0x95c7c752, 0x46232365, 0x9dc3c35e, 0x30181828, 0x379696a1,
0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980, 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11, 0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a}; 0x0a05050f, 0x2f9a9ab5, 0x0e070709, 0x24121236, 0x1b80809b, 0xdfe2e23d, 0xcdebeb26, 0x4e272769, 0x7fb2b2cd,
const uint32_t AES::Te4[256] = {0x63636363, 0x7c7c7c7c, 0x77777777, 0x7b7b7b7b, 0xf2f2f2f2, 0x6b6b6b6b, 0x6f6f6f6f, 0xc5c5c5c5, 0x30303030, 0x01010101, 0x67676767, 0x2b2b2b2b, 0xfefefefe, 0xd7d7d7d7, 0xabababab, 0x76767676, 0xcacacaca, 0x82828282, 0xc9c9c9c9, 0x7d7d7d7d, 0xfafafafa, 0x59595959, 0x47474747, 0xf0f0f0f0, 0xadadadad, 0xd4d4d4d4, 0xa2a2a2a2, 0xafafafaf, 0x9c9c9c9c, 0xa4a4a4a4, 0x72727272, 0xc0c0c0c0, 0xb7b7b7b7, 0xfdfdfdfd, 0x93939393, 0x26262626, 0x36363636, 0x3f3f3f3f, 0xf7f7f7f7, 0xcccccccc, 0x34343434, 0xa5a5a5a5, 0xe5e5e5e5, 0xf1f1f1f1, 0x71717171, 0xd8d8d8d8, 0x31313131, 0xea75759f, 0x1209091b, 0x1d83839e, 0x582c2c74, 0x341a1a2e, 0x361b1b2d, 0xdc6e6eb2, 0xb45a5aee, 0x5ba0a0fb,
0x15151515, 0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3, 0x18181818, 0x96969696, 0x05050505, 0x9a9a9a9a, 0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2, 0xebebebeb, 0x27272727, 0xb2b2b2b2, 0x75757575, 0xa45252f6, 0x763b3b4d, 0xb7d6d661, 0x7db3b3ce, 0x5229297b, 0xdde3e33e, 0x5e2f2f71, 0x13848497, 0xa65353f5,
0x09090909, 0x83838383, 0x2c2c2c2c, 0x1a1a1a1a, 0x1b1b1b1b, 0x6e6e6e6e, 0x5a5a5a5a, 0xa0a0a0a0, 0x52525252, 0x3b3b3b3b, 0xd6d6d6d6, 0xb3b3b3b3, 0x29292929, 0xe3e3e3e3, 0x2f2f2f2f, 0x84848484, 0x53535353, 0xd1d1d1d1, 0x00000000, 0xedededed, 0x20202020, 0xfcfcfcfc, 0xb1b1b1b1, 0x5b5b5b5b, 0x6a6a6a6a, 0xcbcbcbcb, 0xbebebebe, 0x39393939, 0x4a4a4a4a, 0x4c4c4c4c, 0x58585858, 0xcfcfcfcf, 0xd0d0d0d0, 0xefefefef, 0xaaaaaaaa, 0xfbfbfbfb, 0x43434343, 0x4d4d4d4d, 0x33333333, 0x85858585, 0x45454545, 0xf9f9f9f9, 0x02020202, 0x7f7f7f7f, 0x50505050, 0x3c3c3c3c, 0x9f9f9f9f, 0xb9d1d168, 0x00000000, 0xc1eded2c, 0x40202060, 0xe3fcfc1f, 0x79b1b1c8, 0xb65b5bed, 0xd46a6abe, 0x8dcbcb46,
0xa8a8a8a8, 0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f, 0x92929292, 0x9d9d9d9d, 0x38383838, 0xf5f5f5f5, 0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121, 0x10101010, 0xffffffff, 0xf3f3f3f3, 0xd2d2d2d2, 0x67bebed9, 0x7239394b, 0x944a4ade, 0x984c4cd4, 0xb05858e8, 0x85cfcf4a, 0xbbd0d06b, 0xc5efef2a, 0x4faaaae5,
0xcdcdcdcd, 0x0c0c0c0c, 0x13131313, 0xecececec, 0x5f5f5f5f, 0x97979797, 0x44444444, 0x17171717, 0xc4c4c4c4, 0xa7a7a7a7, 0x7e7e7e7e, 0x3d3d3d3d, 0x64646464, 0x5d5d5d5d, 0x19191919, 0x73737373, 0x60606060, 0x81818181, 0x4f4f4f4f, 0xdcdcdcdc, 0x22222222, 0x2a2a2a2a, 0x90909090, 0x88888888, 0x46464646, 0xeeeeeeee, 0xb8b8b8b8, 0x14141414, 0xdededede, 0x5e5e5e5e, 0x0b0b0b0b, 0xdbdbdbdb, 0xe0e0e0e0, 0x32323232, 0x3a3a3a3a, 0x0a0a0a0a, 0x49494949, 0x06060606, 0x24242424, 0x5c5c5c5c, 0xc2c2c2c2, 0xd3d3d3d3, 0xacacacac, 0x62626262, 0x91919191, 0x95959595, 0xe4e4e4e4, 0xedfbfb16, 0x864343c5, 0x9a4d4dd7, 0x66333355, 0x11858594, 0x8a4545cf, 0xe9f9f910, 0x04020206, 0xfe7f7f81,
0x79797979, 0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d, 0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9, 0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea, 0x65656565, 0x7a7a7a7a, 0xaeaeaeae, 0x08080808, 0xa05050f0, 0x783c3c44, 0x259f9fba, 0x4ba8a8e3, 0xa25151f3, 0x5da3a3fe, 0x804040c0, 0x058f8f8a, 0x3f9292ad,
0xbabababa, 0x78787878, 0x25252525, 0x2e2e2e2e, 0x1c1c1c1c, 0xa6a6a6a6, 0xb4b4b4b4, 0xc6c6c6c6, 0xe8e8e8e8, 0xdddddddd, 0x74747474, 0x1f1f1f1f, 0x4b4b4b4b, 0xbdbdbdbd, 0x8b8b8b8b, 0x8a8a8a8a, 0x70707070, 0x3e3e3e3e, 0xb5b5b5b5, 0x66666666, 0x48484848, 0x03030303, 0xf6f6f6f6, 0x0e0e0e0e, 0x61616161, 0x35353535, 0x57575757, 0xb9b9b9b9, 0x86868686, 0xc1c1c1c1, 0x1d1d1d1d, 0x9e9e9e9e, 0xe1e1e1e1, 0xf8f8f8f8, 0x98989898, 0x11111111, 0x69696969, 0xd9d9d9d9, 0x8e8e8e8e, 0x94949494, 0x9b9b9b9b, 0x1e1e1e1e, 0x87878787, 0xe9e9e9e9, 0xcececece, 0x55555555, 0x28282828, 0x219d9dbc, 0x70383848, 0xf1f5f504, 0x63bcbcdf, 0x77b6b6c1, 0xafdada75, 0x42212163, 0x20101030, 0xe5ffff1a,
0xdfdfdfdf, 0x8c8c8c8c, 0xa1a1a1a1, 0x89898989, 0x0d0d0d0d, 0xbfbfbfbf, 0xe6e6e6e6, 0x42424242, 0x68686868, 0x41414141, 0x99999999, 0x2d2d2d2d, 0x0f0f0f0f, 0xb0b0b0b0, 0x54545454, 0xbbbbbbbb, 0x16161616}; 0xfdf3f30e, 0xbfd2d26d, 0x81cdcd4c, 0x180c0c14, 0x26131335, 0xc3ecec2f, 0xbe5f5fe1, 0x359797a2, 0x884444cc,
const uint32_t AES::Td0[256] = {0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55, 0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67, 0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb, 0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd, 0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0, 0xbb6bae84, 0xfe81a01c, 0x2e171739, 0x93c4c457, 0x55a7a7f2, 0xfc7e7e82, 0x7a3d3d47, 0xc86464ac, 0xba5d5de7, 0x3219192b, 0xe6737395,
0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2, 0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba, 0xed16825c, 0xc06060a0, 0x19818198, 0x9e4f4fd1, 0xa3dcdc7f, 0x44222266, 0x542a2a7e, 0x3b9090ab, 0x0b888883, 0x8c4646ca,
0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a, 0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9, 0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997, 0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9, 0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927, 0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0xc7eeee29, 0x6bb8b8d3, 0x2814143c, 0xa7dede79, 0xbc5e5ee2, 0x160b0b1d, 0xaddbdb76, 0xdbe0e03b, 0x64323256,
0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f, 0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad, 0x2db6a8b9, 0x141ea9c8, 0x743a3a4e, 0x140a0a1e, 0x924949db, 0x0c06060a, 0x4824246c, 0xb85c5ce4, 0x9fc2c25d, 0xbdd3d36e, 0x43acacef,
0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5, 0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120, 0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c, 0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1, 0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b, 0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0xc46262a6, 0x399191a8, 0x319595a4, 0xd3e4e437, 0xf279798b, 0xd5e7e732, 0x8bc8c843, 0x6e373759, 0xda6d6db7,
0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3, 0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65, 0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0x018d8d8c, 0xb1d5d564, 0x9c4e4ed2, 0x49a9a9e0, 0xd86c6cb4, 0xac5656fa, 0xf3f4f407, 0xcfeaea25, 0xca6565af,
0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331, 0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e, 0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f, 0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c, 0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f, 0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0xf47a7a8e, 0x47aeaee9, 0x10080818, 0x6fbabad5, 0xf0787888, 0x4a25256f, 0x5c2e2e72, 0x381c1c24, 0x57a6a6f1,
0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c, 0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190, 0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742}; 0x73b4b4c7, 0x97c6c651, 0xcbe8e823, 0xa1dddd7c, 0xe874749c, 0x3e1f1f21, 0x964b4bdd, 0x61bdbddc, 0x0d8b8b86,
const uint8_t AES::Td4[256] = {0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x0f8a8a85, 0xe0707090, 0x7c3e3e42, 0x71b5b5c4, 0xcc6666aa, 0x904848d8, 0x06030305, 0xf7f6f601, 0x1c0e0e12,
0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0xc26161a3, 0x6a35355f, 0xae5757f9, 0x69b9b9d0, 0x17868691, 0x99c1c158, 0x3a1d1d27, 0x279e9eb9, 0xd9e1e138,
0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xebf8f813, 0x2b9898b3, 0x22111133, 0xd26969bb, 0xa9d9d970, 0x078e8e89, 0x339494a7, 0x2d9b9bb6, 0x3c1e1e22,
0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d}; 0x15878792, 0xc9e9e920, 0x87cece49, 0xaa5555ff, 0x50282878, 0xa5dfdf7a, 0x038c8c8f, 0x59a1a1f8, 0x09898980,
const uint32_t AES::rcon[15] = {0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000, 0x6c000000, 0xd8000000, 0xab000000, 0x4d000000, 0x9a000000}; 0x1a0d0d17, 0x65bfbfda, 0xd7e6e631, 0x844242c6, 0xd06868b8, 0x824141c3, 0x299999b0, 0x5a2d2d77, 0x1e0f0f11,
0x7bb0b0cb, 0xa85454fc, 0x6dbbbbd6, 0x2c16163a
};
const uint32_t AES::Te4[256] = {
0x63636363, 0x7c7c7c7c, 0x77777777, 0x7b7b7b7b, 0xf2f2f2f2, 0x6b6b6b6b, 0x6f6f6f6f, 0xc5c5c5c5, 0x30303030,
0x01010101, 0x67676767, 0x2b2b2b2b, 0xfefefefe, 0xd7d7d7d7, 0xabababab, 0x76767676, 0xcacacaca, 0x82828282,
0xc9c9c9c9, 0x7d7d7d7d, 0xfafafafa, 0x59595959, 0x47474747, 0xf0f0f0f0, 0xadadadad, 0xd4d4d4d4, 0xa2a2a2a2,
0xafafafaf, 0x9c9c9c9c, 0xa4a4a4a4, 0x72727272, 0xc0c0c0c0, 0xb7b7b7b7, 0xfdfdfdfd, 0x93939393, 0x26262626,
0x36363636, 0x3f3f3f3f, 0xf7f7f7f7, 0xcccccccc, 0x34343434, 0xa5a5a5a5, 0xe5e5e5e5, 0xf1f1f1f1, 0x71717171,
0xd8d8d8d8, 0x31313131, 0x15151515, 0x04040404, 0xc7c7c7c7, 0x23232323, 0xc3c3c3c3, 0x18181818, 0x96969696,
0x05050505, 0x9a9a9a9a, 0x07070707, 0x12121212, 0x80808080, 0xe2e2e2e2, 0xebebebeb, 0x27272727, 0xb2b2b2b2,
0x75757575, 0x09090909, 0x83838383, 0x2c2c2c2c, 0x1a1a1a1a, 0x1b1b1b1b, 0x6e6e6e6e, 0x5a5a5a5a, 0xa0a0a0a0,
0x52525252, 0x3b3b3b3b, 0xd6d6d6d6, 0xb3b3b3b3, 0x29292929, 0xe3e3e3e3, 0x2f2f2f2f, 0x84848484, 0x53535353,
0xd1d1d1d1, 0x00000000, 0xedededed, 0x20202020, 0xfcfcfcfc, 0xb1b1b1b1, 0x5b5b5b5b, 0x6a6a6a6a, 0xcbcbcbcb,
0xbebebebe, 0x39393939, 0x4a4a4a4a, 0x4c4c4c4c, 0x58585858, 0xcfcfcfcf, 0xd0d0d0d0, 0xefefefef, 0xaaaaaaaa,
0xfbfbfbfb, 0x43434343, 0x4d4d4d4d, 0x33333333, 0x85858585, 0x45454545, 0xf9f9f9f9, 0x02020202, 0x7f7f7f7f,
0x50505050, 0x3c3c3c3c, 0x9f9f9f9f, 0xa8a8a8a8, 0x51515151, 0xa3a3a3a3, 0x40404040, 0x8f8f8f8f, 0x92929292,
0x9d9d9d9d, 0x38383838, 0xf5f5f5f5, 0xbcbcbcbc, 0xb6b6b6b6, 0xdadadada, 0x21212121, 0x10101010, 0xffffffff,
0xf3f3f3f3, 0xd2d2d2d2, 0xcdcdcdcd, 0x0c0c0c0c, 0x13131313, 0xecececec, 0x5f5f5f5f, 0x97979797, 0x44444444,
0x17171717, 0xc4c4c4c4, 0xa7a7a7a7, 0x7e7e7e7e, 0x3d3d3d3d, 0x64646464, 0x5d5d5d5d, 0x19191919, 0x73737373,
0x60606060, 0x81818181, 0x4f4f4f4f, 0xdcdcdcdc, 0x22222222, 0x2a2a2a2a, 0x90909090, 0x88888888, 0x46464646,
0xeeeeeeee, 0xb8b8b8b8, 0x14141414, 0xdededede, 0x5e5e5e5e, 0x0b0b0b0b, 0xdbdbdbdb, 0xe0e0e0e0, 0x32323232,
0x3a3a3a3a, 0x0a0a0a0a, 0x49494949, 0x06060606, 0x24242424, 0x5c5c5c5c, 0xc2c2c2c2, 0xd3d3d3d3, 0xacacacac,
0x62626262, 0x91919191, 0x95959595, 0xe4e4e4e4, 0x79797979, 0xe7e7e7e7, 0xc8c8c8c8, 0x37373737, 0x6d6d6d6d,
0x8d8d8d8d, 0xd5d5d5d5, 0x4e4e4e4e, 0xa9a9a9a9, 0x6c6c6c6c, 0x56565656, 0xf4f4f4f4, 0xeaeaeaea, 0x65656565,
0x7a7a7a7a, 0xaeaeaeae, 0x08080808, 0xbabababa, 0x78787878, 0x25252525, 0x2e2e2e2e, 0x1c1c1c1c, 0xa6a6a6a6,
0xb4b4b4b4, 0xc6c6c6c6, 0xe8e8e8e8, 0xdddddddd, 0x74747474, 0x1f1f1f1f, 0x4b4b4b4b, 0xbdbdbdbd, 0x8b8b8b8b,
0x8a8a8a8a, 0x70707070, 0x3e3e3e3e, 0xb5b5b5b5, 0x66666666, 0x48484848, 0x03030303, 0xf6f6f6f6, 0x0e0e0e0e,
0x61616161, 0x35353535, 0x57575757, 0xb9b9b9b9, 0x86868686, 0xc1c1c1c1, 0x1d1d1d1d, 0x9e9e9e9e, 0xe1e1e1e1,
0xf8f8f8f8, 0x98989898, 0x11111111, 0x69696969, 0xd9d9d9d9, 0x8e8e8e8e, 0x94949494, 0x9b9b9b9b, 0x1e1e1e1e,
0x87878787, 0xe9e9e9e9, 0xcececece, 0x55555555, 0x28282828, 0xdfdfdfdf, 0x8c8c8c8c, 0xa1a1a1a1, 0x89898989,
0x0d0d0d0d, 0xbfbfbfbf, 0xe6e6e6e6, 0x42424242, 0x68686868, 0x41414141, 0x99999999, 0x2d2d2d2d, 0x0f0f0f0f,
0xb0b0b0b0, 0x54545454, 0xbbbbbbbb, 0x16161616
};
const uint32_t AES::Td0[256] = {
0x51f4a750, 0x7e416553, 0x1a17a4c3, 0x3a275e96, 0x3bab6bcb, 0x1f9d45f1, 0xacfa58ab, 0x4be30393, 0x2030fa55,
0xad766df6, 0x88cc7691, 0xf5024c25, 0x4fe5d7fc, 0xc52acbd7, 0x26354480, 0xb562a38f, 0xdeb15a49, 0x25ba1b67,
0x45ea0e98, 0x5dfec0e1, 0xc32f7502, 0x814cf012, 0x8d4697a3, 0x6bd3f9c6, 0x038f5fe7, 0x15929c95, 0xbf6d7aeb,
0x955259da, 0xd4be832d, 0x587421d3, 0x49e06929, 0x8ec9c844, 0x75c2896a, 0xf48e7978, 0x99583e6b, 0x27b971dd,
0xbee14fb6, 0xf088ad17, 0xc920ac66, 0x7dce3ab4, 0x63df4a18, 0xe51a3182, 0x97513360, 0x62537f45, 0xb16477e0,
0xbb6bae84, 0xfe81a01c, 0xf9082b94, 0x70486858, 0x8f45fd19, 0x94de6c87, 0x527bf8b7, 0xab73d323, 0x724b02e2,
0xe31f8f57, 0x6655ab2a, 0xb2eb2807, 0x2fb5c203, 0x86c57b9a, 0xd33708a5, 0x302887f2, 0x23bfa5b2, 0x02036aba,
0xed16825c, 0x8acf1c2b, 0xa779b492, 0xf307f2f0, 0x4e69e2a1, 0x65daf4cd, 0x0605bed5, 0xd134621f, 0xc4a6fe8a,
0x342e539d, 0xa2f355a0, 0x058ae132, 0xa4f6eb75, 0x0b83ec39, 0x4060efaa, 0x5e719f06, 0xbd6e1051, 0x3e218af9,
0x96dd063d, 0xdd3e05ae, 0x4de6bd46, 0x91548db5, 0x71c45d05, 0x0406d46f, 0x605015ff, 0x1998fb24, 0xd6bde997,
0x894043cc, 0x67d99e77, 0xb0e842bd, 0x07898b88, 0xe7195b38, 0x79c8eedb, 0xa17c0a47, 0x7c420fe9, 0xf8841ec9,
0x00000000, 0x09808683, 0x322bed48, 0x1e1170ac, 0x6c5a724e, 0xfd0efffb, 0x0f853856, 0x3daed51e, 0x362d3927,
0x0a0fd964, 0x685ca621, 0x9b5b54d1, 0x24362e3a, 0x0c0a67b1, 0x9357e70f, 0xb4ee96d2, 0x1b9b919e, 0x80c0c54f,
0x61dc20a2, 0x5a774b69, 0x1c121a16, 0xe293ba0a, 0xc0a02ae5, 0x3c22e043, 0x121b171d, 0x0e090d0b, 0xf28bc7ad,
0x2db6a8b9, 0x141ea9c8, 0x57f11985, 0xaf75074c, 0xee99ddbb, 0xa37f60fd, 0xf701269f, 0x5c72f5bc, 0x44663bc5,
0x5bfb7e34, 0x8b432976, 0xcb23c6dc, 0xb6edfc68, 0xb8e4f163, 0xd731dcca, 0x42638510, 0x13972240, 0x84c61120,
0x854a247d, 0xd2bb3df8, 0xaef93211, 0xc729a16d, 0x1d9e2f4b, 0xdcb230f3, 0x0d8652ec, 0x77c1e3d0, 0x2bb3166c,
0xa970b999, 0x119448fa, 0x47e96422, 0xa8fc8cc4, 0xa0f03f1a, 0x567d2cd8, 0x223390ef, 0x87494ec7, 0xd938d1c1,
0x8ccaa2fe, 0x98d40b36, 0xa6f581cf, 0xa57ade28, 0xdab78e26, 0x3fadbfa4, 0x2c3a9de4, 0x5078920d, 0x6a5fcc9b,
0x547e4662, 0xf68d13c2, 0x90d8b8e8, 0x2e39f75e, 0x82c3aff5, 0x9f5d80be, 0x69d0937c, 0x6fd52da9, 0xcf2512b3,
0xc8ac993b, 0x10187da7, 0xe89c636e, 0xdb3bbb7b, 0xcd267809, 0x6e5918f4, 0xec9ab701, 0x834f9aa8, 0xe6956e65,
0xaaffe67e, 0x21bccf08, 0xef15e8e6, 0xbae79bd9, 0x4a6f36ce, 0xea9f09d4, 0x29b07cd6, 0x31a4b2af, 0x2a3f2331,
0xc6a59430, 0x35a266c0, 0x744ebc37, 0xfc82caa6, 0xe090d0b0, 0x33a7d815, 0xf104984a, 0x41ecdaf7, 0x7fcd500e,
0x1791f62f, 0x764dd68d, 0x43efb04d, 0xccaa4d54, 0xe49604df, 0x9ed1b5e3, 0x4c6a881b, 0xc12c1fb8, 0x4665517f,
0x9d5eea04, 0x018c355d, 0xfa877473, 0xfb0b412e, 0xb3671d5a, 0x92dbd252, 0xe9105633, 0x6dd64713, 0x9ad7618c,
0x37a10c7a, 0x59f8148e, 0xeb133c89, 0xcea927ee, 0xb761c935, 0xe11ce5ed, 0x7a47b13c, 0x9cd2df59, 0x55f2733f,
0x1814ce79, 0x73c737bf, 0x53f7cdea, 0x5ffdaa5b, 0xdf3d6f14, 0x7844db86, 0xcaaff381, 0xb968c43e, 0x3824342c,
0xc2a3405f, 0x161dc372, 0xbce2250c, 0x283c498b, 0xff0d9541, 0x39a80171, 0x080cb3de, 0xd8b4e49c, 0x6456c190,
0x7bcb8461, 0xd532b670, 0x486c5c74, 0xd0b85742
};
const uint8_t AES::Td4[256] = {
0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39,
0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2,
0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76,
0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc,
0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d,
0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c,
0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f,
0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85,
0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62,
0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd,
0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60,
0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d,
0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6,
0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d
};
const uint32_t AES::rcon[15] = { 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
0x6c000000, 0xd8000000, 0xab000000, 0x4d000000, 0x9a000000 };
void AES::p_initSW(const uint8_t *key) noexcept void AES::p_initSW(const uint8_t* key) noexcept
{ {
uint32_t *rk = p_k.sw.ek; uint32_t* rk = p_k.sw.ek;
rk[0] = Utils::loadBigEndian< uint32_t >(key); rk[0] = Utils::loadBigEndian<uint32_t>(key);
rk[1] = Utils::loadBigEndian< uint32_t >(key + 4); rk[1] = Utils::loadBigEndian<uint32_t>(key + 4);
rk[2] = Utils::loadBigEndian< uint32_t >(key + 8); rk[2] = Utils::loadBigEndian<uint32_t>(key + 8);
rk[3] = Utils::loadBigEndian< uint32_t >(key + 12); rk[3] = Utils::loadBigEndian<uint32_t>(key + 12);
rk[4] = Utils::loadBigEndian< uint32_t >(key + 16); rk[4] = Utils::loadBigEndian<uint32_t>(key + 16);
rk[5] = Utils::loadBigEndian< uint32_t >(key + 20); rk[5] = Utils::loadBigEndian<uint32_t>(key + 20);
rk[6] = Utils::loadBigEndian< uint32_t >(key + 24); rk[6] = Utils::loadBigEndian<uint32_t>(key + 24);
rk[7] = Utils::loadBigEndian< uint32_t >(key + 28); rk[7] = Utils::loadBigEndian<uint32_t>(key + 28);
for (int i = 0;;) { for (int i = 0;;) {
uint32_t temp = rk[7]; uint32_t temp = rk[7];
rk[8] = rk[0] ^ (Te2_r((temp >> 16U) & 0xffU) & 0xff000000U) ^ (Te3_r((temp >> 8U) & 0xffU) & 0x00ff0000U) ^ (Te0[(temp) & 0xffU] & 0x0000ff00U) ^ (Te1_r(temp >> 24U) & 0x000000ffU) ^ rcon[i]; rk[8] = rk[0] ^ (Te2_r((temp >> 16U) & 0xffU) & 0xff000000U) ^ (Te3_r((temp >> 8U) & 0xffU) & 0x00ff0000U)
^ (Te0[(temp)&0xffU] & 0x0000ff00U) ^ (Te1_r(temp >> 24U) & 0x000000ffU) ^ rcon[i];
rk[9] = rk[1] ^ rk[8]; rk[9] = rk[1] ^ rk[8];
rk[10] = rk[2] ^ rk[9]; rk[10] = rk[2] ^ rk[9];
rk[11] = rk[3] ^ rk[10]; rk[11] = rk[3] ^ rk[10];
if (++i == 7) if (++i == 7)
break; break;
temp = rk[11]; temp = rk[11];
rk[12] = rk[4] ^ (Te2_r(temp >> 24U) & 0xff000000U) ^ (Te3_r((temp >> 16U) & 0xffU) & 0x00ff0000U) ^ (Te0[(temp >> 8U) & 0xffU] & 0x0000ff00U) ^ (Te1_r((temp) & 0xffU) & 0x000000ffU); rk[12] = rk[4] ^ (Te2_r(temp >> 24U) & 0xff000000U) ^ (Te3_r((temp >> 16U) & 0xffU) & 0x00ff0000U)
^ (Te0[(temp >> 8U) & 0xffU] & 0x0000ff00U) ^ (Te1_r((temp)&0xffU) & 0x000000ffU);
rk[13] = rk[5] ^ rk[12]; rk[13] = rk[5] ^ rk[12];
rk[14] = rk[6] ^ rk[13]; rk[14] = rk[6] ^ rk[13];
rk[15] = rk[7] ^ rk[14]; rk[15] = rk[7] ^ rk[14];
rk += 8; rk += 8;
} }
p_encryptSW((const uint8_t *)Utils::ZERO256, (uint8_t *)p_k.sw.h); p_encryptSW((const uint8_t*)Utils::ZERO256, (uint8_t*)p_k.sw.h);
p_k.sw.h[0] = Utils::ntoh(p_k.sw.h[0]); p_k.sw.h[0] = Utils::ntoh(p_k.sw.h[0]);
p_k.sw.h[1] = Utils::ntoh(p_k.sw.h[1]); p_k.sw.h[1] = Utils::ntoh(p_k.sw.h[1]);
@ -531,24 +635,28 @@ void AES::p_initSW(const uint8_t *key) noexcept
} }
for (int i = 1; i < 14; ++i) { for (int i = 1; i < 14; ++i) {
rk += 4; rk += 4;
rk[0] = Td0[Te4[(rk[0] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[0] >> 16U) & 0xffU] & 0xffU) ^ Td2_r(Te4[(rk[0] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[0]) & 0xffU] & 0xffU); rk[0] = Td0[Te4[(rk[0] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[0] >> 16U) & 0xffU] & 0xffU)
rk[1] = Td0[Te4[(rk[1] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[1] >> 16U) & 0xffU] & 0xffU) ^ Td2_r(Te4[(rk[1] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[1]) & 0xffU] & 0xffU); ^ Td2_r(Te4[(rk[0] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[0]) & 0xffU] & 0xffU);
rk[2] = Td0[Te4[(rk[2] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[2] >> 16U) & 0xffU] & 0xffU) ^ Td2_r(Te4[(rk[2] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[2]) & 0xffU] & 0xffU); rk[1] = Td0[Te4[(rk[1] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[1] >> 16U) & 0xffU] & 0xffU)
rk[3] = Td0[Te4[(rk[3] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[3] >> 16U) & 0xffU] & 0xffU) ^ Td2_r(Te4[(rk[3] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[3]) & 0xffU] & 0xffU); ^ Td2_r(Te4[(rk[1] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[1]) & 0xffU] & 0xffU);
rk[2] = Td0[Te4[(rk[2] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[2] >> 16U) & 0xffU] & 0xffU)
^ Td2_r(Te4[(rk[2] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[2]) & 0xffU] & 0xffU);
rk[3] = Td0[Te4[(rk[3] >> 24U)] & 0xffU] ^ Td1_r(Te4[(rk[3] >> 16U) & 0xffU] & 0xffU)
^ Td2_r(Te4[(rk[3] >> 8U) & 0xffU] & 0xffU) ^ Td3_r(Te4[(rk[3]) & 0xffU] & 0xffU);
} }
} }
void AES::p_encryptSW(const uint8_t *in, uint8_t *out) const noexcept void AES::p_encryptSW(const uint8_t* in, uint8_t* out) const noexcept
{ {
const uint32_t *const restrict rk = p_k.sw.ek; const uint32_t* const restrict rk = p_k.sw.ek;
const uint32_t m8 = 0x000000ff; const uint32_t m8 = 0x000000ff;
const uint32_t m8_8 = 0x0000ff00; const uint32_t m8_8 = 0x0000ff00;
const uint32_t m8_16 = 0x00ff0000; const uint32_t m8_16 = 0x00ff0000;
const uint32_t m8_24 = 0xff000000; const uint32_t m8_24 = 0xff000000;
uint32_t s0 = Utils::loadBigEndian< uint32_t >(in) ^rk[0]; uint32_t s0 = Utils::loadBigEndian<uint32_t>(in) ^ rk[0];
uint32_t s1 = Utils::loadBigEndian< uint32_t >(in + 4) ^rk[1]; uint32_t s1 = Utils::loadBigEndian<uint32_t>(in + 4) ^ rk[1];
uint32_t s2 = Utils::loadBigEndian< uint32_t >(in + 8) ^rk[2]; uint32_t s2 = Utils::loadBigEndian<uint32_t>(in + 8) ^ rk[2];
uint32_t s3 = Utils::loadBigEndian< uint32_t >(in + 12) ^rk[3]; uint32_t s3 = Utils::loadBigEndian<uint32_t>(in + 12) ^ rk[3];
uint32_t t0, t1, t2, t3; uint32_t t0, t1, t2, t3;
t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4]; t0 = Te0[s0 >> 24U] ^ Te1_r((s1 >> 16U) & m8) ^ Te2_r((s2 >> 8U) & m8) ^ Te3_r(s3 & m8) ^ rk[4];
@ -603,25 +711,29 @@ void AES::p_encryptSW(const uint8_t *in, uint8_t *out) const noexcept
t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53]; t1 = Te0[s1 >> 24U] ^ Te1_r((s2 >> 16U) & m8) ^ Te2_r((s3 >> 8U) & m8) ^ Te3_r(s0 & m8) ^ rk[53];
t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54]; t2 = Te0[s2 >> 24U] ^ Te1_r((s3 >> 16U) & m8) ^ Te2_r((s0 >> 8U) & m8) ^ Te3_r(s1 & m8) ^ rk[54];
t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55]; t3 = Te0[s3 >> 24U] ^ Te1_r((s0 >> 16U) & m8) ^ Te2_r((s1 >> 8U) & m8) ^ Te3_r(s2 & m8) ^ rk[55];
s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8) ^ (Te1_r(t3 & m8) & m8) ^ rk[56]; s0 = (Te2_r(t0 >> 24U) & m8_24) ^ (Te3_r((t1 >> 16U) & m8) & m8_16) ^ (Te0[(t2 >> 8U) & m8] & m8_8)
s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8) ^ (Te1_r(t0 & m8) & m8) ^ rk[57]; ^ (Te1_r(t3 & m8) & m8) ^ rk[56];
s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8) ^ (Te1_r(t1 & m8) & m8) ^ rk[58]; s1 = (Te2_r(t1 >> 24U) & m8_24) ^ (Te3_r((t2 >> 16U) & m8) & m8_16) ^ (Te0[(t3 >> 8U) & m8] & m8_8)
s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8) ^ (Te1_r(t2 & m8) & m8) ^ rk[59]; ^ (Te1_r(t0 & m8) & m8) ^ rk[57];
s2 = (Te2_r(t2 >> 24U) & m8_24) ^ (Te3_r((t3 >> 16U) & m8) & m8_16) ^ (Te0[(t0 >> 8U) & m8] & m8_8)
^ (Te1_r(t1 & m8) & m8) ^ rk[58];
s3 = (Te2_r(t3 >> 24U) & m8_24) ^ (Te3_r((t0 >> 16U) & m8) & m8_16) ^ (Te0[(t1 >> 8U) & m8] & m8_8)
^ (Te1_r(t2 & m8) & m8) ^ rk[59];
Utils::storeBigEndian< uint32_t >(out, s0); Utils::storeBigEndian<uint32_t>(out, s0);
Utils::storeBigEndian< uint32_t >(out + 4, s1); Utils::storeBigEndian<uint32_t>(out + 4, s1);
Utils::storeBigEndian< uint32_t >(out + 8, s2); Utils::storeBigEndian<uint32_t>(out + 8, s2);
Utils::storeBigEndian< uint32_t >(out + 12, s3); Utils::storeBigEndian<uint32_t>(out + 12, s3);
} }
void AES::p_decryptSW(const uint8_t *in, uint8_t *out) const noexcept void AES::p_decryptSW(const uint8_t* in, uint8_t* out) const noexcept
{ {
const uint32_t *restrict rk = p_k.sw.dk; const uint32_t* restrict rk = p_k.sw.dk;
const uint32_t m8 = 0x000000ff; const uint32_t m8 = 0x000000ff;
uint32_t s0 = Utils::loadBigEndian< uint32_t >(in) ^rk[0]; uint32_t s0 = Utils::loadBigEndian<uint32_t>(in) ^ rk[0];
uint32_t s1 = Utils::loadBigEndian< uint32_t >(in + 4) ^rk[1]; uint32_t s1 = Utils::loadBigEndian<uint32_t>(in + 4) ^ rk[1];
uint32_t s2 = Utils::loadBigEndian< uint32_t >(in + 8) ^rk[2]; uint32_t s2 = Utils::loadBigEndian<uint32_t>(in + 8) ^ rk[2];
uint32_t s3 = Utils::loadBigEndian< uint32_t >(in + 12) ^rk[3]; uint32_t s3 = Utils::loadBigEndian<uint32_t>(in + 12) ^ rk[3];
uint32_t t0, t1, t2, t3; uint32_t t0, t1, t2, t3;
t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[4]; t0 = Td0[s0 >> 24U] ^ Td1_r((s3 >> 16U) & m8) ^ Td2_r((s2 >> 8U) & m8) ^ Td3_r(s1 & m8) ^ rk[4];
@ -676,15 +788,19 @@ void AES::p_decryptSW(const uint8_t *in, uint8_t *out) const noexcept
t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[53]; t1 = Td0[s1 >> 24U] ^ Td1_r((s0 >> 16U) & m8) ^ Td2_r((s3 >> 8U) & m8) ^ Td3_r(s2 & m8) ^ rk[53];
t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[54]; t2 = Td0[s2 >> 24U] ^ Td1_r((s1 >> 16U) & m8) ^ Td2_r((s0 >> 8U) & m8) ^ Td3_r(s3 & m8) ^ rk[54];
t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[55]; t3 = Td0[s3 >> 24U] ^ Td1_r((s2 >> 16U) & m8) ^ Td2_r((s1 >> 8U) & m8) ^ Td3_r(s0 & m8) ^ rk[55];
s0 = (Td4[t0 >> 24U] << 24U) ^ (Td4[(t3 >> 16U) & m8] << 16U) ^ (Td4[(t2 >> 8U) & m8] << 8U) ^ (Td4[(t1) & m8]) ^ rk[56]; s0 = (Td4[t0 >> 24U] << 24U) ^ (Td4[(t3 >> 16U) & m8] << 16U) ^ (Td4[(t2 >> 8U) & m8] << 8U) ^ (Td4[(t1)&m8])
s1 = (Td4[t1 >> 24U] << 24U) ^ (Td4[(t0 >> 16U) & m8] << 16U) ^ (Td4[(t3 >> 8U) & m8] << 8U) ^ (Td4[(t2) & m8]) ^ rk[57]; ^ rk[56];
s2 = (Td4[t2 >> 24U] << 24U) ^ (Td4[(t1 >> 16U) & m8] << 16U) ^ (Td4[(t0 >> 8U) & m8] << 8U) ^ (Td4[(t3) & m8]) ^ rk[58]; s1 = (Td4[t1 >> 24U] << 24U) ^ (Td4[(t0 >> 16U) & m8] << 16U) ^ (Td4[(t3 >> 8U) & m8] << 8U) ^ (Td4[(t2)&m8])
s3 = (Td4[t3 >> 24U] << 24U) ^ (Td4[(t2 >> 16U) & m8] << 16U) ^ (Td4[(t1 >> 8U) & m8] << 8U) ^ (Td4[(t0) & m8]) ^ rk[59]; ^ rk[57];
s2 = (Td4[t2 >> 24U] << 24U) ^ (Td4[(t1 >> 16U) & m8] << 16U) ^ (Td4[(t0 >> 8U) & m8] << 8U) ^ (Td4[(t3)&m8])
^ rk[58];
s3 = (Td4[t3 >> 24U] << 24U) ^ (Td4[(t2 >> 16U) & m8] << 16U) ^ (Td4[(t1 >> 8U) & m8] << 8U) ^ (Td4[(t0)&m8])
^ rk[59];
Utils::storeBigEndian< uint32_t >(out, s0); Utils::storeBigEndian<uint32_t>(out, s0);
Utils::storeBigEndian< uint32_t >(out + 4, s1); Utils::storeBigEndian<uint32_t>(out + 4, s1);
Utils::storeBigEndian< uint32_t >(out + 8, s2); Utils::storeBigEndian<uint32_t>(out + 8, s2);
Utils::storeBigEndian< uint32_t >(out + 12, s3); Utils::storeBigEndian<uint32_t>(out + 12, s3);
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -15,16 +15,16 @@
#define ZT_AES_HPP #define ZT_AES_HPP
#include "Constants.hpp" #include "Constants.hpp"
#include "Utils.hpp"
#include "SHA512.hpp" #include "SHA512.hpp"
#include "Utils.hpp"
// Uncomment to disable all hardware acceleration (usually for testing) // Uncomment to disable all hardware acceleration (usually for testing)
//#define ZT_AES_NO_ACCEL //#define ZT_AES_NO_ACCEL
#if !defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_X64) #if ! defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_X64)
#define ZT_AES_AESNI 1 #define ZT_AES_AESNI 1
#endif #endif
#if !defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_ARM_HAS_NEON) #if ! defined(ZT_AES_NO_ACCEL) && defined(ZT_ARCH_ARM_HAS_NEON)
#define ZT_AES_NEON 1 #define ZT_AES_NEON 1
#endif #endif
@ -40,9 +40,8 @@ namespace ZeroTier {
* This includes hardware acceleration for certain processors. The software * This includes hardware acceleration for certain processors. The software
* mode is fallback and is significantly slower. * mode is fallback and is significantly slower.
*/ */
class AES class AES {
{ public:
public:
/** /**
* @return True if this system has hardware AES acceleration * @return True if this system has hardware AES acceleration
*/ */
@ -64,39 +63,44 @@ public:
* Create an un-initialized AES instance (must call init() before use) * Create an un-initialized AES instance (must call init() before use)
*/ */
ZT_INLINE AES() noexcept ZT_INLINE AES() noexcept
{} {
}
/** /**
* Create an AES instance with the given key * Create an AES instance with the given key
* *
* @param key 256-bit key * @param key 256-bit key
*/ */
explicit ZT_INLINE AES(const void *const key) noexcept explicit ZT_INLINE AES(const void* const key) noexcept
{ this->init(key); } {
this->init(key);
}
ZT_INLINE ~AES() ZT_INLINE ~AES()
{ Utils::burn(&p_k, sizeof(p_k)); } {
Utils::burn(&p_k, sizeof(p_k));
}
/** /**
* Set (or re-set) this AES256 cipher's key * Set (or re-set) this AES256 cipher's key
* *
* @param key 256-bit / 32-byte key * @param key 256-bit / 32-byte key
*/ */
ZT_INLINE void init(const void *const key) noexcept ZT_INLINE void init(const void* const key) noexcept
{ {
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
if (likely(Utils::CPUID.aes)) { if (likely(Utils::CPUID.aes)) {
p_init_aesni(reinterpret_cast<const uint8_t *>(key)); p_init_aesni(reinterpret_cast<const uint8_t*>(key));
return; return;
} }
#endif #endif
#ifdef ZT_AES_NEON #ifdef ZT_AES_NEON
if (Utils::ARMCAP.aes) { if (Utils::ARMCAP.aes) {
p_init_armneon_crypto(reinterpret_cast<const uint8_t *>(key)); p_init_armneon_crypto(reinterpret_cast<const uint8_t*>(key));
return; return;
} }
#endif #endif
p_initSW(reinterpret_cast<const uint8_t *>(key)); p_initSW(reinterpret_cast<const uint8_t*>(key));
} }
/** /**
@ -105,7 +109,7 @@ public:
* @param in Input block * @param in Input block
* @param out Output block (can be same as input) * @param out Output block (can be same as input)
*/ */
ZT_INLINE void encrypt(const void *const in, void *const out) const noexcept ZT_INLINE void encrypt(const void* const in, void* const out) const noexcept
{ {
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
if (likely(Utils::CPUID.aes)) { if (likely(Utils::CPUID.aes)) {
@ -119,7 +123,7 @@ public:
return; return;
} }
#endif #endif
p_encryptSW(reinterpret_cast<const uint8_t *>(in), reinterpret_cast<uint8_t *>(out)); p_encryptSW(reinterpret_cast<const uint8_t*>(in), reinterpret_cast<uint8_t*>(out));
} }
/** /**
@ -128,7 +132,7 @@ public:
* @param in Input block * @param in Input block
* @param out Output block (can be same as input) * @param out Output block (can be same as input)
*/ */
ZT_INLINE void decrypt(const void *const in, void *const out) const noexcept ZT_INLINE void decrypt(const void* const in, void* const out) const noexcept
{ {
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
if (likely(Utils::CPUID.aes)) { if (likely(Utils::CPUID.aes)) {
@ -142,7 +146,7 @@ public:
return; return;
} }
#endif #endif
p_decryptSW(reinterpret_cast<const uint8_t *>(in), reinterpret_cast<uint8_t *>(out)); p_decryptSW(reinterpret_cast<const uint8_t*>(in), reinterpret_cast<uint8_t*>(out));
} }
class GMACSIVEncryptor; class GMACSIVEncryptor;
@ -151,8 +155,7 @@ public:
/** /**
* Streaming GMAC calculator * Streaming GMAC calculator
*/ */
class GMAC class GMAC {
{
friend class GMACSIVEncryptor; friend class GMACSIVEncryptor;
friend class GMACSIVDecryptor; friend class GMACSIVDecryptor;
@ -178,8 +181,9 @@ public:
* *
* @param aes Keyed AES instance to use * @param aes Keyed AES instance to use
*/ */
ZT_INLINE GMAC(const AES &aes) : _aes(aes) ZT_INLINE GMAC(const AES& aes) : _aes(aes)
{} {
}
/** /**
* Reset and initialize for a new GMAC calculation * Reset and initialize for a new GMAC calculation
@ -195,9 +199,9 @@ public:
// this would hold the counter, but we're not doing GCM just GMAC. That means the // this would hold the counter, but we're not doing GCM just GMAC. That means the
// counter always stays just 1. // counter always stays just 1.
#ifdef ZT_AES_AESNI // also implies an x64 processor #ifdef ZT_AES_AESNI // also implies an x64 processor
*reinterpret_cast<uint64_t *>(_iv) = *reinterpret_cast<const uint64_t *>(iv); *reinterpret_cast<uint64_t*>(_iv) = *reinterpret_cast<const uint64_t*>(iv);
*reinterpret_cast<uint32_t *>(_iv + 8) = *reinterpret_cast<const uint64_t *>(iv + 8); *reinterpret_cast<uint32_t*>(_iv + 8) = *reinterpret_cast<const uint64_t*>(iv + 8);
*reinterpret_cast<uint32_t *>(_iv + 12) = 0x01000000; // 0x00000001 in big-endian byte order *reinterpret_cast<uint32_t*>(_iv + 12) = 0x01000000; // 0x00000001 in big-endian byte order
#else #else
Utils::copy<12>(_iv, iv); Utils::copy<12>(_iv, iv);
_iv[12] = 0; _iv[12] = 0;
@ -216,7 +220,7 @@ public:
* @param data Bytes to process * @param data Bytes to process
* @param len Length of input * @param len Length of input
*/ */
void update(const void *data, unsigned int len) noexcept; void update(const void* data, unsigned int len) noexcept;
/** /**
* Process any remaining cached bytes and generate tag * Process any remaining cached bytes and generate tag
@ -229,14 +233,14 @@ public:
private: private:
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
void p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept; void p_aesNIUpdate(const uint8_t* in, unsigned int len) noexcept;
void p_aesNIFinish(uint8_t tag[16]) noexcept; void p_aesNIFinish(uint8_t tag[16]) noexcept;
#endif #endif
#ifdef ZT_AES_NEON #ifdef ZT_AES_NEON
void p_armUpdate(const uint8_t *in, unsigned int len) noexcept; void p_armUpdate(const uint8_t* in, unsigned int len) noexcept;
void p_armFinish(uint8_t tag[16]) noexcept; void p_armFinish(uint8_t tag[16]) noexcept;
#endif #endif
const AES &_aes; const AES& _aes;
unsigned int _rp; unsigned int _rp;
unsigned int _len; unsigned int _len;
uint8_t _r[16]; // remainder uint8_t _r[16]; // remainder
@ -251,14 +255,14 @@ public:
* We will never encrypt more than a tiny fraction of 2^32 blocks, so this is left out as * We will never encrypt more than a tiny fraction of 2^32 blocks, so this is left out as
* an optimization. * an optimization.
*/ */
class CTR class CTR {
{
friend class GMACSIVEncryptor; friend class GMACSIVEncryptor;
friend class GMACSIVDecryptor; friend class GMACSIVDecryptor;
public: public:
ZT_INLINE CTR(const AES &aes) noexcept: _aes(aes) ZT_INLINE CTR(const AES& aes) noexcept : _aes(aes)
{} {
}
/** /**
* Initialize this CTR instance to encrypt a new stream * Initialize this CTR instance to encrypt a new stream
@ -266,10 +270,10 @@ public:
* @param iv Unique initialization vector and initial 32-bit counter (least significant 32 bits, big-endian) * @param iv Unique initialization vector and initial 32-bit counter (least significant 32 bits, big-endian)
* @param output Buffer to which to store output (MUST be large enough for total bytes processed!) * @param output Buffer to which to store output (MUST be large enough for total bytes processed!)
*/ */
ZT_INLINE void init(const uint8_t iv[16], void *const output) noexcept ZT_INLINE void init(const uint8_t iv[16], void* const output) noexcept
{ {
Utils::copy< 16 >(_ctr, iv); Utils::copy<16>(_ctr, iv);
_out = reinterpret_cast<uint8_t *>(output); _out = reinterpret_cast<uint8_t*>(output);
_len = 0; _len = 0;
} }
@ -280,11 +284,11 @@ public:
* @param ic Initial counter (must be in big-endian byte order!) * @param ic Initial counter (must be in big-endian byte order!)
* @param output Buffer to which to store output (MUST be large enough for total bytes processed!) * @param output Buffer to which to store output (MUST be large enough for total bytes processed!)
*/ */
ZT_INLINE void init(const uint8_t iv[12], const uint32_t ic, void *const output) noexcept ZT_INLINE void init(const uint8_t iv[12], const uint32_t ic, void* const output) noexcept
{ {
Utils::copy< 12 >(_ctr, iv); Utils::copy<12>(_ctr, iv);
reinterpret_cast<uint32_t *>(_ctr)[3] = ic; reinterpret_cast<uint32_t*>(_ctr)[3] = ic;
_out = reinterpret_cast<uint8_t *>(output); _out = reinterpret_cast<uint8_t*>(output);
_len = 0; _len = 0;
} }
@ -294,7 +298,7 @@ public:
* @param input Input data * @param input Input data
* @param len Length of input * @param len Length of input
*/ */
void crypt(const void *input, unsigned int len) noexcept; void crypt(const void* input, unsigned int len) noexcept;
/** /**
* Finish any remaining bytes if total bytes processed wasn't a multiple of 16 * Finish any remaining bytes if total bytes processed wasn't a multiple of 16
@ -305,14 +309,14 @@ public:
private: private:
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
void p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept; void p_aesNICrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept;
#endif #endif
#ifdef ZT_AES_NEON #ifdef ZT_AES_NEON
void p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept; void p_armCrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept;
#endif #endif
const AES &_aes; const AES& _aes;
uint64_t _ctr[2]; uint64_t _ctr[2];
uint8_t *_out; uint8_t* _out;
unsigned int _len; unsigned int _len;
}; };
@ -327,8 +331,7 @@ public:
* This supports encryption of a maximum of 2^31 bytes of data per * This supports encryption of a maximum of 2^31 bytes of data per
* call to init(). * call to init().
*/ */
class GMACSIVEncryptor class GMACSIVEncryptor {
{
public: public:
/** /**
* Create a new AES-GMAC-SIV encryptor keyed with the provided AES instances * Create a new AES-GMAC-SIV encryptor keyed with the provided AES instances
@ -336,10 +339,11 @@ public:
* @param k0 First of two AES instances keyed with K0 * @param k0 First of two AES instances keyed with K0
* @param k1 Second of two AES instances keyed with K1 * @param k1 Second of two AES instances keyed with K1
*/ */
ZT_INLINE GMACSIVEncryptor(const AES &k0, const AES &k1) noexcept : ZT_INLINE GMACSIVEncryptor(const AES& k0, const AES& k1) noexcept
_gmac(k0), : _gmac(k0)
_ctr(k1) , _ctr(k1)
{} {
}
/** /**
* Initialize AES-GMAC-SIV * Initialize AES-GMAC-SIV
@ -347,7 +351,7 @@ public:
* @param iv IV in network byte order (byte order in which it will appear on the wire) * @param iv IV in network byte order (byte order in which it will appear on the wire)
* @param output Pointer to buffer to receive ciphertext, must be large enough for all to-be-processed data! * @param output Pointer to buffer to receive ciphertext, must be large enough for all to-be-processed data!
*/ */
ZT_INLINE void init(const uint64_t iv, void *const output) noexcept ZT_INLINE void init(const uint64_t iv, void* const output) noexcept
{ {
// Output buffer to receive the result of AES-CTR encryption. // Output buffer to receive the result of AES-CTR encryption.
_output = output; _output = output;
@ -355,7 +359,7 @@ public:
// Initialize GMAC with 64-bit IV (and remaining 32 bits padded to zero). // Initialize GMAC with 64-bit IV (and remaining 32 bits padded to zero).
_tag[0] = iv; _tag[0] = iv;
_tag[1] = 0; _tag[1] = 0;
_gmac.init(reinterpret_cast<const uint8_t *>(_tag)); _gmac.init(reinterpret_cast<const uint8_t*>(_tag));
} }
/** /**
@ -368,7 +372,7 @@ public:
* @param aad Additional authenticated data * @param aad Additional authenticated data
* @param len Length of AAD in bytes * @param len Length of AAD in bytes
*/ */
ZT_INLINE void aad(const void *const aad, unsigned int len) noexcept ZT_INLINE void aad(const void* const aad, unsigned int len) noexcept
{ {
// Feed ADD into GMAC first // Feed ADD into GMAC first
_gmac.update(aad, len); _gmac.update(aad, len);
@ -385,8 +389,10 @@ public:
* @param input Plaintext chunk * @param input Plaintext chunk
* @param len Length of plaintext chunk * @param len Length of plaintext chunk
*/ */
ZT_INLINE void update1(const void *const input, const unsigned int len) noexcept ZT_INLINE void update1(const void* const input, const unsigned int len) noexcept
{ _gmac.update(input, len); } {
_gmac.update(input, len);
}
/** /**
* Finish first pass, compute CTR IV, initialize second pass. * Finish first pass, compute CTR IV, initialize second pass.
@ -395,7 +401,7 @@ public:
{ {
// Compute 128-bit GMAC tag. // Compute 128-bit GMAC tag.
uint64_t tmp[2]; uint64_t tmp[2];
_gmac.finish(reinterpret_cast<uint8_t *>(tmp)); _gmac.finish(reinterpret_cast<uint8_t*>(tmp));
// Shorten to 64 bits, concatenate with message IV, and encrypt with AES to // Shorten to 64 bits, concatenate with message IV, and encrypt with AES to
// yield the CTR IV and opaque IV/MAC blob. In ZeroTier's use of GMAC-SIV // yield the CTR IV and opaque IV/MAC blob. In ZeroTier's use of GMAC-SIV
@ -415,7 +421,7 @@ public:
// and so 2^31 should be considered the input limit. // and so 2^31 should be considered the input limit.
tmp[0] = _tag[0]; tmp[0] = _tag[0];
tmp[1] = _tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL); tmp[1] = _tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL);
_ctr.init(reinterpret_cast<const uint8_t *>(tmp), _output); _ctr.init(reinterpret_cast<const uint8_t*>(tmp), _output);
} }
/** /**
@ -428,8 +434,10 @@ public:
* @param input Plaintext chunk * @param input Plaintext chunk
* @param len Length of plaintext chunk * @param len Length of plaintext chunk
*/ */
ZT_INLINE void update2(const void *const input, const unsigned int len) noexcept ZT_INLINE void update2(const void* const input, const unsigned int len) noexcept
{ _ctr.crypt(input, len); } {
_ctr.crypt(input, len);
}
/** /**
* Finish second pass and return a pointer to the opaque 128-bit IV+MAC block * Finish second pass and return a pointer to the opaque 128-bit IV+MAC block
@ -439,14 +447,14 @@ public:
* *
* @return Pointer to 128-bit opaque IV+MAC (packed into two 64-bit integers) * @return Pointer to 128-bit opaque IV+MAC (packed into two 64-bit integers)
*/ */
ZT_INLINE const uint64_t *finish2() ZT_INLINE const uint64_t* finish2()
{ {
_ctr.finish(); _ctr.finish();
return _tag; return _tag;
} }
private: private:
void *_output; void* _output;
uint64_t _tag[2]; uint64_t _tag[2];
AES::GMAC _gmac; AES::GMAC _gmac;
AES::CTR _ctr; AES::CTR _ctr;
@ -457,13 +465,13 @@ public:
* *
* GMAC-SIV decryption is single-pass. AAD (if any) must be processed first. * GMAC-SIV decryption is single-pass. AAD (if any) must be processed first.
*/ */
class GMACSIVDecryptor class GMACSIVDecryptor {
{
public: public:
ZT_INLINE GMACSIVDecryptor(const AES &k0, const AES &k1) noexcept: ZT_INLINE GMACSIVDecryptor(const AES& k0, const AES& k1) noexcept
_ctr(k1), : _ctr(k1)
_gmac(k0) , _gmac(k0)
{} {
}
/** /**
* Initialize decryptor for a new message * Initialize decryptor for a new message
@ -471,18 +479,18 @@ public:
* @param tag 128-bit combined IV/MAC originally created by GMAC-SIV encryption * @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!) * @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 ZT_INLINE void init(const uint64_t tag[2], void* const output) noexcept
{ {
uint64_t tmp[2]; uint64_t tmp[2];
tmp[0] = tag[0]; tmp[0] = tag[0];
tmp[1] = tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL); tmp[1] = tag[1] & ZT_CONST_TO_BE_UINT64(0xffffffff7fffffffULL);
_ctr.init(reinterpret_cast<const uint8_t *>(tmp), output); _ctr.init(reinterpret_cast<const uint8_t*>(tmp), output);
_ctr._aes.decrypt(tag, _ivMac); _ctr._aes.decrypt(tag, _ivMac);
tmp[0] = _ivMac[0]; tmp[0] = _ivMac[0];
tmp[1] = 0; tmp[1] = 0;
_gmac.init(reinterpret_cast<const uint8_t *>(tmp)); _gmac.init(reinterpret_cast<const uint8_t*>(tmp));
_output = output; _output = output;
_decryptedLen = 0; _decryptedLen = 0;
@ -494,7 +502,7 @@ public:
* @param aad Additional authenticated data * @param aad Additional authenticated data
* @param len Length of AAD in bytes * @param len Length of AAD in bytes
*/ */
ZT_INLINE void aad(const void *const aad, unsigned int len) noexcept ZT_INLINE void aad(const void* const aad, unsigned int len) noexcept
{ {
_gmac.update(aad, len); _gmac.update(aad, len);
len &= 0xfU; len &= 0xfU;
@ -510,7 +518,7 @@ public:
* @param input Input ciphertext * @param input Input ciphertext
* @param len Length of ciphertext * @param len Length of ciphertext
*/ */
ZT_INLINE void update(const void *const input, const unsigned int len) noexcept ZT_INLINE void update(const void* const input, const unsigned int len) noexcept
{ {
_ctr.crypt(input, len); _ctr.crypt(input, len);
_decryptedLen += len; _decryptedLen += len;
@ -527,7 +535,7 @@ public:
uint64_t gmacTag[2]; uint64_t gmacTag[2];
_gmac.update(_output, _decryptedLen); _gmac.update(_output, _decryptedLen);
_gmac.finish(reinterpret_cast<uint8_t *>(gmacTag)); _gmac.finish(reinterpret_cast<uint8_t*>(gmacTag));
return (gmacTag[0] ^ gmacTag[1]) == _ivMac[1]; return (gmacTag[0] ^ gmacTag[1]) == _ivMac[1];
} }
@ -535,26 +543,24 @@ public:
uint64_t _ivMac[2]; uint64_t _ivMac[2];
AES::CTR _ctr; AES::CTR _ctr;
AES::GMAC _gmac; AES::GMAC _gmac;
void *_output; void* _output;
unsigned int _decryptedLen; unsigned int _decryptedLen;
}; };
private: private:
static const uint32_t Te0[256]; static const uint32_t Te0[256];
static const uint32_t Te4[256]; static const uint32_t Te4[256];
static const uint32_t Td0[256]; static const uint32_t Td0[256];
static const uint8_t Td4[256]; static const uint8_t Td4[256];
static const uint32_t rcon[15]; static const uint32_t rcon[15];
void p_initSW(const uint8_t *key) noexcept; void p_initSW(const uint8_t* key) noexcept;
void p_encryptSW(const uint8_t *in, uint8_t *out) const noexcept; void p_encryptSW(const uint8_t* in, uint8_t* out) const noexcept;
void p_decryptSW(const uint8_t *in, uint8_t *out) const noexcept; void p_decryptSW(const uint8_t* in, uint8_t* out) const noexcept;
union union {
{
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
struct struct {
{
__m128i k[28]; __m128i k[28];
__m128i h[4]; // h, hh, hhh, hhhh __m128i h[4]; // h, hh, hhh, hhhh
__m128i h2[4]; // _mm_xor_si128(_mm_shuffle_epi32(h, 78), h), etc. __m128i h2[4]; // _mm_xor_si128(_mm_shuffle_epi32(h, 78), h), etc.
@ -562,8 +568,7 @@ private:
#endif #endif
#ifdef ZT_AES_NEON #ifdef ZT_AES_NEON
struct struct {
{
uint64_t hsw[2]; // in case it has AES but not PMULL, not sure if that ever happens uint64_t hsw[2]; // in case it has AES but not PMULL, not sure if that ever happens
uint8x16_t ek[15]; uint8x16_t ek[15];
uint8x16_t dk[15]; uint8x16_t dk[15];
@ -571,8 +576,7 @@ private:
} neon; } neon;
#endif #endif
struct struct {
{
uint64_t h[2]; uint64_t h[2];
uint32_t ek[60]; uint32_t ek[60];
uint32_t dk[60]; uint32_t dk[60];
@ -580,15 +584,15 @@ private:
} p_k; } p_k;
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
void p_init_aesni(const uint8_t *key) noexcept; void p_init_aesni(const uint8_t* key) noexcept;
void p_encrypt_aesni(const void *in, void *out) const noexcept; void p_encrypt_aesni(const void* in, void* out) const noexcept;
void p_decrypt_aesni(const void *in, void *out) const noexcept; void p_decrypt_aesni(const void* in, void* out) const noexcept;
#endif #endif
#ifdef ZT_AES_NEON #ifdef ZT_AES_NEON
void p_init_armneon_crypto(const uint8_t *key) noexcept; void p_init_armneon_crypto(const uint8_t* key) noexcept;
void p_encrypt_armneon_crypto(const void *in, void *out) const noexcept; void p_encrypt_armneon_crypto(const void* in, void* out) const noexcept;
void p_decrypt_armneon_crypto(const void *in, void *out) const noexcept; void p_decrypt_armneon_crypto(const void* in, void* out) const noexcept;
#endif #endif
}; };

View file

@ -14,8 +14,8 @@
// AES for X64 AES-NI extensions (no 32-bit X86 support). Supports AVX2 and // AES for X64 AES-NI extensions (no 32-bit X86 support). Supports AVX2 and
// AVX512 VAES for performance in excess of 10GiB/sec/core on newer chips. // AVX512 VAES for performance in excess of 10GiB/sec/core on newer chips.
#include "Constants.hpp"
#include "AES.hpp" #include "AES.hpp"
#include "Constants.hpp"
#ifdef ZT_AES_AESNI #ifdef ZT_AES_AESNI
@ -32,7 +32,8 @@ const __m128i s_sseSwapBytes = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11
#ifdef __GNUC__ #ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul"))) __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul")))
#endif #endif
__m128i p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept __m128i
p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept
{ {
y = _mm_shuffle_epi8(y, s_sseSwapBytes); y = _mm_shuffle_epi8(y, s_sseSwapBytes);
__m128i t1 = _mm_clmulepi64_si128(h, y, 0x00); __m128i t1 = _mm_clmulepi64_si128(h, y, 0x00);
@ -46,10 +47,16 @@ __m128i p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept
t4 = _mm_xor_si128(t4, t2); t4 = _mm_xor_si128(t4, t2);
__m128i t5 = _mm_srli_epi32(t1, 31); __m128i t5 = _mm_srli_epi32(t1, 31);
t1 = _mm_or_si128(_mm_slli_epi32(t1, 1), _mm_slli_si128(t5, 4)); t1 = _mm_or_si128(_mm_slli_epi32(t1, 1), _mm_slli_si128(t5, 4));
t4 = _mm_or_si128(_mm_or_si128(_mm_slli_epi32(t4, 1), _mm_slli_si128(_mm_srli_epi32(t4, 31), 4)), _mm_srli_si128(t5, 12)); t4 = _mm_or_si128(
_mm_or_si128(_mm_slli_epi32(t4, 1), _mm_slli_si128(_mm_srli_epi32(t4, 31), 4)),
_mm_srli_si128(t5, 12));
t5 = _mm_xor_si128(_mm_xor_si128(_mm_slli_epi32(t1, 31), _mm_slli_epi32(t1, 30)), _mm_slli_epi32(t1, 25)); t5 = _mm_xor_si128(_mm_xor_si128(_mm_slli_epi32(t1, 31), _mm_slli_epi32(t1, 30)), _mm_slli_epi32(t1, 25));
t1 = _mm_xor_si128(t1, _mm_slli_si128(t5, 12)); t1 = _mm_xor_si128(t1, _mm_slli_si128(t5, 12));
t4 = _mm_xor_si128(_mm_xor_si128(_mm_xor_si128(_mm_xor_si128(_mm_xor_si128(t4, _mm_srli_si128(t5, 4)), t1), _mm_srli_epi32(t1, 2)), _mm_srli_epi32(t1, 7)), _mm_srli_epi32(t1, 1)); t4 = _mm_xor_si128(
_mm_xor_si128(
_mm_xor_si128(_mm_xor_si128(_mm_xor_si128(t4, _mm_srli_si128(t5, 4)), t1), _mm_srli_epi32(t1, 2)),
_mm_srli_epi32(t1, 7)),
_mm_srli_epi32(t1, 1));
return _mm_shuffle_epi8(t4, s_sseSwapBytes); return _mm_shuffle_epi8(t4, s_sseSwapBytes);
} }
@ -58,7 +65,7 @@ __m128i p_gmacPCLMUL128(const __m128i h, __m128i y) noexcept
* The performance gain can be significant but regular SSE is already so * The performance gain can be significant but regular SSE is already so
* fast it's highly unlikely to be a rate limiting factor except on massive * fast it's highly unlikely to be a rate limiting factor except on massive
* servers and network infrastructure stuff. */ * servers and network infrastructure stuff. */
#if !defined(__WINDOWS__) && ((__GNUC__ >= 8) || (__clang_major__ >= 7)) #if ! defined(__WINDOWS__) && ((__GNUC__ >= 8) || (__clang_major__ >= 7))
#define ZT_AES_VAES512 1 #define ZT_AES_VAES512 1
@ -83,12 +90,16 @@ void p_aesCtrInnerVAES512(unsigned int &len, const uint64_t c0, uint64_t &c1, co
const __m512i kk13 = _mm512_broadcast_i32x4(k[13]); const __m512i kk13 = _mm512_broadcast_i32x4(k[13]);
const __m512i kk14 = _mm512_broadcast_i32x4(k[14]); const __m512i kk14 = _mm512_broadcast_i32x4(k[14]);
do { do {
__m512i p0 = _mm512_loadu_si512(reinterpret_cast<const __m512i *>(in)); __m512i p0 = _mm512_loadu_si512(reinterpret_cast<const __m512i*>(in));
__m512i d0 = _mm512_set_epi64( __m512i d0 = _mm512_set_epi64(
(long long)Utils::hton(c1 + 3ULL), (long long)c0, (long long)Utils::hton(c1 + 3ULL),
(long long)Utils::hton(c1 + 2ULL), (long long)c0, (long long)c0,
(long long)Utils::hton(c1 + 1ULL), (long long)c0, (long long)Utils::hton(c1 + 2ULL),
(long long)Utils::hton(c1), (long long)c0); (long long)c0,
(long long)Utils::hton(c1 + 1ULL),
(long long)c0,
(long long)Utils::hton(c1),
(long long)c0);
c1 += 4; c1 += 4;
in += 64; in += 64;
len -= 64; len -= 64;
@ -107,7 +118,7 @@ void p_aesCtrInnerVAES512(unsigned int &len, const uint64_t c0, uint64_t &c1, co
d0 = _mm512_aesenc_epi128(d0, kk12); d0 = _mm512_aesenc_epi128(d0, kk12);
d0 = _mm512_aesenc_epi128(d0, kk13); d0 = _mm512_aesenc_epi128(d0, kk13);
d0 = _mm512_aesenclast_epi128(d0, kk14); d0 = _mm512_aesenclast_epi128(d0, kk14);
_mm512_storeu_si512(reinterpret_cast<__m512i *>(out), _mm512_xor_si512(p0, d0)); _mm512_storeu_si512(reinterpret_cast<__m512i*>(out), _mm512_xor_si512(p0, d0));
out += 64; out += 64;
} while (likely(len >= 64)); } while (likely(len >= 64));
} }
@ -135,14 +146,18 @@ void p_aesCtrInnerVAES256(unsigned int &len, const uint64_t c0, uint64_t &c1, co
const __m256i kk13 = _mm256_broadcastsi128_si256(k[13]); const __m256i kk13 = _mm256_broadcastsi128_si256(k[13]);
const __m256i kk14 = _mm256_broadcastsi128_si256(k[14]); const __m256i kk14 = _mm256_broadcastsi128_si256(k[14]);
do { do {
__m256i p0 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(in)); __m256i p0 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(in));
__m256i p1 = _mm256_loadu_si256(reinterpret_cast<const __m256i *>(in + 32)); __m256i p1 = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(in + 32));
__m256i d0 = _mm256_set_epi64x( __m256i d0 = _mm256_set_epi64x(
(long long)Utils::hton(c1 + 1ULL), (long long)c0, (long long)Utils::hton(c1 + 1ULL),
(long long)Utils::hton(c1), (long long)c0); (long long)c0,
(long long)Utils::hton(c1),
(long long)c0);
__m256i d1 = _mm256_set_epi64x( __m256i d1 = _mm256_set_epi64x(
(long long)Utils::hton(c1 + 3ULL), (long long)c0, (long long)Utils::hton(c1 + 3ULL),
(long long)Utils::hton(c1 + 2ULL), (long long)c0); (long long)c0,
(long long)Utils::hton(c1 + 2ULL),
(long long)c0);
c1 += 4; c1 += 4;
in += 64; in += 64;
len -= 64; len -= 64;
@ -176,8 +191,8 @@ void p_aesCtrInnerVAES256(unsigned int &len, const uint64_t c0, uint64_t &c1, co
d1 = _mm256_aesenc_epi128(d1, kk13); d1 = _mm256_aesenc_epi128(d1, kk13);
d0 = _mm256_aesenclast_epi128(d0, kk14); d0 = _mm256_aesenclast_epi128(d0, kk14);
d1 = _mm256_aesenclast_epi128(d1, kk14); d1 = _mm256_aesenclast_epi128(d1, kk14);
_mm256_storeu_si256(reinterpret_cast<__m256i *>(out), _mm256_xor_si256(d0, p0)); _mm256_storeu_si256(reinterpret_cast<__m256i*>(out), _mm256_xor_si256(d0, p0));
_mm256_storeu_si256(reinterpret_cast<__m256i *>(out + 32), _mm256_xor_si256(d1, p1)); _mm256_storeu_si256(reinterpret_cast<__m256i*>(out + 32), _mm256_xor_si256(d1, p1));
out += 64; out += 64;
} while (likely(len >= 64)); } while (likely(len >= 64));
} }
@ -187,7 +202,8 @@ void p_aesCtrInnerVAES256(unsigned int &len, const uint64_t c0, uint64_t &c1, co
#ifdef __GNUC__ #ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul"))) __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif #endif
__m128i p_init256_1_aesni(__m128i a, __m128i b) noexcept __m128i
p_init256_1_aesni(__m128i a, __m128i b) noexcept
{ {
__m128i x, y; __m128i x, y;
b = _mm_shuffle_epi32(b, 0xff); b = _mm_shuffle_epi32(b, 0xff);
@ -204,7 +220,8 @@ __m128i p_init256_1_aesni(__m128i a, __m128i b) noexcept
#ifdef __GNUC__ #ifdef __GNUC__
__attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul"))) __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif #endif
__m128i p_init256_2_aesni(__m128i a, __m128i b) noexcept __m128i
p_init256_2_aesni(__m128i a, __m128i b) noexcept
{ {
__m128i x, y, z; __m128i x, y, z;
y = _mm_aeskeygenassist_si128(a, 0x00); y = _mm_aeskeygenassist_si128(a, 0x00);
@ -226,17 +243,19 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul")))
#endif #endif
void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept
{ {
__m128i y = _mm_loadu_si128(reinterpret_cast<const __m128i *>(_y)); __m128i y = _mm_loadu_si128(reinterpret_cast<const __m128i*>(_y));
// Handle anything left over from a previous run that wasn't a multiple of 16 bytes. // Handle anything left over from a previous run that wasn't a multiple of 16 bytes.
if (_rp) { if (_rp) {
for (;;) { for (;;) {
if (!len) if (! len)
return; return;
--len; --len;
_r[_rp++] = *(in++); _r[_rp++] = *(in++);
if (_rp == 16) { if (_rp == 16) {
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i *>(_r)))); y = p_gmacPCLMUL128(
_aes.p_k.ni.h[0],
_mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i*>(_r))));
break; break;
} }
} }
@ -252,36 +271,56 @@ void AES::GMAC::p_aesNIUpdate(const uint8_t *in, unsigned int len) noexcept
const __m128i hh2 = _aes.p_k.ni.h2[1]; const __m128i hh2 = _aes.p_k.ni.h2[1];
const __m128i hhh2 = _aes.p_k.ni.h2[2]; const __m128i hhh2 = _aes.p_k.ni.h2[2];
const __m128i hhhh2 = _aes.p_k.ni.h2[3]; const __m128i hhhh2 = _aes.p_k.ni.h2[3];
const uint8_t *const end64 = in + (len & ~((unsigned int)63)); const uint8_t* const end64 = in + (len & ~((unsigned int)63));
len &= 63U; len &= 63U;
do { do {
__m128i d1 = _mm_shuffle_epi8(_mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<const __m128i *>(in))), sb); __m128i d1 = _mm_shuffle_epi8(_mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<const __m128i*>(in))), sb);
__m128i d2 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 16)), sb); __m128i d2 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 16)), sb);
__m128i d3 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 32)), sb); __m128i d3 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 32)), sb);
__m128i d4 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 48)), sb); __m128i d4 = _mm_shuffle_epi8(_mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 48)), sb);
in += 64; in += 64;
__m128i a = _mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x00), _mm_clmulepi64_si128(hhh, d2, 0x00)), _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x00), _mm_clmulepi64_si128(h, d4, 0x00))); __m128i a = _mm_xor_si128(
__m128i b = _mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x11), _mm_clmulepi64_si128(hhh, d2, 0x11)), _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x11), _mm_clmulepi64_si128(h, d4, 0x11))); _mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x00), _mm_clmulepi64_si128(hhh, d2, 0x00)),
__m128i c = _mm_xor_si128(_mm_xor_si128(_mm_xor_si128(_mm_clmulepi64_si128(hhhh2, _mm_xor_si128(_mm_shuffle_epi32(d1, 78), d1), 0x00), _mm_clmulepi64_si128(hhh2, _mm_xor_si128(_mm_shuffle_epi32(d2, 78), d2), 0x00)), _mm_xor_si128(_mm_clmulepi64_si128(hh2, _mm_xor_si128(_mm_shuffle_epi32(d3, 78), d3), 0x00), _mm_clmulepi64_si128(h2, _mm_xor_si128(_mm_shuffle_epi32(d4, 78), d4), 0x00))), _mm_xor_si128(a, b)); _mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x00), _mm_clmulepi64_si128(h, d4, 0x00)));
__m128i b = _mm_xor_si128(
_mm_xor_si128(_mm_clmulepi64_si128(hhhh, d1, 0x11), _mm_clmulepi64_si128(hhh, d2, 0x11)),
_mm_xor_si128(_mm_clmulepi64_si128(hh, d3, 0x11), _mm_clmulepi64_si128(h, d4, 0x11)));
__m128i c = _mm_xor_si128(
_mm_xor_si128(
_mm_xor_si128(
_mm_clmulepi64_si128(hhhh2, _mm_xor_si128(_mm_shuffle_epi32(d1, 78), d1), 0x00),
_mm_clmulepi64_si128(hhh2, _mm_xor_si128(_mm_shuffle_epi32(d2, 78), d2), 0x00)),
_mm_xor_si128(
_mm_clmulepi64_si128(hh2, _mm_xor_si128(_mm_shuffle_epi32(d3, 78), d3), 0x00),
_mm_clmulepi64_si128(h2, _mm_xor_si128(_mm_shuffle_epi32(d4, 78), d4), 0x00))),
_mm_xor_si128(a, b));
a = _mm_xor_si128(_mm_slli_si128(c, 8), a); a = _mm_xor_si128(_mm_slli_si128(c, 8), a);
b = _mm_xor_si128(_mm_srli_si128(c, 8), b); b = _mm_xor_si128(_mm_srli_si128(c, 8), b);
c = _mm_srli_epi32(a, 31); c = _mm_srli_epi32(a, 31);
a = _mm_or_si128(_mm_slli_epi32(a, 1), _mm_slli_si128(c, 4)); a = _mm_or_si128(_mm_slli_epi32(a, 1), _mm_slli_si128(c, 4));
b = _mm_or_si128(_mm_or_si128(_mm_slli_epi32(b, 1), _mm_slli_si128(_mm_srli_epi32(b, 31), 4)), _mm_srli_si128(c, 12)); b = _mm_or_si128(
_mm_or_si128(_mm_slli_epi32(b, 1), _mm_slli_si128(_mm_srli_epi32(b, 31), 4)),
_mm_srli_si128(c, 12));
c = _mm_xor_si128(_mm_slli_epi32(a, 31), _mm_xor_si128(_mm_slli_epi32(a, 30), _mm_slli_epi32(a, 25))); c = _mm_xor_si128(_mm_slli_epi32(a, 31), _mm_xor_si128(_mm_slli_epi32(a, 30), _mm_slli_epi32(a, 25)));
a = _mm_xor_si128(a, _mm_slli_si128(c, 12)); a = _mm_xor_si128(a, _mm_slli_si128(c, 12));
b = _mm_xor_si128(b, _mm_xor_si128(a, _mm_xor_si128(_mm_xor_si128(_mm_srli_epi32(a, 1), _mm_srli_si128(c, 4)), _mm_xor_si128(_mm_srli_epi32(a, 2), _mm_srli_epi32(a, 7))))); b = _mm_xor_si128(
b,
_mm_xor_si128(
a,
_mm_xor_si128(
_mm_xor_si128(_mm_srli_epi32(a, 1), _mm_srli_si128(c, 4)),
_mm_xor_si128(_mm_srli_epi32(a, 2), _mm_srli_epi32(a, 7)))));
y = _mm_shuffle_epi8(b, sb); y = _mm_shuffle_epi8(b, sb);
} while (likely(in != end64)); } while (likely(in != end64));
} }
while (len >= 16) { while (len >= 16) {
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)))); y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<const __m128i*>(in))));
in += 16; in += 16;
len -= 16; len -= 16;
} }
_mm_storeu_si128(reinterpret_cast<__m128i *>(_y), y); _mm_storeu_si128(reinterpret_cast<__m128i*>(_y), y);
// Any overflow is cached for a later run or finish(). // Any overflow is cached for a later run or finish().
for (unsigned int i = 0; i < len; ++i) for (unsigned int i = 0; i < len; ++i)
@ -294,22 +333,22 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,pclmul,aes")))
#endif #endif
void AES::GMAC::p_aesNIFinish(uint8_t tag[16]) noexcept void AES::GMAC::p_aesNIFinish(uint8_t tag[16]) noexcept
{ {
__m128i y = _mm_loadu_si128(reinterpret_cast<const __m128i *>(_y)); __m128i y = _mm_loadu_si128(reinterpret_cast<const __m128i*>(_y));
// Handle any remaining bytes, padding the last block with zeroes. // Handle any remaining bytes, padding the last block with zeroes.
if (_rp) { if (_rp) {
while (_rp < 16) while (_rp < 16)
_r[_rp++] = 0; _r[_rp++] = 0;
y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i *>(_r)))); y = p_gmacPCLMUL128(_aes.p_k.ni.h[0], _mm_xor_si128(y, _mm_loadu_si128(reinterpret_cast<__m128i*>(_r))));
} }
// Interleave encryption of IV with the final GHASH of y XOR (length * 8). // Interleave encryption of IV with the final GHASH of y XOR (length * 8).
// Then XOR these together to get the final tag. // Then XOR these together to get the final tag.
const __m128i *const k = _aes.p_k.ni.k; const __m128i* const k = _aes.p_k.ni.k;
const __m128i h = _aes.p_k.ni.h[0]; const __m128i h = _aes.p_k.ni.h[0];
y = _mm_xor_si128(y, _mm_set_epi64x(0LL, (long long)Utils::hton((uint64_t)_len << 3U))); y = _mm_xor_si128(y, _mm_set_epi64x(0LL, (long long)Utils::hton((uint64_t)_len << 3U)));
y = _mm_shuffle_epi8(y, s_sseSwapBytes); y = _mm_shuffle_epi8(y, s_sseSwapBytes);
__m128i encIV = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<const __m128i *>(_iv)), k[0]); __m128i encIV = _mm_xor_si128(_mm_loadu_si128(reinterpret_cast<const __m128i*>(_iv)), k[0]);
__m128i t1 = _mm_clmulepi64_si128(h, y, 0x00); __m128i t1 = _mm_clmulepi64_si128(h, y, 0x00);
__m128i t2 = _mm_clmulepi64_si128(h, y, 0x01); __m128i t2 = _mm_clmulepi64_si128(h, y, 0x01);
__m128i t3 = _mm_clmulepi64_si128(h, y, 0x10); __m128i t3 = _mm_clmulepi64_si128(h, y, 0x10);
@ -359,7 +398,7 @@ void AES::GMAC::p_aesNIFinish(uint8_t tag[16]) noexcept
t4 = _mm_xor_si128(t4, t3); t4 = _mm_xor_si128(t4, t3);
encIV = _mm_aesenclast_si128(encIV, k[14]); encIV = _mm_aesenclast_si128(encIV, k[14]);
t4 = _mm_xor_si128(t4, t5); t4 = _mm_xor_si128(t4, t5);
_mm_storeu_si128(reinterpret_cast<__m128i *>(tag), _mm_xor_si128(_mm_shuffle_epi8(t4, s_sseSwapBytes), encIV)); _mm_storeu_si128(reinterpret_cast<__m128i*>(tag), _mm_xor_si128(_mm_shuffle_epi8(t4, s_sseSwapBytes), encIV));
} }
#ifdef __GNUC__ #ifdef __GNUC__
@ -370,7 +409,7 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
const __m128i dd = _mm_set_epi64x(0, (long long)_ctr[0]); const __m128i dd = _mm_set_epi64x(0, (long long)_ctr[0]);
uint64_t c1 = Utils::ntoh(_ctr[1]); uint64_t c1 = Utils::ntoh(_ctr[1]);
const __m128i *const k = _aes.p_k.ni.k; const __m128i* const k = _aes.p_k.ni.k;
const __m128i k0 = k[0]; const __m128i k0 = k[0];
const __m128i k1 = k[1]; const __m128i k1 = k[1];
const __m128i k2 = k[2]; const __m128i k2 = k[2];
@ -391,14 +430,14 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
unsigned int totalLen = _len; unsigned int totalLen = _len;
if ((totalLen & 15U)) { if ((totalLen & 15U)) {
for (;;) { for (;;) {
if (unlikely(!len)) { if (unlikely(! len)) {
_ctr[1] = Utils::hton(c1); _ctr[1] = Utils::hton(c1);
_len = totalLen; _len = totalLen;
return; return;
} }
--len; --len;
out[totalLen++] = *(in++); out[totalLen++] = *(in++);
if (!(totalLen & 15U)) { if (! (totalLen & 15U)) {
__m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1); __m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1);
d0 = _mm_xor_si128(d0, k0); d0 = _mm_xor_si128(d0, k0);
d0 = _mm_aesenc_si128(d0, k1); d0 = _mm_aesenc_si128(d0, k1);
@ -411,7 +450,7 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
d0 = _mm_aesenc_si128(d0, k8); d0 = _mm_aesenc_si128(d0, k8);
d0 = _mm_aesenc_si128(d0, k9); d0 = _mm_aesenc_si128(d0, k9);
d0 = _mm_aesenc_si128(d0, k10); d0 = _mm_aesenc_si128(d0, k10);
__m128i *const outblk = reinterpret_cast<__m128i *>(out + (totalLen - 16)); __m128i* const outblk = reinterpret_cast<__m128i*>(out + (totalLen - 16));
d0 = _mm_aesenc_si128(d0, k11); d0 = _mm_aesenc_si128(d0, k11);
const __m128i p0 = _mm_loadu_si128(outblk); const __m128i p0 = _mm_loadu_si128(outblk);
d0 = _mm_aesenc_si128(d0, k12); d0 = _mm_aesenc_si128(d0, k12);
@ -427,26 +466,26 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
_len = totalLen + len; _len = totalLen + len;
if (likely(len >= 64)) { if (likely(len >= 64)) {
#if defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256) #if defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256)
if (Utils::CPUID.vaes) { if (Utils::CPUID.vaes) {
if (Utils::CPUID.avx512f) { if (Utils::CPUID.avx512f) {
p_aesCtrInnerVAES512(len, _ctr[0], c1, in, out, k); p_aesCtrInnerVAES512(len, _ctr[0], c1, in, out, k);
} else { }
else {
p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k); p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k);
} }
goto skip_conventional_aesni_64; goto skip_conventional_aesni_64;
} }
#endif #endif
#if !defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256) #if ! defined(ZT_AES_VAES512) && defined(ZT_AES_VAES256)
if (Utils::CPUID.vaes && (len >= 256)) { if (Utils::CPUID.vaes && (len >= 256)) {
p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k); p_aesCtrInnerVAES256(len, _ctr[0], c1, in, out, k);
goto skip_conventional_aesni_64; goto skip_conventional_aesni_64;
} }
#endif #endif
const uint8_t *const eof64 = in + (len & ~((unsigned int)63)); const uint8_t* const eof64 = in + (len & ~((unsigned int)63));
len &= 63; len &= 63;
__m128i d0, d1, d2, d3; __m128i d0, d1, d2, d3;
do { do {
@ -515,21 +554,26 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
d1 = _mm_aesenc_si128(d1, k13); d1 = _mm_aesenc_si128(d1, k13);
d2 = _mm_aesenc_si128(d2, k13); d2 = _mm_aesenc_si128(d2, k13);
d3 = _mm_aesenc_si128(d3, k13); d3 = _mm_aesenc_si128(d3, k13);
d0 = _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in))); d0 = _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in)));
d1 = _mm_xor_si128(_mm_aesenclast_si128(d1, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 16))); d1 = _mm_xor_si128(
d2 = _mm_xor_si128(_mm_aesenclast_si128(d2, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 32))); _mm_aesenclast_si128(d1, k14),
d3 = _mm_xor_si128(_mm_aesenclast_si128(d3, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in + 48))); _mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 16)));
d2 = _mm_xor_si128(
_mm_aesenclast_si128(d2, k14),
_mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 32)));
d3 = _mm_xor_si128(
_mm_aesenclast_si128(d3, k14),
_mm_loadu_si128(reinterpret_cast<const __m128i*>(in + 48)));
in += 64; in += 64;
_mm_storeu_si128(reinterpret_cast<__m128i *>(out), d0); _mm_storeu_si128(reinterpret_cast<__m128i*>(out), d0);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 16), d1); _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 16), d1);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 32), d2); _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 32), d2);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out + 48), d3); _mm_storeu_si128(reinterpret_cast<__m128i*>(out + 48), d3);
out += 64; out += 64;
} while (likely(in != eof64)); } while (likely(in != eof64));
} }
skip_conventional_aesni_64: skip_conventional_aesni_64:
while (len >= 16) { while (len >= 16) {
__m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1); __m128i d0 = _mm_insert_epi64(dd, (long long)Utils::hton(c1++), 1);
d0 = _mm_xor_si128(d0, k0); d0 = _mm_xor_si128(d0, k0);
@ -546,7 +590,9 @@ void AES::CTR::p_aesNICrypt(const uint8_t *in, uint8_t *out, unsigned int len) n
d0 = _mm_aesenc_si128(d0, k11); d0 = _mm_aesenc_si128(d0, k11);
d0 = _mm_aesenc_si128(d0, k12); d0 = _mm_aesenc_si128(d0, k12);
d0 = _mm_aesenc_si128(d0, k13); d0 = _mm_aesenc_si128(d0, k13);
_mm_storeu_si128(reinterpret_cast<__m128i *>(out), _mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast<const __m128i *>(in)))); _mm_storeu_si128(
reinterpret_cast<__m128i*>(out),
_mm_xor_si128(_mm_aesenclast_si128(d0, k14), _mm_loadu_si128(reinterpret_cast<const __m128i*>(in))));
in += 16; in += 16;
len -= 16; len -= 16;
out += 16; out += 16;
@ -567,8 +613,8 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
void AES::p_init_aesni(const uint8_t *key) noexcept void AES::p_init_aesni(const uint8_t *key) noexcept
{ {
__m128i t1, t2, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13; __m128i t1, t2, k1, k2, k3, k4, k5, k6, k7, k8, k9, k10, k11, k12, k13;
p_k.ni.k[0] = t1 = _mm_loadu_si128((const __m128i *)key); p_k.ni.k[0] = t1 = _mm_loadu_si128((const __m128i*)key);
p_k.ni.k[1] = k1 = t2 = _mm_loadu_si128((const __m128i *)(key + 16)); p_k.ni.k[1] = k1 = t2 = _mm_loadu_si128((const __m128i*)(key + 16));
p_k.ni.k[2] = k2 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x01)); p_k.ni.k[2] = k2 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x01));
p_k.ni.k[3] = k3 = t2 = p_init256_2_aesni(t1, t2); p_k.ni.k[3] = k3 = t2 = p_init256_2_aesni(t1, t2);
p_k.ni.k[4] = k4 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x02)); p_k.ni.k[4] = k4 = t1 = p_init256_1_aesni(t1, _mm_aeskeygenassist_si128(t2, 0x02));
@ -630,7 +676,7 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif #endif
void AES::p_encrypt_aesni(const void *const in, void *const out) const noexcept void AES::p_encrypt_aesni(const void *const in, void *const out) const noexcept
{ {
__m128i tmp = _mm_loadu_si128((const __m128i *)in); __m128i tmp = _mm_loadu_si128((const __m128i*)in);
tmp = _mm_xor_si128(tmp, p_k.ni.k[0]); tmp = _mm_xor_si128(tmp, p_k.ni.k[0]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[1]); tmp = _mm_aesenc_si128(tmp, p_k.ni.k[1]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[2]); tmp = _mm_aesenc_si128(tmp, p_k.ni.k[2]);
@ -645,7 +691,7 @@ void AES::p_encrypt_aesni(const void *const in, void *const out) const noexcept
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[11]); tmp = _mm_aesenc_si128(tmp, p_k.ni.k[11]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[12]); tmp = _mm_aesenc_si128(tmp, p_k.ni.k[12]);
tmp = _mm_aesenc_si128(tmp, p_k.ni.k[13]); tmp = _mm_aesenc_si128(tmp, p_k.ni.k[13]);
_mm_storeu_si128((__m128i *)out, _mm_aesenclast_si128(tmp, p_k.ni.k[14])); _mm_storeu_si128((__m128i*)out, _mm_aesenclast_si128(tmp, p_k.ni.k[14]));
} }
#ifdef __GNUC__ #ifdef __GNUC__
@ -653,7 +699,7 @@ __attribute__((__target__("ssse3,sse4,sse4.1,sse4.2,aes,pclmul")))
#endif #endif
void AES::p_decrypt_aesni(const void *in, void *out) const noexcept void AES::p_decrypt_aesni(const void *in, void *out) const noexcept
{ {
__m128i tmp = _mm_loadu_si128((const __m128i *)in); __m128i tmp = _mm_loadu_si128((const __m128i*)in);
tmp = _mm_xor_si128(tmp, p_k.ni.k[14]); tmp = _mm_xor_si128(tmp, p_k.ni.k[14]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[15]); tmp = _mm_aesdec_si128(tmp, p_k.ni.k[15]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[16]); tmp = _mm_aesdec_si128(tmp, p_k.ni.k[16]);
@ -668,7 +714,7 @@ void AES::p_decrypt_aesni(const void *in, void *out) const noexcept
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[25]); tmp = _mm_aesdec_si128(tmp, p_k.ni.k[25]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[26]); tmp = _mm_aesdec_si128(tmp, p_k.ni.k[26]);
tmp = _mm_aesdec_si128(tmp, p_k.ni.k[27]); tmp = _mm_aesdec_si128(tmp, p_k.ni.k[27]);
_mm_storeu_si128((__m128i *)out, _mm_aesdeclast_si128(tmp, p_k.ni.k[0])); _mm_storeu_si128((__m128i*)out, _mm_aesdeclast_si128(tmp, p_k.ni.k[0]));
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -13,8 +13,8 @@
// AES for ARM crypto extensions and NEON. // AES for ARM crypto extensions and NEON.
#include "Constants.hpp"
#include "AES.hpp" #include "AES.hpp"
#include "Constants.hpp"
#ifdef ZT_AES_NEON #ifdef ZT_AES_NEON
@ -31,34 +31,34 @@ ZT_INLINE uint8x16_t s_clmul_armneon_crypto(uint8x16_t h, uint8x16_t y, const ui
y = vrbitq_u8(y); y = vrbitq_u8(y);
const uint8x16_t p = vreinterpretq_u8_u64(vdupq_n_u64(0x0000000000000087)); const uint8x16_t p = vreinterpretq_u8_u64(vdupq_n_u64(0x0000000000000087));
t0 = vextq_u8(y, y, 8); t0 = vextq_u8(y, y, 8);
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (r0) : "w" (h), "w" (y)); __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(r0) : "w"(h), "w"(y));
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (r1) : "w" (h), "w" (y)); __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(r1) : "w"(h), "w"(y));
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (t1) : "w" (h), "w" (t0)); __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(t1) : "w"(h), "w"(t0));
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (t0) : "w" (h), "w" (t0)); __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(t0) : "w"(h), "w"(t0));
t0 = veorq_u8(t0, t1); t0 = veorq_u8(t0, t1);
t1 = vextq_u8(z, t0, 8); t1 = vextq_u8(z, t0, 8);
r0 = veorq_u8(r0, t1); r0 = veorq_u8(r0, t1);
t1 = vextq_u8(t0, z, 8); t1 = vextq_u8(t0, z, 8);
r1 = veorq_u8(r1, t1); r1 = veorq_u8(r1, t1);
__asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" :"=w" (t0) : "w" (r1), "w" (p)); __asm__ __volatile__("pmull2 %0.1q, %1.2d, %2.2d \n\t" : "=w"(t0) : "w"(r1), "w"(p));
t1 = vextq_u8(t0, z, 8); t1 = vextq_u8(t0, z, 8);
r1 = veorq_u8(r1, t1); r1 = veorq_u8(r1, t1);
t1 = vextq_u8(z, t0, 8); t1 = vextq_u8(z, t0, 8);
r0 = veorq_u8(r0, t1); r0 = veorq_u8(r0, t1);
__asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w" (t0) : "w" (r1), "w" (p)); __asm__ __volatile__("pmull %0.1q, %1.1d, %2.1d \n\t" : "=w"(t0) : "w"(r1), "w"(p));
return vrbitq_u8(veorq_u8(r0, t0)); return vrbitq_u8(veorq_u8(r0, t0));
} }
} // anonymous namespace } // anonymous namespace
void AES::GMAC::p_armUpdate(const uint8_t *in, unsigned int len) noexcept void AES::GMAC::p_armUpdate(const uint8_t* in, unsigned int len) noexcept
{ {
uint8x16_t y = vld1q_u8(reinterpret_cast<const uint8_t *>(_y)); uint8x16_t y = vld1q_u8(reinterpret_cast<const uint8_t*>(_y));
const uint8x16_t h = _aes.p_k.neon.h; const uint8x16_t h = _aes.p_k.neon.h;
if (_rp) { if (_rp) {
for(;;) { for (;;) {
if (!len) if (! len)
return; return;
--len; --len;
_r[_rp++] = *(in++); _r[_rp++] = *(in++);
@ -75,7 +75,7 @@ void AES::GMAC::p_armUpdate(const uint8_t *in, unsigned int len) noexcept
len -= 16; len -= 16;
} }
vst1q_u8(reinterpret_cast<uint8_t *>(_y), y); vst1q_u8(reinterpret_cast<uint8_t*>(_y), y);
for (unsigned int i = 0; i < len; ++i) for (unsigned int i = 0; i < len; ++i)
_r[i] = in[i]; _r[i] = in[i];
@ -85,7 +85,7 @@ void AES::GMAC::p_armUpdate(const uint8_t *in, unsigned int len) noexcept
void AES::GMAC::p_armFinish(uint8_t tag[16]) noexcept void AES::GMAC::p_armFinish(uint8_t tag[16]) noexcept
{ {
uint64_t tmp[2]; uint64_t tmp[2];
uint8x16_t y = vld1q_u8(reinterpret_cast<const uint8_t *>(_y)); uint8x16_t y = vld1q_u8(reinterpret_cast<const uint8_t*>(_y));
const uint8x16_t h = _aes.p_k.neon.h; const uint8x16_t h = _aes.p_k.neon.h;
if (_rp) { if (_rp) {
@ -96,25 +96,25 @@ void AES::GMAC::p_armFinish(uint8_t tag[16]) noexcept
tmp[0] = Utils::hton((uint64_t)_len << 3U); tmp[0] = Utils::hton((uint64_t)_len << 3U);
tmp[1] = 0; tmp[1] = 0;
y = s_clmul_armneon_crypto(h, y, reinterpret_cast<const uint8_t *>(tmp)); y = s_clmul_armneon_crypto(h, y, reinterpret_cast<const uint8_t*>(tmp));
Utils::copy< 12 >(tmp, _iv); Utils::copy<12>(tmp, _iv);
#if __BYTE_ORDER == __BIG_ENDIAN #if __BYTE_ORDER == __BIG_ENDIAN
reinterpret_cast<uint32_t *>(tmp)[3] = 0x00000001; reinterpret_cast<uint32_t*>(tmp)[3] = 0x00000001;
#else #else
reinterpret_cast<uint32_t *>(tmp)[3] = 0x01000000; reinterpret_cast<uint32_t*>(tmp)[3] = 0x01000000;
#endif #endif
_aes.encrypt(tmp, tmp); _aes.encrypt(tmp, tmp);
uint8x16_t yy = y; uint8x16_t yy = y;
Utils::storeMachineEndian< uint64_t >(tag, tmp[0] ^ reinterpret_cast<const uint64_t *>(&yy)[0]); Utils::storeMachineEndian<uint64_t>(tag, tmp[0] ^ reinterpret_cast<const uint64_t*>(&yy)[0]);
Utils::storeMachineEndian< uint64_t >(tag + 8, tmp[1] ^ reinterpret_cast<const uint64_t *>(&yy)[1]); Utils::storeMachineEndian<uint64_t>(tag + 8, tmp[1] ^ reinterpret_cast<const uint64_t*>(&yy)[1]);
} }
void AES::CTR::p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noexcept void AES::CTR::p_armCrypt(const uint8_t* in, uint8_t* out, unsigned int len) noexcept
{ {
uint8x16_t dd = vrev32q_u8(vld1q_u8(reinterpret_cast<uint8_t *>(_ctr))); uint8x16_t dd = vrev32q_u8(vld1q_u8(reinterpret_cast<uint8_t*>(_ctr)));
const uint32x4_t one = {0,0,0,1}; const uint32x4_t one = { 0, 0, 0, 1 };
uint8x16_t k0 = _aes.p_k.neon.ek[0]; uint8x16_t k0 = _aes.p_k.neon.ek[0];
uint8x16_t k1 = _aes.p_k.neon.ek[1]; uint8x16_t k1 = _aes.p_k.neon.ek[1];
@ -135,15 +135,15 @@ void AES::CTR::p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noe
unsigned int totalLen = _len; unsigned int totalLen = _len;
if ((totalLen & 15U) != 0) { if ((totalLen & 15U) != 0) {
for (;;) { for (;;) {
if (unlikely(!len)) { if (unlikely(! len)) {
vst1q_u8(reinterpret_cast<uint8_t *>(_ctr), vrev32q_u8(dd)); vst1q_u8(reinterpret_cast<uint8_t*>(_ctr), vrev32q_u8(dd));
_len = totalLen; _len = totalLen;
return; return;
} }
--len; --len;
out[totalLen++] = *(in++); out[totalLen++] = *(in++);
if ((totalLen & 15U) == 0) { if ((totalLen & 15U) == 0) {
uint8_t *const otmp = out + (totalLen - 16); uint8_t* const otmp = out + (totalLen - 16);
uint8x16_t d0 = vrev32q_u8(dd); uint8x16_t d0 = vrev32q_u8(dd);
uint8x16_t pt = vld1q_u8(otmp); uint8x16_t pt = vld1q_u8(otmp);
d0 = vaesmcq_u8(vaeseq_u8(d0, k0)); d0 = vaesmcq_u8(vaeseq_u8(d0, k0));
@ -295,45 +295,65 @@ void AES::CTR::p_armCrypt(const uint8_t *in, uint8_t *out, unsigned int len) noe
for (unsigned int i = 0; i < len; ++i) for (unsigned int i = 0; i < len; ++i)
out[i] = in[i]; out[i] = in[i];
vst1q_u8(reinterpret_cast<uint8_t *>(_ctr), vrev32q_u8(dd)); vst1q_u8(reinterpret_cast<uint8_t*>(_ctr), vrev32q_u8(dd));
} }
#define ZT_INIT_ARMNEON_CRYPTO_SUBWORD(w) ((uint32_t)s_sbox[w & 0xffU] + ((uint32_t)s_sbox[(w >> 8U) & 0xffU] << 8U) + ((uint32_t)s_sbox[(w >> 16U) & 0xffU] << 16U) + ((uint32_t)s_sbox[(w >> 24U) & 0xffU] << 24U)) #define ZT_INIT_ARMNEON_CRYPTO_SUBWORD(w) \
((uint32_t)s_sbox[w & 0xffU] + ((uint32_t)s_sbox[(w >> 8U) & 0xffU] << 8U) \
+ ((uint32_t)s_sbox[(w >> 16U) & 0xffU] << 16U) + ((uint32_t)s_sbox[(w >> 24U) & 0xffU] << 24U))
#define ZT_INIT_ARMNEON_CRYPTO_ROTWORD(w) (((w) << 8U) | ((w) >> 24U)) #define ZT_INIT_ARMNEON_CRYPTO_ROTWORD(w) (((w) << 8U) | ((w) >> 24U))
#define ZT_INIT_ARMNEON_CRYPTO_NK 8 #define ZT_INIT_ARMNEON_CRYPTO_NK 8
#define ZT_INIT_ARMNEON_CRYPTO_NB 4 #define ZT_INIT_ARMNEON_CRYPTO_NB 4
#define ZT_INIT_ARMNEON_CRYPTO_NR 14 #define ZT_INIT_ARMNEON_CRYPTO_NR 14
void AES::p_init_armneon_crypto(const uint8_t *key) noexcept void AES::p_init_armneon_crypto(const uint8_t* key) noexcept
{ {
static const uint8_t s_sbox[256] = {0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, static const uint8_t s_sbox[256] = {
0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82,
0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16}; 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96,
0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb,
0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff,
0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32,
0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6,
0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e,
0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
0xb0, 0x54, 0xbb, 0x16
};
uint64_t h[2]; uint64_t h[2];
uint32_t *const w = reinterpret_cast<uint32_t *>(p_k.neon.ek); uint32_t* const w = reinterpret_cast<uint32_t*>(p_k.neon.ek);
for (unsigned int i=0;i<ZT_INIT_ARMNEON_CRYPTO_NK;++i) { for (unsigned int i = 0; i < ZT_INIT_ARMNEON_CRYPTO_NK; ++i) {
const unsigned int j = i * 4; const unsigned int j = i * 4;
w[i] = ((uint32_t)key[j] << 24U) | ((uint32_t)key[j + 1] << 16U) | ((uint32_t)key[j + 2] << 8U) | (uint32_t)key[j + 3]; w[i] = ((uint32_t)key[j] << 24U) | ((uint32_t)key[j + 1] << 16U) | ((uint32_t)key[j + 2] << 8U)
| (uint32_t)key[j + 3];
} }
for (unsigned int i=ZT_INIT_ARMNEON_CRYPTO_NK;i<(ZT_INIT_ARMNEON_CRYPTO_NB * (ZT_INIT_ARMNEON_CRYPTO_NR + 1));++i) { for (unsigned int i = ZT_INIT_ARMNEON_CRYPTO_NK; i < (ZT_INIT_ARMNEON_CRYPTO_NB * (ZT_INIT_ARMNEON_CRYPTO_NR + 1));
++i) {
uint32_t t = w[i - 1]; uint32_t t = w[i - 1];
const unsigned int imod = i & (ZT_INIT_ARMNEON_CRYPTO_NK - 1); const unsigned int imod = i & (ZT_INIT_ARMNEON_CRYPTO_NK - 1);
if (imod == 0) { if (imod == 0) {
t = ZT_INIT_ARMNEON_CRYPTO_SUBWORD(ZT_INIT_ARMNEON_CRYPTO_ROTWORD(t)) ^ rcon[(i - 1) / ZT_INIT_ARMNEON_CRYPTO_NK]; t = ZT_INIT_ARMNEON_CRYPTO_SUBWORD(ZT_INIT_ARMNEON_CRYPTO_ROTWORD(t))
} else if (imod == 4) { ^ rcon[(i - 1) / ZT_INIT_ARMNEON_CRYPTO_NK];
}
else if (imod == 4) {
t = ZT_INIT_ARMNEON_CRYPTO_SUBWORD(t); t = ZT_INIT_ARMNEON_CRYPTO_SUBWORD(t);
} }
w[i] = w[i - ZT_INIT_ARMNEON_CRYPTO_NK] ^ t; w[i] = w[i - ZT_INIT_ARMNEON_CRYPTO_NK] ^ t;
} }
for (unsigned int i=0;i<(ZT_INIT_ARMNEON_CRYPTO_NB * (ZT_INIT_ARMNEON_CRYPTO_NR + 1));++i) for (unsigned int i = 0; i < (ZT_INIT_ARMNEON_CRYPTO_NB * (ZT_INIT_ARMNEON_CRYPTO_NR + 1)); ++i)
w[i] = Utils::hton(w[i]); w[i] = Utils::hton(w[i]);
p_k.neon.dk[0] = p_k.neon.ek[14]; p_k.neon.dk[0] = p_k.neon.ek[14];
for (int i=1;i<14;++i) for (int i = 1; i < 14; ++i)
p_k.neon.dk[i] = vaesimcq_u8(p_k.neon.ek[14 - i]); p_k.neon.dk[i] = vaesimcq_u8(p_k.neon.ek[14 - i]);
p_k.neon.dk[14] = p_k.neon.ek[0]; p_k.neon.dk[14] = p_k.neon.ek[0];
@ -344,9 +364,9 @@ void AES::p_init_armneon_crypto(const uint8_t *key) noexcept
p_k.sw.h[1] = Utils::ntoh(h[1]); p_k.sw.h[1] = Utils::ntoh(h[1]);
} }
void AES::p_encrypt_armneon_crypto(const void *const in, void *const out) const noexcept void AES::p_encrypt_armneon_crypto(const void* const in, void* const out) const noexcept
{ {
uint8x16_t tmp = vld1q_u8(reinterpret_cast<const uint8_t *>(in)); uint8x16_t tmp = vld1q_u8(reinterpret_cast<const uint8_t*>(in));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[0])); tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[0]));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[1])); tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[1]));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[2])); tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[2]));
@ -361,12 +381,12 @@ void AES::p_encrypt_armneon_crypto(const void *const in, void *const out) const
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[11])); tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[11]));
tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[12])); tmp = vaesmcq_u8(vaeseq_u8(tmp, p_k.neon.ek[12]));
tmp = veorq_u8(vaeseq_u8(tmp, p_k.neon.ek[13]), p_k.neon.ek[14]); tmp = veorq_u8(vaeseq_u8(tmp, p_k.neon.ek[13]), p_k.neon.ek[14]);
vst1q_u8(reinterpret_cast<uint8_t *>(out), tmp); vst1q_u8(reinterpret_cast<uint8_t*>(out), tmp);
} }
void AES::p_decrypt_armneon_crypto(const void *const in, void *const out) const noexcept void AES::p_decrypt_armneon_crypto(const void* const in, void* const out) const noexcept
{ {
uint8x16_t tmp = vld1q_u8(reinterpret_cast<const uint8_t *>(in)); uint8x16_t tmp = vld1q_u8(reinterpret_cast<const uint8_t*>(in));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[0])); tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[0]));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[1])); tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[1]));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[2])); tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[2]));
@ -381,7 +401,7 @@ void AES::p_decrypt_armneon_crypto(const void *const in, void *const out) const
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[11])); tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[11]));
tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[12])); tmp = vaesimcq_u8(vaesdq_u8(tmp, p_k.neon.dk[12]));
tmp = veorq_u8(vaesdq_u8(tmp, p_k.neon.dk[13]), p_k.neon.dk[14]); tmp = veorq_u8(vaesdq_u8(tmp, p_k.neon.dk[13]), p_k.neon.dk[14]);
vst1q_u8(reinterpret_cast<uint8_t *>(out), tmp); vst1q_u8(reinterpret_cast<uint8_t*>(out), tmp);
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -15,9 +15,9 @@
#define ZT_ADDRESS_HPP #define ZT_ADDRESS_HPP
#include "Constants.hpp" #include "Constants.hpp"
#include "Utils.hpp"
#include "TriviallyCopyable.hpp"
#include "Containers.hpp" #include "Containers.hpp"
#include "TriviallyCopyable.hpp"
#include "Utils.hpp"
#define ZT_ADDRESS_STRING_SIZE_MAX (ZT_ADDRESS_LENGTH_HEX + 1) #define ZT_ADDRESS_STRING_SIZE_MAX (ZT_ADDRESS_LENGTH_HEX + 1)
@ -28,28 +28,37 @@ namespace ZeroTier {
* *
* This is merely a 40-bit short address packed into a uint64_t and wrapped with methods. * This is merely a 40-bit short address packed into a uint64_t and wrapped with methods.
*/ */
class Address : public TriviallyCopyable class Address : public TriviallyCopyable {
{ public:
public: ZT_INLINE Address() noexcept : _a(0)
ZT_INLINE Address() noexcept: _a(0) {
{} }
ZT_INLINE Address(const uint64_t a) noexcept: _a(a) ZT_INLINE Address(const uint64_t a) noexcept : _a(a)
{} {
}
explicit ZT_INLINE Address(const uint8_t b[5]) noexcept: explicit ZT_INLINE Address(const uint8_t b[5]) noexcept
_a(((uint64_t)b[0] << 32U) | ((uint64_t)b[1] << 24U) | ((uint64_t)b[2] << 16U) | ((uint64_t)b[3] << 8U) | (uint64_t)b[4]) : _a(((uint64_t)b[0] << 32U) | ((uint64_t)b[1] << 24U) | ((uint64_t)b[2] << 16U) | ((uint64_t)b[3] << 8U)
{} | (uint64_t)b[4])
{
}
ZT_INLINE Address &operator=(const uint64_t a) noexcept ZT_INLINE Address& operator=(const uint64_t a) noexcept
{ _a = a; return *this; } {
_a = a;
return *this;
}
/** /**
* @param bits Raw address -- 5 bytes, big-endian byte order * @param bits Raw address -- 5 bytes, big-endian byte order
* @param len Length of array * @param len Length of array
*/ */
ZT_INLINE void setTo(const uint8_t b[5]) noexcept ZT_INLINE void setTo(const uint8_t b[5]) noexcept
{ _a = ((uint64_t)b[0] << 32U) | ((uint64_t)b[1] << 24U) | ((uint64_t)b[2] << 16U) | ((uint64_t)b[3] << 8U) | (uint64_t)b[4]; } {
_a = ((uint64_t)b[0] << 32U) | ((uint64_t)b[1] << 24U) | ((uint64_t)b[2] << 16U) | ((uint64_t)b[3] << 8U)
| (uint64_t)b[4];
}
/** /**
* @param bits Buffer to hold 5-byte address in big-endian byte order * @param bits Buffer to hold 5-byte address in big-endian byte order
@ -69,19 +78,23 @@ public:
* @return Integer containing address (0 to 2^40) * @return Integer containing address (0 to 2^40)
*/ */
ZT_INLINE uint64_t toInt() const noexcept ZT_INLINE uint64_t toInt() const noexcept
{ return _a; } {
return _a;
}
/** /**
* Set address to zero/NIL * Set address to zero/NIL
*/ */
ZT_INLINE void zero() noexcept ZT_INLINE void zero() noexcept
{ _a = 0; } {
_a = 0;
}
/** /**
* @param s String with at least 11 characters of space available (10 + terminating NULL) * @param s String with at least 11 characters of space available (10 + terminating NULL)
* @return Hexadecimal string * @return Hexadecimal string
*/ */
ZT_INLINE char *toString(char s[ZT_ADDRESS_STRING_SIZE_MAX]) const noexcept ZT_INLINE char* toString(char s[ZT_ADDRESS_STRING_SIZE_MAX]) const noexcept
{ {
const uint64_t a = _a; const uint64_t a = _a;
const unsigned int m = 0xf; const unsigned int m = 0xf;
@ -116,47 +129,90 @@ public:
* @return True if address is reserved and may not be used * @return True if address is reserved and may not be used
*/ */
ZT_INLINE bool isReserved() const noexcept ZT_INLINE bool isReserved() const noexcept
{ return ((!_a) || ((_a >> 32U) == ZT_ADDRESS_RESERVED_PREFIX)); } {
return ((! _a) || ((_a >> 32U) == ZT_ADDRESS_RESERVED_PREFIX));
}
ZT_INLINE unsigned long hashCode() const noexcept ZT_INLINE unsigned long hashCode() const noexcept
{ return (unsigned long)_a; } {
return (unsigned long)_a;
}
ZT_INLINE operator bool() const noexcept ZT_INLINE operator bool() const noexcept
{ return (_a != 0); } {
return (_a != 0);
}
ZT_INLINE operator uint64_t() const noexcept ZT_INLINE operator uint64_t() const noexcept
{ return _a; } {
return _a;
}
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;
}
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;
}
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;
}
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; }
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; }
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; }
ZT_INLINE bool operator==(const uint64_t a) const noexcept ZT_INLINE bool operator==(const uint64_t a) const noexcept
{ return _a == a; } {
ZT_INLINE bool operator!=(const uint64_t a) const noexcept return _a == a;
{ return _a != a; } }
ZT_INLINE bool operator>(const uint64_t a) const noexcept
{ return _a > a; }
ZT_INLINE bool operator<(const uint64_t a) const noexcept
{ return _a < a; }
ZT_INLINE bool operator>=(const uint64_t a) const noexcept
{ return _a >= a; }
ZT_INLINE bool operator<=(const uint64_t a) const noexcept
{ return _a <= a; }
private: ZT_INLINE bool operator!=(const uint64_t a) const noexcept
{
return _a != a;
}
ZT_INLINE bool operator>(const uint64_t a) const noexcept
{
return _a > a;
}
ZT_INLINE bool operator<(const uint64_t a) const noexcept
{
return _a < a;
}
ZT_INLINE bool operator>=(const uint64_t a) const noexcept
{
return _a >= a;
}
ZT_INLINE bool operator<=(const uint64_t a) const noexcept
{
return _a <= a;
}
private:
uint64_t _a; uint64_t _a;
}; };
static_assert(sizeof(Address) == sizeof(uint64_t),"Address has unnecessary extra padding"); static_assert(sizeof(Address) == sizeof(uint64_t), "Address has unnecessary extra padding");
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -12,56 +12,59 @@
/****/ /****/
#include "Buf.hpp" #include "Buf.hpp"
#include "Spinlock.hpp" #include "Spinlock.hpp"
namespace ZeroTier { namespace ZeroTier {
static std::atomic< uintptr_t > s_pool(0); static std::atomic<uintptr_t> s_pool(0);
static std::atomic< long > s_allocated(0); static std::atomic<long> s_allocated(0);
// uintptr_max can never be a valid pointer, so use it to indicate that s_pool is locked (very short duration spinlock) // uintptr_max can never be a valid pointer, so use it to indicate that s_pool is locked (very short duration spinlock)
#define ZT_ATOMIC_PTR_LOCKED (~((uintptr_t)0)) #define ZT_ATOMIC_PTR_LOCKED (~((uintptr_t)0))
void *Buf::operator new(std::size_t sz) void* Buf::operator new(std::size_t sz)
{ {
uintptr_t bb; uintptr_t bb;
for (;;) { for (;;) {
bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED, std::memory_order_acquire); bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED, std::memory_order_acquire);
if (likely(bb != ZT_ATOMIC_PTR_LOCKED)) { if (likely(bb != ZT_ATOMIC_PTR_LOCKED)) {
Buf *b; Buf* b;
if (likely(bb != 0)) { if (likely(bb != 0)) {
b = reinterpret_cast<Buf *>(bb); b = reinterpret_cast<Buf*>(bb);
s_pool.store(b->__nextInPool, std::memory_order_release); s_pool.store(b->__nextInPool, std::memory_order_release);
} else { }
else {
s_pool.store(0, std::memory_order_release); s_pool.store(0, std::memory_order_release);
b = reinterpret_cast<Buf *>(malloc(sz)); b = reinterpret_cast<Buf*>(malloc(sz));
if (!b) if (! b)
throw Utils::BadAllocException; throw Utils::BadAllocException;
s_allocated.fetch_add(1, std::memory_order_relaxed); s_allocated.fetch_add(1, std::memory_order_relaxed);
} }
b->__refCount.store(0, std::memory_order_relaxed); b->__refCount.store(0, std::memory_order_relaxed);
return reinterpret_cast<void *>(b); return reinterpret_cast<void*>(b);
} }
Spinlock::pause(); Spinlock::pause();
} }
} }
void Buf::operator delete(void *ptr) void Buf::operator delete(void* ptr)
{ {
if (likely(ptr != nullptr)) { if (likely(ptr != nullptr)) {
if (s_allocated.load(std::memory_order_relaxed) > ZT_BUF_MAX_POOL_SIZE) { if (s_allocated.load(std::memory_order_relaxed) > ZT_BUF_MAX_POOL_SIZE) {
s_allocated.fetch_sub(1, std::memory_order_relaxed); s_allocated.fetch_sub(1, std::memory_order_relaxed);
free(ptr); free(ptr);
} else { }
else {
uintptr_t bb; uintptr_t bb;
for (;;) { for (;;) {
bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED, std::memory_order_acquire); bb = s_pool.exchange(ZT_ATOMIC_PTR_LOCKED, std::memory_order_acquire);
if (likely(bb != ZT_ATOMIC_PTR_LOCKED)) { if (likely(bb != ZT_ATOMIC_PTR_LOCKED)) {
reinterpret_cast<Buf *>(ptr)->__nextInPool = bb; reinterpret_cast<Buf*>(ptr)->__nextInPool = bb;
s_pool.store(reinterpret_cast<uintptr_t>(ptr), std::memory_order_release); s_pool.store(reinterpret_cast<uintptr_t>(ptr), std::memory_order_release);
return; return;
} }
@ -81,9 +84,9 @@ void Buf::freePool() noexcept
s_pool.store(0, std::memory_order_release); s_pool.store(0, std::memory_order_release);
while (bb != 0) { while (bb != 0) {
const uintptr_t next = reinterpret_cast<Buf *>(bb)->__nextInPool; const uintptr_t next = reinterpret_cast<Buf*>(bb)->__nextInPool;
s_allocated.fetch_sub(1, std::memory_order_relaxed); s_allocated.fetch_sub(1, std::memory_order_relaxed);
free(reinterpret_cast<void *>(bb)); free(reinterpret_cast<void*>(bb));
bb = next; bb = next;
} }
@ -95,6 +98,8 @@ void Buf::freePool() noexcept
} }
long Buf::poolAllocated() noexcept long Buf::poolAllocated() noexcept
{ return s_allocated.load(std::memory_order_relaxed); } {
return s_allocated.load(std::memory_order_relaxed);
}
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -15,16 +15,16 @@
#define ZT_BUF_HPP #define ZT_BUF_HPP
#include "Constants.hpp" #include "Constants.hpp"
#include "Utils.hpp"
#include "SharedPtr.hpp"
#include "Mutex.hpp"
#include "TriviallyCopyable.hpp"
#include "FCV.hpp" #include "FCV.hpp"
#include "Mutex.hpp"
#include "SharedPtr.hpp"
#include "TriviallyCopyable.hpp"
#include "Utils.hpp"
#include <stdexcept>
#include <utility>
#include <algorithm> #include <algorithm>
#include <new> #include <new>
#include <stdexcept>
#include <utility>
// Buffers are 16384 bytes in size because this is the smallest size that can hold any packet // Buffers are 16384 bytes in size because this is the smallest size that can hold any packet
// and is a power of two. It needs to be a power of two because masking is significantly faster // and is a power of two. It needs to be a power of two because masking is significantly faster
@ -77,15 +77,14 @@ namespace ZeroTier {
* *
* @tparam U Type to overlap with data bytes in data union (can't be larger than ZT_BUF_MEM_SIZE) * @tparam U Type to overlap with data bytes in data union (can't be larger than ZT_BUF_MEM_SIZE)
*/ */
class Buf class Buf {
{ friend class SharedPtr<Buf>;
friend class SharedPtr< Buf >;
public: public:
// New and delete operators that allocate Buf instances from a shared lock-free memory pool. // New and delete operators that allocate Buf instances from a shared lock-free memory pool.
static void *operator new(std::size_t sz); static void* operator new(std::size_t sz);
static void operator delete(void *ptr); static void operator delete(void* ptr);
/** /**
* Raw data held in buffer * Raw data held in buffer
@ -113,19 +112,30 @@ public:
/** /**
* Slice is almost exactly like the built-in slice data structure in Go * Slice is almost exactly like the built-in slice data structure in Go
*/ */
struct Slice : TriviallyCopyable struct Slice : TriviallyCopyable {
ZT_INLINE Slice(const SharedPtr<Buf>& b_, const unsigned int s_, const unsigned int e_) noexcept
: b(b_)
, s(s_)
, e(e_)
{ {
ZT_INLINE Slice(const SharedPtr< Buf > &b_, const unsigned int s_, const unsigned int e_) noexcept: b(b_), s(s_), e(e_) }
{}
ZT_INLINE Slice() noexcept: b(), s(0), e(0) ZT_INLINE Slice() noexcept
{} : b()
, s(0)
, e(0)
{
}
ZT_INLINE operator bool() const noexcept ZT_INLINE operator bool() const noexcept
{ return (b); } {
return (b);
}
ZT_INLINE unsigned int size() const noexcept ZT_INLINE unsigned int size() const noexcept
{ return (e - s); } {
return (e - s);
}
ZT_INLINE void zero() noexcept ZT_INLINE void zero() noexcept
{ {
@ -137,7 +147,7 @@ public:
/** /**
* Buffer holding slice data * Buffer holding slice data
*/ */
SharedPtr< Buf > b; SharedPtr<Buf> b;
/** /**
* Index of start of data in slice * Index of start of data in slice
@ -153,11 +163,11 @@ public:
/** /**
* A vector of slices making up a packet that might span more than one buffer. * A vector of slices making up a packet that might span more than one buffer.
*/ */
class PacketVector : public ZeroTier::FCV< Slice, ZT_MAX_PACKET_FRAGMENTS > class PacketVector : public ZeroTier::FCV<Slice, ZT_MAX_PACKET_FRAGMENTS> {
{
public: public:
ZT_INLINE PacketVector() : ZeroTier::FCV< Slice, ZT_MAX_PACKET_FRAGMENTS >() ZT_INLINE PacketVector() : ZeroTier::FCV<Slice, ZT_MAX_PACKET_FRAGMENTS>()
{} {
}
ZT_INLINE unsigned int totalSize() const noexcept ZT_INLINE unsigned int totalSize() const noexcept
{ {
@ -173,7 +183,7 @@ public:
* @param b Destination buffer * @param b Destination buffer
* @return Size of data in destination or -1 on error * @return Size of data in destination or -1 on error
*/ */
ZT_INLINE int mergeCopy(Buf &b) const noexcept ZT_INLINE int mergeCopy(Buf& b) const noexcept
{ {
unsigned int size = 0; unsigned int size = 0;
for (PacketVector::const_iterator s(begin()); s != end(); ++s) { for (PacketVector::const_iterator s(begin()); s != end(); ++s) {
@ -182,7 +192,8 @@ public:
if (likely((size + rem) <= ZT_BUF_MEM_SIZE)) { if (likely((size + rem) <= ZT_BUF_MEM_SIZE)) {
Utils::copy(b.unsafeData + size, s->b->unsafeData + start, rem); Utils::copy(b.unsafeData + size, s->b->unsafeData + start, rem);
size += rem; size += rem;
} else { }
else {
return -1; return -1;
} }
} }
@ -200,8 +211,8 @@ public:
* @tparam F Type of copyFunction (typically inferred) * @tparam F Type of copyFunction (typically inferred)
* @return Size of data in destination or -1 on error * @return Size of data in destination or -1 on error
*/ */
template< typename F > template <typename F>
ZT_INLINE int mergeMap(Buf &b, const unsigned int simpleCopyBefore, F copyFunction) const noexcept ZT_INLINE int mergeMap(Buf& b, const unsigned int simpleCopyBefore, F copyFunction) const noexcept
{ {
unsigned int size = 0; unsigned int size = 0;
for (PacketVector::const_iterator s(begin()); s != end(); ++s) { for (PacketVector::const_iterator s(begin()); s != end(); ++s) {
@ -221,7 +232,8 @@ public:
copyFunction(b.unsafeData + size, s->b->unsafeData + start, rem); copyFunction(b.unsafeData + size, s->b->unsafeData + start, rem);
size += rem; size += rem;
} }
} else { }
else {
return -1; return -1;
} }
} }
@ -232,29 +244,31 @@ public:
/** /**
* Create a new uninitialized buffer with undefined contents (use clear() to zero if needed) * Create a new uninitialized buffer with undefined contents (use clear() to zero if needed)
*/ */
ZT_INLINE Buf() noexcept: __nextInPool(0), __refCount(0) ZT_INLINE Buf() noexcept
{} : __nextInPool(0)
, __refCount(0)
{
}
/** /**
* Create a new buffer and copy data into it * Create a new buffer and copy data into it
*/ */
ZT_INLINE Buf(const void *const data, const unsigned int len) noexcept: ZT_INLINE Buf(const void* const data, const unsigned int len) noexcept : __refCount(0)
__refCount(0)
{ {
Utils::copy(unsafeData, data, len); Utils::copy(unsafeData, data, len);
} }
ZT_INLINE Buf(const Buf &b2) noexcept: ZT_INLINE Buf(const Buf& b2) noexcept
__nextInPool(0), : __nextInPool(0)
__refCount(0) , __refCount(0)
{ {
Utils::copy< ZT_BUF_MEM_SIZE >(unsafeData, b2.unsafeData); Utils::copy<ZT_BUF_MEM_SIZE>(unsafeData, b2.unsafeData);
} }
ZT_INLINE Buf &operator=(const Buf &b2) noexcept ZT_INLINE Buf& operator=(const Buf& b2) noexcept
{ {
if (this != &b2) if (this != &b2)
Utils::copy< ZT_BUF_MEM_SIZE >(unsafeData, b2.unsafeData); Utils::copy<ZT_BUF_MEM_SIZE>(unsafeData, b2.unsafeData);
return *this; return *this;
} }
@ -267,8 +281,10 @@ public:
* @param ii Iterator to check * @param ii Iterator to check
* @return True if iterator has read past the size of the buffer * @return True if iterator has read past the size of the buffer
*/ */
static ZT_INLINE bool writeOverflow(const int &ii) noexcept static ZT_INLINE bool writeOverflow(const int& ii) noexcept
{ return ((ii - ZT_BUF_MEM_SIZE) > 0); } {
return ((ii - ZT_BUF_MEM_SIZE) > 0);
}
/** /**
* Check for overflow beyond the size of the data that should be in the buffer * Check for overflow beyond the size of the data that should be in the buffer
@ -280,15 +296,17 @@ public:
* @param size Size of data that should be in buffer * @param size Size of data that should be in buffer
* @return True if iterator has read past the size of the data * @return True if iterator has read past the size of the data
*/ */
static ZT_INLINE bool readOverflow(const int &ii, const unsigned int size) noexcept static ZT_INLINE bool readOverflow(const int& ii, const unsigned int size) noexcept
{ return ((ii - (int)size) > 0); } {
return ((ii - (int)size) > 0);
}
/** /**
* Set all memory to zero * Set all memory to zero
*/ */
ZT_INLINE void clear() noexcept ZT_INLINE void clear() noexcept
{ {
Utils::zero< ZT_BUF_MEM_SIZE >(unsafeData); Utils::zero<ZT_BUF_MEM_SIZE>(unsafeData);
} }
/** /**
@ -297,7 +315,7 @@ public:
* @param ii Index value-result parameter (incremented by 1) * @param ii Index value-result parameter (incremented by 1)
* @return Byte (undefined on overflow) * @return Byte (undefined on overflow)
*/ */
ZT_INLINE uint8_t rI8(int &ii) const noexcept ZT_INLINE uint8_t rI8(int& ii) const noexcept
{ {
const int s = ii++; const int s = ii++;
return unsafeData[(unsigned int)s & ZT_BUF_MEM_MASK]; return unsafeData[(unsigned int)s & ZT_BUF_MEM_MASK];
@ -309,16 +327,14 @@ public:
* @param ii Index value-result parameter (incremented by 2) * @param ii Index value-result parameter (incremented by 2)
* @return Integer (undefined on overflow) * @return Integer (undefined on overflow)
*/ */
ZT_INLINE uint16_t rI16(int &ii) const noexcept ZT_INLINE uint16_t rI16(int& ii) const noexcept
{ {
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
ii += 2; ii += 2;
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
return ( return (((uint16_t)unsafeData[s] << 8U) | (uint16_t)unsafeData[s + 1]);
((uint16_t)unsafeData[s] << 8U) |
(uint16_t)unsafeData[s + 1]);
#else #else
return Utils::ntoh(*reinterpret_cast<const uint16_t *>(unsafeData + s)); return Utils::ntoh(*reinterpret_cast<const uint16_t*>(unsafeData + s));
#endif #endif
} }
@ -328,18 +344,16 @@ public:
* @param ii Index value-result parameter (incremented by 4) * @param ii Index value-result parameter (incremented by 4)
* @return Integer (undefined on overflow) * @return Integer (undefined on overflow)
*/ */
ZT_INLINE uint32_t rI32(int &ii) const noexcept ZT_INLINE uint32_t rI32(int& ii) const noexcept
{ {
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
ii += 4; ii += 4;
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
return ( return (
((uint32_t)unsafeData[s] << 24U) | ((uint32_t)unsafeData[s] << 24U) | ((uint32_t)unsafeData[s + 1] << 16U)
((uint32_t)unsafeData[s + 1] << 16U) | | ((uint32_t)unsafeData[s + 2] << 8U) | (uint32_t)unsafeData[s + 3]);
((uint32_t)unsafeData[s + 2] << 8U) |
(uint32_t)unsafeData[s + 3]);
#else #else
return Utils::ntoh(*reinterpret_cast<const uint32_t *>(unsafeData + s)); return Utils::ntoh(*reinterpret_cast<const uint32_t*>(unsafeData + s));
#endif #endif
} }
@ -349,22 +363,18 @@ public:
* @param ii Index value-result parameter (incremented by 8) * @param ii Index value-result parameter (incremented by 8)
* @return Integer (undefined on overflow) * @return Integer (undefined on overflow)
*/ */
ZT_INLINE uint64_t rI64(int &ii) const noexcept ZT_INLINE uint64_t rI64(int& ii) const noexcept
{ {
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
ii += 8; ii += 8;
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
return ( return (
((uint64_t)unsafeData[s] << 56U) | ((uint64_t)unsafeData[s] << 56U) | ((uint64_t)unsafeData[s + 1] << 48U)
((uint64_t)unsafeData[s + 1] << 48U) | | ((uint64_t)unsafeData[s + 2] << 40U) | ((uint64_t)unsafeData[s + 3] << 32U)
((uint64_t)unsafeData[s + 2] << 40U) | | ((uint64_t)unsafeData[s + 4] << 24U) | ((uint64_t)unsafeData[s + 5] << 16U)
((uint64_t)unsafeData[s + 3] << 32U) | | ((uint64_t)unsafeData[s + 6] << 8U) | (uint64_t)unsafeData[s + 7]);
((uint64_t)unsafeData[s + 4] << 24U) |
((uint64_t)unsafeData[s + 5] << 16U) |
((uint64_t)unsafeData[s + 6] << 8U) |
(uint64_t)unsafeData[s + 7]);
#else #else
return Utils::ntoh(*reinterpret_cast<const uint64_t *>(unsafeData + s)); return Utils::ntoh(*reinterpret_cast<const uint64_t*>(unsafeData + s));
#endif #endif
} }
@ -383,8 +393,7 @@ public:
* @param obj Object to read * @param obj Object to read
* @return Bytes read or a negative value on unmarshal error (passed from object) or overflow * @return Bytes read or a negative value on unmarshal error (passed from object) or overflow
*/ */
template< typename T > template <typename T> ZT_INLINE int rO(int& ii, T& obj) const noexcept
ZT_INLINE int rO(int &ii, T &obj) const noexcept
{ {
if (likely(ii < ZT_BUF_MEM_SIZE)) { if (likely(ii < ZT_BUF_MEM_SIZE)) {
int ms = obj.unmarshal(unsafeData + ii, ZT_BUF_MEM_SIZE - ii); int ms = obj.unmarshal(unsafeData + ii, ZT_BUF_MEM_SIZE - ii);
@ -406,9 +415,9 @@ public:
* @param bufSize Capacity of buffer in bytes * @param bufSize Capacity of buffer in bytes
* @return Pointer to buf or NULL on overflow or error * @return Pointer to buf or NULL on overflow or error
*/ */
ZT_INLINE char *rS(int &ii, char *const buf, const unsigned int bufSize) const noexcept ZT_INLINE char* rS(int& ii, char* const buf, const unsigned int bufSize) const noexcept
{ {
const char *const s = (const char *)(unsafeData + ii); const char* const s = (const char*)(unsafeData + ii);
const int sii = ii; const int sii = ii;
while (ii < ZT_BUF_MEM_SIZE) { while (ii < ZT_BUF_MEM_SIZE) {
if (unsafeData[ii++] == 0) { if (unsafeData[ii++] == 0) {
@ -435,9 +444,9 @@ public:
* @param ii Index value-result parameter (incremented by length of string) * @param ii Index value-result parameter (incremented by length of string)
* @return Pointer to null-terminated C-style string or NULL on overflow or error * @return Pointer to null-terminated C-style string or NULL on overflow or error
*/ */
ZT_INLINE const char *rSnc(int &ii) const noexcept ZT_INLINE const char* rSnc(int& ii) const noexcept
{ {
const char *const s = (const char *)(unsafeData + ii); const char* const s = (const char*)(unsafeData + ii);
while (ii < ZT_BUF_MEM_SIZE) { while (ii < ZT_BUF_MEM_SIZE) {
if (unsafeData[ii++] == 0) if (unsafeData[ii++] == 0)
return s; return s;
@ -456,11 +465,11 @@ public:
* @param len Length of buffer * @param len Length of buffer
* @return Pointer to data or NULL on overflow or error * @return Pointer to data or NULL on overflow or error
*/ */
ZT_INLINE uint8_t *rB(int &ii, void *const bytes, const unsigned int len) const noexcept ZT_INLINE uint8_t* rB(int& ii, void* const bytes, const unsigned int len) const noexcept
{ {
if (likely(((ii += (int)len) <= ZT_BUF_MEM_SIZE))) { if (likely(((ii += (int)len) <= ZT_BUF_MEM_SIZE))) {
Utils::copy(bytes, unsafeData + ii, len); Utils::copy(bytes, unsafeData + ii, len);
return reinterpret_cast<uint8_t *>(bytes); return reinterpret_cast<uint8_t*>(bytes);
} }
return nullptr; return nullptr;
} }
@ -478,9 +487,9 @@ public:
* @param len Length of data field to obtain a pointer to * @param len Length of data field to obtain a pointer to
* @return Pointer to field or NULL on overflow * @return Pointer to field or NULL on overflow
*/ */
ZT_INLINE const uint8_t *rBnc(int &ii, unsigned int len) const noexcept ZT_INLINE const uint8_t* rBnc(int& ii, unsigned int len) const noexcept
{ {
const uint8_t *const b = unsafeData + ii; const uint8_t* const b = unsafeData + ii;
return ((ii += (int)len) <= ZT_BUF_MEM_SIZE) ? b : nullptr; return ((ii += (int)len) <= ZT_BUF_MEM_SIZE) ? b : nullptr;
} }
@ -490,8 +499,7 @@ public:
* @tparam I Static index * @tparam I Static index
* @return Value * @return Value
*/ */
template< unsigned int I > template <unsigned int I> ZT_INLINE uint8_t lI8() const noexcept
ZT_INLINE uint8_t lI8() const noexcept
{ {
static_assert(I < ZT_BUF_MEM_SIZE, "overflow"); static_assert(I < ZT_BUF_MEM_SIZE, "overflow");
return unsafeData[I]; return unsafeData[I];
@ -503,16 +511,13 @@ public:
* @tparam I Static index * @tparam I Static index
* @return Value * @return Value
*/ */
template< unsigned int I > template <unsigned int I> ZT_INLINE uint8_t lI16() const noexcept
ZT_INLINE uint8_t lI16() const noexcept
{ {
static_assert((I + 1) < ZT_BUF_MEM_SIZE, "overflow"); static_assert((I + 1) < ZT_BUF_MEM_SIZE, "overflow");
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
return ( return (((uint16_t)unsafeData[I] << 8U) | (uint16_t)unsafeData[I + 1]);
((uint16_t)unsafeData[I] << 8U) |
(uint16_t)unsafeData[I + 1]);
#else #else
return Utils::ntoh(*reinterpret_cast<const uint16_t *>(unsafeData + I)); return Utils::ntoh(*reinterpret_cast<const uint16_t*>(unsafeData + I));
#endif #endif
} }
@ -522,18 +527,15 @@ public:
* @tparam I Static index * @tparam I Static index
* @return Value * @return Value
*/ */
template< unsigned int I > template <unsigned int I> ZT_INLINE uint8_t lI32() const noexcept
ZT_INLINE uint8_t lI32() const noexcept
{ {
static_assert((I + 3) < ZT_BUF_MEM_SIZE, "overflow"); static_assert((I + 3) < ZT_BUF_MEM_SIZE, "overflow");
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
return ( return (
((uint32_t)unsafeData[I] << 24U) | ((uint32_t)unsafeData[I] << 24U) | ((uint32_t)unsafeData[I + 1] << 16U)
((uint32_t)unsafeData[I + 1] << 16U) | | ((uint32_t)unsafeData[I + 2] << 8U) | (uint32_t)unsafeData[I + 3]);
((uint32_t)unsafeData[I + 2] << 8U) |
(uint32_t)unsafeData[I + 3]);
#else #else
return Utils::ntoh(*reinterpret_cast<const uint32_t *>(unsafeData + I)); return Utils::ntoh(*reinterpret_cast<const uint32_t*>(unsafeData + I));
#endif #endif
} }
@ -543,22 +545,17 @@ public:
* @tparam I Static index * @tparam I Static index
* @return Value * @return Value
*/ */
template< unsigned int I > template <unsigned int I> ZT_INLINE uint8_t lI64() const noexcept
ZT_INLINE uint8_t lI64() const noexcept
{ {
static_assert((I + 7) < ZT_BUF_MEM_SIZE, "overflow"); static_assert((I + 7) < ZT_BUF_MEM_SIZE, "overflow");
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
return ( return (
((uint64_t)unsafeData[I] << 56U) | ((uint64_t)unsafeData[I] << 56U) | ((uint64_t)unsafeData[I + 1] << 48U)
((uint64_t)unsafeData[I + 1] << 48U) | | ((uint64_t)unsafeData[I + 2] << 40U) | ((uint64_t)unsafeData[I + 3] << 32U)
((uint64_t)unsafeData[I + 2] << 40U) | | ((uint64_t)unsafeData[I + 4] << 24U) | ((uint64_t)unsafeData[I + 5] << 16U)
((uint64_t)unsafeData[I + 3] << 32U) | | ((uint64_t)unsafeData[I + 6] << 8U) | (uint64_t)unsafeData[I + 7]);
((uint64_t)unsafeData[I + 4] << 24U) |
((uint64_t)unsafeData[I + 5] << 16U) |
((uint64_t)unsafeData[I + 6] << 8U) |
(uint64_t)unsafeData[I + 7]);
#else #else
return Utils::ntoh(*reinterpret_cast<const uint64_t *>(unsafeData + I)); return Utils::ntoh(*reinterpret_cast<const uint64_t*>(unsafeData + I));
#endif #endif
} }
@ -585,11 +582,9 @@ public:
{ {
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
return ( return (((uint16_t)unsafeData[s] << 8U) | (uint16_t)unsafeData[s + 1]);
((uint16_t)unsafeData[s] << 8U) |
(uint16_t)unsafeData[s + 1]);
#else #else
return Utils::ntoh(*reinterpret_cast<const uint16_t *>(unsafeData + s)); return Utils::ntoh(*reinterpret_cast<const uint16_t*>(unsafeData + s));
#endif #endif
} }
@ -605,12 +600,10 @@ public:
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
return ( return (
((uint32_t)unsafeData[s] << 24U) | ((uint32_t)unsafeData[s] << 24U) | ((uint32_t)unsafeData[s + 1] << 16U)
((uint32_t)unsafeData[s + 1] << 16U) | | ((uint32_t)unsafeData[s + 2] << 8U) | (uint32_t)unsafeData[s + 3]);
((uint32_t)unsafeData[s + 2] << 8U) |
(uint32_t)unsafeData[s + 3]);
#else #else
return Utils::ntoh(*reinterpret_cast<const uint32_t *>(unsafeData + s)); return Utils::ntoh(*reinterpret_cast<const uint32_t*>(unsafeData + s));
#endif #endif
} }
@ -626,16 +619,12 @@ public:
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK; const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
return ( return (
((uint64_t)unsafeData[s] << 56U) | ((uint64_t)unsafeData[s] << 56U) | ((uint64_t)unsafeData[s + 1] << 48U)
((uint64_t)unsafeData[s + 1] << 48U) | | ((uint64_t)unsafeData[s + 2] << 40U) | ((uint64_t)unsafeData[s + 3] << 32U)
((uint64_t)unsafeData[s + 2] << 40U) | | ((uint64_t)unsafeData[s + 4] << 24U) | ((uint64_t)unsafeData[s + 5] << 16U)
((uint64_t)unsafeData[s + 3] << 32U) | | ((uint64_t)unsafeData[s + 6] << 8U) | (uint64_t)unsafeData[s + 7]);
((uint64_t)unsafeData[s + 4] << 24U) |
((uint64_t)unsafeData[s + 5] << 16U) |
((uint64_t)unsafeData[s + 6] << 8U) |
(uint64_t)unsafeData[s + 7]);
#else #else
return Utils::ntoh(*reinterpret_cast<const uint64_t *>(unsafeData + s)); return Utils::ntoh(*reinterpret_cast<const uint64_t*>(unsafeData + s));
#endif #endif
} }
@ -645,7 +634,7 @@ public:
* @param ii Index value-result parameter (incremented by 1) * @param ii Index value-result parameter (incremented by 1)
* @param n Byte * @param n Byte
*/ */
ZT_INLINE void wI8(int &ii, const uint8_t n) noexcept ZT_INLINE void wI8(int& ii, const uint8_t n) noexcept
{ {
const int s = ii++; const int s = ii++;
unsafeData[(unsigned int)s & ZT_BUF_MEM_MASK] = n; unsafeData[(unsigned int)s & ZT_BUF_MEM_MASK] = n;
@ -657,7 +646,7 @@ public:
* @param ii Index value-result parameter (incremented by 2) * @param ii Index value-result parameter (incremented by 2)
* @param n Integer * @param n Integer
*/ */
ZT_INLINE void wI16(int &ii, const uint16_t n) noexcept ZT_INLINE void wI16(int& ii, const uint16_t n) noexcept
{ {
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
ii += 2; ii += 2;
@ -665,7 +654,7 @@ public:
unsafeData[s] = (uint8_t)(n >> 8U); unsafeData[s] = (uint8_t)(n >> 8U);
unsafeData[s + 1] = (uint8_t)n; unsafeData[s + 1] = (uint8_t)n;
#else #else
*reinterpret_cast<uint16_t *>(unsafeData + s) = Utils::hton(n); *reinterpret_cast<uint16_t*>(unsafeData + s) = Utils::hton(n);
#endif #endif
} }
@ -675,7 +664,7 @@ public:
* @param ii Index value-result parameter (incremented by 4) * @param ii Index value-result parameter (incremented by 4)
* @param n Integer * @param n Integer
*/ */
ZT_INLINE void wI32(int &ii, const uint32_t n) noexcept ZT_INLINE void wI32(int& ii, const uint32_t n) noexcept
{ {
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
ii += 4; ii += 4;
@ -685,7 +674,7 @@ public:
unsafeData[s + 2] = (uint8_t)(n >> 8U); unsafeData[s + 2] = (uint8_t)(n >> 8U);
unsafeData[s + 3] = (uint8_t)n; unsafeData[s + 3] = (uint8_t)n;
#else #else
*reinterpret_cast<uint32_t *>(unsafeData + s) = Utils::hton(n); *reinterpret_cast<uint32_t*>(unsafeData + s) = Utils::hton(n);
#endif #endif
} }
@ -695,7 +684,7 @@ public:
* @param ii Index value-result parameter (incremented by 8) * @param ii Index value-result parameter (incremented by 8)
* @param n Integer * @param n Integer
*/ */
ZT_INLINE void wI64(int &ii, const uint64_t n) noexcept ZT_INLINE void wI64(int& ii, const uint64_t n) noexcept
{ {
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK; const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
ii += 8; ii += 8;
@ -709,7 +698,7 @@ public:
unsafeData[s + 6] = (uint8_t)(n >> 8U); unsafeData[s + 6] = (uint8_t)(n >> 8U);
unsafeData[s + 7] = (uint8_t)n; unsafeData[s + 7] = (uint8_t)n;
#else #else
*reinterpret_cast<uint64_t *>(unsafeData + s) = Utils::hton(n); *reinterpret_cast<uint64_t*>(unsafeData + s) = Utils::hton(n);
#endif #endif
} }
@ -720,15 +709,15 @@ public:
* @param ii Index value-result parameter (incremented by size of object) * @param ii Index value-result parameter (incremented by size of object)
* @param t Object to write * @param t Object to write
*/ */
template< typename T > template <typename T> ZT_INLINE void wO(int& ii, T& t) noexcept
ZT_INLINE void wO(int &ii, T &t) noexcept
{ {
const int s = ii; const int s = ii;
if (likely((s + T::marshalSizeMax()) <= ZT_BUF_MEM_SIZE)) { if (likely((s + T::marshalSizeMax()) <= ZT_BUF_MEM_SIZE)) {
int ms = t.marshal(unsafeData + s); int ms = t.marshal(unsafeData + s);
if (ms > 0) if (ms > 0)
ii += ms; ii += ms;
} else { }
else {
ii += T::marshalSizeMax(); // mark as overflowed even if we didn't do anything ii += T::marshalSizeMax(); // mark as overflowed even if we didn't do anything
} }
} }
@ -739,7 +728,7 @@ public:
* @param ii Index value-result parameter (incremented by length of string) * @param ii Index value-result parameter (incremented by length of string)
* @param s String to write (writes an empty string if this is NULL) * @param s String to write (writes an empty string if this is NULL)
*/ */
ZT_INLINE void wS(int &ii, const char *s) noexcept ZT_INLINE void wS(int& ii, const char* s) noexcept
{ {
if (s) { if (s) {
char c; char c;
@ -747,7 +736,8 @@ public:
c = *(s++); c = *(s++);
wI8(ii, (uint8_t)c); wI8(ii, (uint8_t)c);
} while (c); } while (c);
} else { }
else {
wI8(ii, 0); wI8(ii, 0);
} }
} }
@ -759,7 +749,7 @@ public:
* @param bytes Bytes to write * @param bytes Bytes to write
* @param len Size of data in bytes * @param len Size of data in bytes
*/ */
ZT_INLINE void wB(int &ii, const void *const bytes, const unsigned int len) noexcept ZT_INLINE void wB(int& ii, const void* const bytes, const unsigned int len) noexcept
{ {
const int s = ii; const int s = ii;
if (likely((ii += (int)len) <= ZT_BUF_MEM_SIZE)) if (likely((ii += (int)len) <= ZT_BUF_MEM_SIZE))
@ -772,7 +762,7 @@ public:
* @param ii Index value-result parameter (incremented by len) * @param ii Index value-result parameter (incremented by len)
* @param len Number of zero bytes to write * @param len Number of zero bytes to write
*/ */
ZT_INLINE void wZ(int &ii, const unsigned int len) noexcept ZT_INLINE void wZ(int& ii, const unsigned int len) noexcept
{ {
const int s = ii; const int s = ii;
if (likely((ii += (int)len) <= ZT_BUF_MEM_SIZE)) if (likely((ii += (int)len) <= ZT_BUF_MEM_SIZE))
@ -785,7 +775,7 @@ public:
* @param ii Index value-result parameter (incremented by len) * @param ii Index value-result parameter (incremented by len)
* @param len Number of random bytes to write * @param len Number of random bytes to write
*/ */
ZT_INLINE void wR(int &ii, const unsigned int len) noexcept ZT_INLINE void wR(int& ii, const unsigned int len) noexcept
{ {
const int s = ii; const int s = ii;
if (likely((ii += (int)len) <= ZT_BUF_MEM_SIZE)) if (likely((ii += (int)len) <= ZT_BUF_MEM_SIZE))
@ -810,7 +800,7 @@ public:
unsafeData[s] = (uint8_t)(n >> 8U); unsafeData[s] = (uint8_t)(n >> 8U);
unsafeData[s + 1] = (uint8_t)n; unsafeData[s + 1] = (uint8_t)n;
#else #else
*reinterpret_cast<uint16_t *>(unsafeData + s) = Utils::hton(n); *reinterpret_cast<uint16_t*>(unsafeData + s) = Utils::hton(n);
#endif #endif
} }
@ -826,7 +816,7 @@ public:
unsafeData[s + 2] = (uint8_t)(n >> 8U); unsafeData[s + 2] = (uint8_t)(n >> 8U);
unsafeData[s + 3] = (uint8_t)n; unsafeData[s + 3] = (uint8_t)n;
#else #else
*reinterpret_cast<uint32_t *>(unsafeData + s) = Utils::hton(n); *reinterpret_cast<uint32_t*>(unsafeData + s) = Utils::hton(n);
#endif #endif
} }
@ -846,7 +836,7 @@ public:
unsafeData[s + 6] = (uint8_t)(n >> 8U); unsafeData[s + 6] = (uint8_t)(n >> 8U);
unsafeData[s + 7] = (uint8_t)n; unsafeData[s + 7] = (uint8_t)n;
#else #else
*reinterpret_cast<uint64_t *>(unsafeData + s) = Utils::hton(n); *reinterpret_cast<uint64_t*>(unsafeData + s) = Utils::hton(n);
#endif #endif
} }
@ -854,11 +844,13 @@ public:
* @return Capacity of this buffer (usable size of data.bytes) * @return Capacity of this buffer (usable size of data.bytes)
*/ */
static constexpr unsigned int capacity() noexcept static constexpr unsigned int capacity() noexcept
{ return ZT_BUF_MEM_SIZE; } {
return ZT_BUF_MEM_SIZE;
}
private: private:
volatile uintptr_t __nextInPool; volatile uintptr_t __nextInPool;
std::atomic< int > __refCount; std::atomic<int> __refCount;
}; };
} // namespace ZeroTier } // namespace ZeroTier

File diff suppressed because it is too large Load diff

View file

@ -35,18 +35,20 @@ namespace ZeroTier {
/** /**
* A combined Curve25519 ECDH and Ed25519 signature engine * A combined Curve25519 ECDH and Ed25519 signature engine
*/ */
class C25519 class C25519 {
{ public:
public:
/** /**
* Generate a set of two 25519 keys: a C25519 ECDH key pair and an Ed25519 EDDSA key pair. * Generate a set of two 25519 keys: a C25519 ECDH key pair and an Ed25519 EDDSA key pair.
*/ */
static void generateCombined(uint8_t pub[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],uint8_t priv[ZT_C25519_COMBINED_PRIVATE_KEY_SIZE]); static void generateCombined(
uint8_t pub[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],
uint8_t priv[ZT_C25519_COMBINED_PRIVATE_KEY_SIZE]);
/** /**
* Generate a C25519 ECDH key pair only. * Generate a C25519 ECDH key pair only.
*/ */
static void generateC25519(uint8_t pub[ZT_C25519_ECDH_PUBLIC_KEY_SIZE],uint8_t priv[ZT_C25519_ECDH_PRIVATE_KEY_SIZE]); static void
generateC25519(uint8_t pub[ZT_C25519_ECDH_PUBLIC_KEY_SIZE], uint8_t priv[ZT_C25519_ECDH_PRIVATE_KEY_SIZE]);
/** /**
* Generate a key pair satisfying a condition * Generate a key pair satisfying a condition
@ -61,16 +63,19 @@ public:
* @return Key pair where cond(kp) returns true * @return Key pair where cond(kp) returns true
* @tparam F Type of 'cond' * @tparam F Type of 'cond'
*/ */
template<typename F> template <typename F>
static ZT_INLINE void generateSatisfying(F cond,uint8_t pub[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],uint8_t priv[ZT_C25519_COMBINED_PRIVATE_KEY_SIZE]) static ZT_INLINE void generateSatisfying(
F cond,
uint8_t pub[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],
uint8_t priv[ZT_C25519_COMBINED_PRIVATE_KEY_SIZE])
{ {
Utils::getSecureRandom(priv,ZT_C25519_COMBINED_PRIVATE_KEY_SIZE); Utils::getSecureRandom(priv, ZT_C25519_COMBINED_PRIVATE_KEY_SIZE);
s_calcPubED(pub, priv); // do Ed25519 key -- bytes 32-63 of pub and priv s_calcPubED(pub, priv); // do Ed25519 key -- bytes 32-63 of pub and priv
do { do {
++(((uint64_t *)priv)[1]); ++(((uint64_t*)priv)[1]);
--(((uint64_t *)priv)[2]); --(((uint64_t*)priv)[2]);
s_calcPubDH(pub, priv); // keep regenerating bytes 0-31 until satisfied s_calcPubDH(pub, priv); // keep regenerating bytes 0-31 until satisfied
} while (!cond(pub)); } while (! cond(pub));
} }
/** /**
@ -83,7 +88,10 @@ public:
* @param their Their public key * @param their Their public key
* @param rawkey Buffer to receive raw (not hashed) agreed upon key * @param rawkey Buffer to receive raw (not hashed) agreed upon key
*/ */
static void agree(const uint8_t mine[ZT_C25519_ECDH_PRIVATE_KEY_SIZE],const uint8_t their[ZT_C25519_ECDH_PUBLIC_KEY_SIZE],uint8_t rawkey[ZT_C25519_ECDH_SHARED_SECRET_SIZE]); static void agree(
const uint8_t mine[ZT_C25519_ECDH_PRIVATE_KEY_SIZE],
const uint8_t their[ZT_C25519_ECDH_PUBLIC_KEY_SIZE],
uint8_t rawkey[ZT_C25519_ECDH_SHARED_SECRET_SIZE]);
/** /**
* Sign a message with a sender's key pair * Sign a message with a sender's key pair
@ -102,7 +110,12 @@ public:
* @param len Length of message in bytes * @param len Length of message in bytes
* @param signature Buffer to fill with signature -- MUST be 96 bytes in length * @param signature Buffer to fill with signature -- MUST be 96 bytes in length
*/ */
static void sign(const uint8_t myPrivate[ZT_C25519_COMBINED_PRIVATE_KEY_SIZE],const uint8_t myPublic[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],const void *msg,unsigned int len,void *signature); static void sign(
const uint8_t myPrivate[ZT_C25519_COMBINED_PRIVATE_KEY_SIZE],
const uint8_t myPublic[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],
const void* msg,
unsigned int len,
void* signature);
/** /**
* Verify a message's signature * Verify a message's signature
@ -114,16 +127,21 @@ public:
* @param siglen Length of signature in bytes * @param siglen Length of signature in bytes
* @return True if signature is valid and the message is authentic and unmodified * @return True if signature is valid and the message is authentic and unmodified
*/ */
static bool verify(const uint8_t their[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],const void *msg,unsigned int len,const void *signature,unsigned int siglen); static bool verify(
const uint8_t their[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE],
const void* msg,
unsigned int len,
const void* signature,
unsigned int siglen);
private: private:
// derive first 32 bytes of kp.pub from first 32 bytes of kp.priv // derive first 32 bytes of kp.pub from first 32 bytes of kp.priv
// this is the ECDH key // this is the ECDH key
static void s_calcPubDH(uint8_t *pub, const uint8_t *priv); static void s_calcPubDH(uint8_t* pub, const uint8_t* priv);
// derive 2nd 32 bytes of kp.pub from 2nd 32 bytes of kp.priv // derive 2nd 32 bytes of kp.pub from 2nd 32 bytes of kp.priv
// this is the Ed25519 sign/verify key // this is the Ed25519 sign/verify key
static void s_calcPubED(uint8_t *pub, const uint8_t *priv); static void s_calcPubED(uint8_t* pub, const uint8_t* priv);
}; };
} // namespace ZeroTier } // namespace ZeroTier

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,4 @@
cmake_minimum_required (VERSION 3.0) cmake_minimum_required(VERSION 3.0)
project(zt_core) project(zt_core)
configure_file( configure_file(
@ -61,7 +61,7 @@ set(core_headers
Utils.hpp Utils.hpp
VL1.hpp VL1.hpp
VL2.hpp VL2.hpp
) )
set(core_src set(core_src
AES.cpp AES.cpp
@ -102,22 +102,22 @@ set(core_src
Utils.cpp Utils.cpp
VL1.cpp VL1.cpp
VL2.cpp VL2.cpp
) )
add_library(${PROJECT_NAME} STATIC ${core_src} ${core_headers}) add_library(${PROJECT_NAME} STATIC ${core_src} ${core_headers})
target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_BINARY_DIR}) target_include_directories(${PROJECT_NAME} PRIVATE ${CMAKE_BINARY_DIR})
if(WIN32) if (WIN32)
set(libs ${libs} wsock32 ws2_32 rpcrt4 iphlpapi) set(libs ${libs} wsock32 ws2_32 rpcrt4 iphlpapi)
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17)
else(WIN32) else (WIN32)
set(libs ${libs} pthread) set(libs ${libs} pthread)
if (APPLE) if (APPLE)
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_17)
else(APPLE) else (APPLE)
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11) target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_11)
endif(APPLE) endif (APPLE)
endif(WIN32) endif (WIN32)
add_executable(zt_core_tests Tests.h Tests.cpp) add_executable(zt_core_tests Tests.h Tests.cpp)
target_compile_definitions(zt_core_tests PRIVATE ZT_ENABLE_TESTS=1 ZT_STANDALONE_TESTS=1) target_compile_definitions(zt_core_tests PRIVATE ZT_ENABLE_TESTS=1 ZT_STANDALONE_TESTS=1)

View file

@ -25,14 +25,11 @@ namespace ZeroTier {
* graph around from function to function as needed. It's cleaner and probably * graph around from function to function as needed. It's cleaner and probably
* faster than passing clock, ticks, and tPtr around everywhere. * faster than passing clock, ticks, and tPtr around everywhere.
*/ */
class CallContext class CallContext {
{ public:
public: ZT_INLINE CallContext(const int64_t c, const int64_t t, void* const p) : clock(c), ticks(t), tPtr(p)
ZT_INLINE CallContext(const int64_t c, const int64_t t, void *const p) : {
clock(c), }
ticks(t),
tPtr(p)
{}
/** /**
* Real world time in milliseconds since Unix epoch or -1 if unknown. * Real world time in milliseconds since Unix epoch or -1 if unknown.
@ -56,7 +53,7 @@ public:
* By passing this back to callbacks state can be kept by the caller using * By passing this back to callbacks state can be kept by the caller using
* a mechanism that is faster (on most platforms) than thread-local storage. * a mechanism that is faster (on most platforms) than thread-local storage.
*/ */
void *const tPtr; void* const tPtr;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -12,9 +12,10 @@
/****/ /****/
#include "CapabilityCredential.hpp" #include "CapabilityCredential.hpp"
#include "Utils.hpp"
#include "Constants.hpp" #include "Constants.hpp"
#include "MAC.hpp" #include "MAC.hpp"
#include "Utils.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -22,26 +23,26 @@ CapabilityCredential::CapabilityCredential(
const uint32_t id, const uint32_t id,
const uint64_t nwid, const uint64_t nwid,
const int64_t timestamp, const int64_t timestamp,
const ZT_VirtualNetworkRule *const rules, const ZT_VirtualNetworkRule* const rules,
const unsigned int ruleCount) noexcept: const unsigned int ruleCount) noexcept
m_nwid(nwid), : m_nwid(nwid)
m_timestamp(timestamp), , m_timestamp(timestamp)
m_id(id), , m_id(id)
m_ruleCount((ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES), , m_ruleCount((ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES)
m_signatureLength(0) , m_signatureLength(0)
{ {
Utils::zero< sizeof(m_rules) >(m_rules); Utils::zero<sizeof(m_rules)>(m_rules);
if (m_ruleCount > 0) if (m_ruleCount > 0)
Utils::copy(m_rules, rules, sizeof(ZT_VirtualNetworkRule) * m_ruleCount); Utils::copy(m_rules, rules, sizeof(ZT_VirtualNetworkRule) * m_ruleCount);
Utils::zero< sizeof(m_signature) >(m_signature); Utils::zero<sizeof(m_signature)>(m_signature);
} }
bool CapabilityCredential::sign(const Identity &from, const Address &to) noexcept bool CapabilityCredential::sign(const Identity& from, const Address& to) noexcept
{ {
uint8_t buf[ZT_CAPABILITY_MARSHAL_SIZE_MAX + 16]; uint8_t buf[ZT_CAPABILITY_MARSHAL_SIZE_MAX + 16];
m_issuedTo = to; m_issuedTo = to;
m_signedBy = from.address(); m_signedBy = from.address();
m_signatureLength = from.sign(buf, (unsigned int) marshal(buf, true), m_signature, sizeof(m_signature)); m_signatureLength = from.sign(buf, (unsigned int)marshal(buf, true), m_signature, sizeof(m_signature));
return m_signatureLength > 0; return m_signatureLength > 0;
} }
@ -50,16 +51,16 @@ int CapabilityCredential::marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX],
int p = 0; int p = 0;
if (forSign) { if (forSign) {
for (int k = 0;k < 8;++k) for (int k = 0; k < 8; ++k)
data[p++] = 0x7f; data[p++] = 0x7f;
} }
Utils::storeBigEndian<uint64_t>(data + p, m_nwid); Utils::storeBigEndian<uint64_t>(data + p, m_nwid);
Utils::storeBigEndian<uint64_t>(data + p + 8, (uint64_t) m_timestamp); Utils::storeBigEndian<uint64_t>(data + p + 8, (uint64_t)m_timestamp);
Utils::storeBigEndian<uint32_t>(data + p + 16, m_id); Utils::storeBigEndian<uint32_t>(data + p + 16, m_id);
p += 20; p += 20;
Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_ruleCount); Utils::storeBigEndian<uint16_t>(data + p, (uint16_t)m_ruleCount);
p += 2; p += 2;
p += CapabilityCredential::marshalVirtualNetworkRules(data + p, m_rules, m_ruleCount); p += CapabilityCredential::marshalVirtualNetworkRules(data + p, m_rules, m_ruleCount);
@ -67,18 +68,18 @@ int CapabilityCredential::marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX],
// chain length. This is deprecated so set the max chain length to one. // chain length. This is deprecated so set the max chain length to one.
data[p++] = (uint8_t)1; data[p++] = (uint8_t)1;
if (!forSign) { if (! forSign) {
m_issuedTo.copyTo(data + p); m_issuedTo.copyTo(data + p);
m_signedBy.copyTo(data + p + ZT_ADDRESS_LENGTH); m_signedBy.copyTo(data + p + ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH + ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH + ZT_ADDRESS_LENGTH;
data[p++] = 1; // LEGACY: old versions require a reserved byte here data[p++] = 1; // LEGACY: old versions require a reserved byte here
Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_signatureLength); Utils::storeBigEndian<uint16_t>(data + p, (uint16_t)m_signatureLength);
p += 2; p += 2;
Utils::copy(data + p, m_signature, m_signatureLength); Utils::copy(data + p, m_signature, m_signatureLength);
p += (int)m_signatureLength; p += (int)m_signatureLength;
// LEGACY: older versions supported more than one record terminated by a zero address. // LEGACY: older versions supported more than one record terminated by a zero address.
for (int k = 0;k < ZT_ADDRESS_LENGTH;++k) for (int k = 0; k < ZT_ADDRESS_LENGTH; ++k)
data[p++] = 0; data[p++] = 0;
} }
@ -86,20 +87,20 @@ int CapabilityCredential::marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX],
data[p++] = 0; // uint16_t size of additional fields, currently 0 data[p++] = 0; // uint16_t size of additional fields, currently 0
if (forSign) { if (forSign) {
for (int k = 0;k < 8;++k) for (int k = 0; k < 8; ++k)
data[p++] = 0x7f; data[p++] = 0x7f;
} }
return p; return p;
} }
int CapabilityCredential::unmarshal(const uint8_t *data, int len) noexcept int CapabilityCredential::unmarshal(const uint8_t* data, int len) noexcept
{ {
if (len < 22) if (len < 22)
return -1; return -1;
m_nwid = Utils::loadBigEndian<uint64_t>(data); m_nwid = Utils::loadBigEndian<uint64_t>(data);
m_timestamp = (int64_t) Utils::loadBigEndian<uint64_t>(data + 8); m_timestamp = (int64_t)Utils::loadBigEndian<uint64_t>(data + 8);
m_id = Utils::loadBigEndian<uint32_t>(data + 16); m_id = Utils::loadBigEndian<uint32_t>(data + 16);
const unsigned int rc = Utils::loadBigEndian<uint16_t>(data + 20); const unsigned int rc = Utils::loadBigEndian<uint16_t>(data + 20);
@ -118,13 +119,13 @@ int CapabilityCredential::unmarshal(const uint8_t *data, int len) noexcept
// this feature was never used, just set the signature and issued to and other related // this feature was never used, just set the signature and issued to and other related
// fields each time and we should only ever see one. If there's more than one and the // fields each time and we should only ever see one. If there's more than one and the
// last is not the controller, this credential will just fail validity check. // last is not the controller, this credential will just fail validity check.
for (unsigned int i = 0;;++i) { for (unsigned int i = 0;; ++i) {
if ((p + ZT_ADDRESS_LENGTH) > len) if ((p + ZT_ADDRESS_LENGTH) > len)
return -1; return -1;
const Address to(data + p); const Address to(data + p);
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
if (!to) if (! to)
break; break;
m_issuedTo = to; m_issuedTo = to;
@ -137,10 +138,10 @@ int CapabilityCredential::unmarshal(const uint8_t *data, int len) noexcept
return -1; return -1;
m_signatureLength = Utils::loadBigEndian<uint16_t>(data + p); m_signatureLength = Utils::loadBigEndian<uint16_t>(data + p);
p += 2; p += 2;
if ((m_signatureLength > sizeof(m_signature)) || ((p + (int) m_signatureLength) > len)) if ((m_signatureLength > sizeof(m_signature)) || ((p + (int)m_signatureLength) > len))
return -1; return -1;
Utils::copy(m_signature, data + p, m_signatureLength); Utils::copy(m_signature, data + p, m_signatureLength);
p += (int) m_signatureLength; p += (int)m_signatureLength;
} }
if ((p + 2) > len) if ((p + 2) > len)
@ -153,12 +154,15 @@ int CapabilityCredential::unmarshal(const uint8_t *data, int len) noexcept
return p; return p;
} }
int CapabilityCredential::marshalVirtualNetworkRules(uint8_t *data, const ZT_VirtualNetworkRule *const rules, const unsigned int ruleCount) noexcept int CapabilityCredential::marshalVirtualNetworkRules(
uint8_t* data,
const ZT_VirtualNetworkRule* const rules,
const unsigned int ruleCount) noexcept
{ {
int p = 0; int p = 0;
for (unsigned int i = 0;i < ruleCount;++i) { for (unsigned int i = 0; i < ruleCount; ++i) {
data[p++] = rules[i].t; data[p++] = rules[i].t;
switch ((ZT_VirtualNetworkRuleType) (rules[i].t & 0x3fU)) { switch ((ZT_VirtualNetworkRuleType)(rules[i].t & 0x3fU)) {
default: default:
data[p++] = 0; data[p++] = 0;
break; break;
@ -201,10 +205,10 @@ int CapabilityCredential::marshalVirtualNetworkRules(uint8_t *data, const ZT_Vir
case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE:
case ZT_NETWORK_RULE_MATCH_IPV4_DEST: case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
data[p++] = 5; data[p++] = 5;
data[p++] = reinterpret_cast<const uint8_t *>(&(rules[i].v.ipv4.ip))[0]; data[p++] = reinterpret_cast<const uint8_t*>(&(rules[i].v.ipv4.ip))[0];
data[p++] = reinterpret_cast<const uint8_t *>(&(rules[i].v.ipv4.ip))[1]; data[p++] = reinterpret_cast<const uint8_t*>(&(rules[i].v.ipv4.ip))[1];
data[p++] = reinterpret_cast<const uint8_t *>(&(rules[i].v.ipv4.ip))[2]; data[p++] = reinterpret_cast<const uint8_t*>(&(rules[i].v.ipv4.ip))[2];
data[p++] = reinterpret_cast<const uint8_t *>(&(rules[i].v.ipv4.ip))[3]; data[p++] = reinterpret_cast<const uint8_t*>(&(rules[i].v.ipv4.ip))[3];
data[p++] = rules[i].v.ipv4.mask; data[p++] = rules[i].v.ipv4.mask;
break; break;
case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
@ -277,7 +281,9 @@ int CapabilityCredential::marshalVirtualNetworkRules(uint8_t *data, const ZT_Vir
data[p++] = 19; data[p++] = 19;
Utils::storeBigEndian<uint64_t>(data + p, rules[i].v.intRange.start); Utils::storeBigEndian<uint64_t>(data + p, rules[i].v.intRange.start);
p += 8; p += 8;
Utils::storeBigEndian<uint64_t>(data + p, rules[i].v.intRange.start + (uint64_t) rules[i].v.intRange.end); Utils::storeBigEndian<uint64_t>(
data + p,
rules[i].v.intRange.start + (uint64_t)rules[i].v.intRange.end);
p += 8; p += 8;
Utils::storeBigEndian<uint16_t>(data + p, rules[i].v.intRange.idx); Utils::storeBigEndian<uint16_t>(data + p, rules[i].v.intRange.idx);
p += 2; p += 2;
@ -288,7 +294,12 @@ int CapabilityCredential::marshalVirtualNetworkRules(uint8_t *data, const ZT_Vir
return p; return p;
} }
int CapabilityCredential::unmarshalVirtualNetworkRules(const uint8_t *const data, const int len, ZT_VirtualNetworkRule *const rules, unsigned int &ruleCount, const unsigned int maxRuleCount) noexcept int CapabilityCredential::unmarshalVirtualNetworkRules(
const uint8_t* const data,
const int len,
ZT_VirtualNetworkRule* const rules,
unsigned int& ruleCount,
const unsigned int maxRuleCount) noexcept
{ {
int p = 0; int p = 0;
unsigned int rc = 0; unsigned int rc = 0;
@ -296,16 +307,17 @@ int CapabilityCredential::unmarshalVirtualNetworkRules(const uint8_t *const data
if (p >= len) if (p >= len)
return -1; return -1;
rules[ruleCount].t = data[p++]; rules[ruleCount].t = data[p++];
const int fieldLen = (int) data[p++]; const int fieldLen = (int)data[p++];
if ((p + fieldLen) > len) if ((p + fieldLen) > len)
return -1; return -1;
switch ((ZT_VirtualNetworkRuleType) (rules[ruleCount].t & 0x3fU)) { switch ((ZT_VirtualNetworkRuleType)(rules[ruleCount].t & 0x3fU)) {
default: default:
break; break;
case ZT_NETWORK_RULE_ACTION_TEE: case ZT_NETWORK_RULE_ACTION_TEE:
case ZT_NETWORK_RULE_ACTION_WATCH: case ZT_NETWORK_RULE_ACTION_WATCH:
case ZT_NETWORK_RULE_ACTION_REDIRECT: case ZT_NETWORK_RULE_ACTION_REDIRECT:
if ((p + 14) > len) return -1; if ((p + 14) > len)
return -1;
rules[ruleCount].v.fwd.address = Utils::loadBigEndian<uint64_t>(data + p); rules[ruleCount].v.fwd.address = Utils::loadBigEndian<uint64_t>(data + p);
p += 8; p += 8;
rules[ruleCount].v.fwd.flags = Utils::loadBigEndian<uint32_t>(data + p); rules[ruleCount].v.fwd.flags = Utils::loadBigEndian<uint32_t>(data + p);
@ -315,86 +327,101 @@ int CapabilityCredential::unmarshalVirtualNetworkRules(const uint8_t *const data
break; break;
case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS: case ZT_NETWORK_RULE_MATCH_SOURCE_ZEROTIER_ADDRESS:
case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS: case ZT_NETWORK_RULE_MATCH_DEST_ZEROTIER_ADDRESS:
if ((p + ZT_ADDRESS_LENGTH) > len) return -1; if ((p + ZT_ADDRESS_LENGTH) > len)
return -1;
rules[ruleCount].v.zt = Address(data + p).toInt(); rules[ruleCount].v.zt = Address(data + p).toInt();
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
break; break;
case ZT_NETWORK_RULE_MATCH_VLAN_ID: case ZT_NETWORK_RULE_MATCH_VLAN_ID:
if ((p + 2) > len) return -1; if ((p + 2) > len)
return -1;
rules[ruleCount].v.vlanId = Utils::loadBigEndian<uint16_t>(data + p); rules[ruleCount].v.vlanId = Utils::loadBigEndian<uint16_t>(data + p);
p += 2; p += 2;
break; break;
case ZT_NETWORK_RULE_MATCH_VLAN_PCP: case ZT_NETWORK_RULE_MATCH_VLAN_PCP:
if ((p + 1) > len) return -1; if ((p + 1) > len)
return -1;
rules[ruleCount].v.vlanPcp = data[p++]; rules[ruleCount].v.vlanPcp = data[p++];
break; break;
case ZT_NETWORK_RULE_MATCH_VLAN_DEI: case ZT_NETWORK_RULE_MATCH_VLAN_DEI:
if ((p + 1) > len) return -1; if ((p + 1) > len)
return -1;
rules[ruleCount].v.vlanDei = data[p++]; rules[ruleCount].v.vlanDei = data[p++];
break; break;
case ZT_NETWORK_RULE_MATCH_MAC_SOURCE: case ZT_NETWORK_RULE_MATCH_MAC_SOURCE:
case ZT_NETWORK_RULE_MATCH_MAC_DEST: case ZT_NETWORK_RULE_MATCH_MAC_DEST:
if ((p + 6) > len) return -1; if ((p + 6) > len)
return -1;
Utils::copy<6>(rules[ruleCount].v.mac, data + p); Utils::copy<6>(rules[ruleCount].v.mac, data + p);
p += 6; p += 6;
break; break;
case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE: case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE:
case ZT_NETWORK_RULE_MATCH_IPV4_DEST: case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
if ((p + 5) > len) return -1; if ((p + 5) > len)
return -1;
Utils::copy<4>(&(rules[ruleCount].v.ipv4.ip), data + p); Utils::copy<4>(&(rules[ruleCount].v.ipv4.ip), data + p);
p += 4; p += 4;
rules[ruleCount].v.ipv4.mask = data[p++]; rules[ruleCount].v.ipv4.mask = data[p++];
break; break;
case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE: case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
case ZT_NETWORK_RULE_MATCH_IPV6_DEST: case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
if ((p + 17) > len) return -1; if ((p + 17) > len)
return -1;
Utils::copy<16>(rules[ruleCount].v.ipv6.ip, data + p); Utils::copy<16>(rules[ruleCount].v.ipv6.ip, data + p);
p += 16; p += 16;
rules[ruleCount].v.ipv6.mask = data[p++]; rules[ruleCount].v.ipv6.mask = data[p++];
break; break;
case ZT_NETWORK_RULE_MATCH_IP_TOS: case ZT_NETWORK_RULE_MATCH_IP_TOS:
if ((p + 3) > len) return -1; if ((p + 3) > len)
return -1;
rules[ruleCount].v.ipTos.mask = data[p++]; rules[ruleCount].v.ipTos.mask = data[p++];
rules[ruleCount].v.ipTos.value[0] = data[p++]; rules[ruleCount].v.ipTos.value[0] = data[p++];
rules[ruleCount].v.ipTos.value[1] = data[p++]; rules[ruleCount].v.ipTos.value[1] = data[p++];
break; break;
case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL: case ZT_NETWORK_RULE_MATCH_IP_PROTOCOL:
if ((p + 1) > len) return -1; if ((p + 1) > len)
return -1;
rules[ruleCount].v.ipProtocol = data[p++]; rules[ruleCount].v.ipProtocol = data[p++];
break; break;
case ZT_NETWORK_RULE_MATCH_ETHERTYPE: case ZT_NETWORK_RULE_MATCH_ETHERTYPE:
if ((p + 2) > len) return -1; if ((p + 2) > len)
return -1;
rules[ruleCount].v.etherType = Utils::loadBigEndian<uint16_t>(data + p); rules[ruleCount].v.etherType = Utils::loadBigEndian<uint16_t>(data + p);
p += 2; p += 2;
break; break;
case ZT_NETWORK_RULE_MATCH_ICMP: case ZT_NETWORK_RULE_MATCH_ICMP:
if ((p + 3) > len) return -1; if ((p + 3) > len)
return -1;
rules[ruleCount].v.icmp.type = data[p++]; rules[ruleCount].v.icmp.type = data[p++];
rules[ruleCount].v.icmp.code = data[p++]; rules[ruleCount].v.icmp.code = data[p++];
rules[ruleCount].v.icmp.flags = data[p++]; rules[ruleCount].v.icmp.flags = data[p++];
break; break;
case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE: case ZT_NETWORK_RULE_MATCH_IP_SOURCE_PORT_RANGE:
case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE: case ZT_NETWORK_RULE_MATCH_IP_DEST_PORT_RANGE:
if ((p + 4) > len) return -1; if ((p + 4) > len)
return -1;
rules[ruleCount].v.port[0] = Utils::loadBigEndian<uint16_t>(data + p); rules[ruleCount].v.port[0] = Utils::loadBigEndian<uint16_t>(data + p);
p += 2; p += 2;
rules[ruleCount].v.port[1] = Utils::loadBigEndian<uint16_t>(data + p); rules[ruleCount].v.port[1] = Utils::loadBigEndian<uint16_t>(data + p);
p += 2; p += 2;
break; break;
case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS: case ZT_NETWORK_RULE_MATCH_CHARACTERISTICS:
if ((p + 8) > len) return -1; if ((p + 8) > len)
return -1;
rules[ruleCount].v.characteristics = Utils::loadBigEndian<uint64_t>(data + p); rules[ruleCount].v.characteristics = Utils::loadBigEndian<uint64_t>(data + p);
p += 8; p += 8;
break; break;
case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE: case ZT_NETWORK_RULE_MATCH_FRAME_SIZE_RANGE:
if ((p + 4) > len) return -1; if ((p + 4) > len)
return -1;
rules[ruleCount].v.frameSize[0] = Utils::loadBigEndian<uint16_t>(data + p); rules[ruleCount].v.frameSize[0] = Utils::loadBigEndian<uint16_t>(data + p);
p += 2; p += 2;
rules[ruleCount].v.frameSize[1] = Utils::loadBigEndian<uint16_t>(data + p); rules[ruleCount].v.frameSize[1] = Utils::loadBigEndian<uint16_t>(data + p);
p += 2; p += 2;
break; break;
case ZT_NETWORK_RULE_MATCH_RANDOM: case ZT_NETWORK_RULE_MATCH_RANDOM:
if ((p + 4) > len) return -1; if ((p + 4) > len)
return -1;
rules[ruleCount].v.randomProbability = Utils::loadBigEndian<uint32_t>(data + p); rules[ruleCount].v.randomProbability = Utils::loadBigEndian<uint32_t>(data + p);
p += 4; p += 4;
break; break;
@ -405,17 +432,20 @@ int CapabilityCredential::unmarshalVirtualNetworkRules(const uint8_t *const data
case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL: case ZT_NETWORK_RULE_MATCH_TAGS_EQUAL:
case ZT_NETWORK_RULE_MATCH_TAG_SENDER: case ZT_NETWORK_RULE_MATCH_TAG_SENDER:
case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER: case ZT_NETWORK_RULE_MATCH_TAG_RECEIVER:
if ((p + 4) > len) return -1; if ((p + 4) > len)
return -1;
rules[ruleCount].v.tag.id = Utils::loadBigEndian<uint32_t>(data + p); rules[ruleCount].v.tag.id = Utils::loadBigEndian<uint32_t>(data + p);
p += 4; p += 4;
rules[ruleCount].v.tag.value = Utils::loadBigEndian<uint32_t>(data + p); rules[ruleCount].v.tag.value = Utils::loadBigEndian<uint32_t>(data + p);
p += 4; p += 4;
break; break;
case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE: case ZT_NETWORK_RULE_MATCH_INTEGER_RANGE:
if ((p + 19) > len) return -1; if ((p + 19) > len)
return -1;
rules[ruleCount].v.intRange.start = Utils::loadBigEndian<uint64_t>(data + p); rules[ruleCount].v.intRange.start = Utils::loadBigEndian<uint64_t>(data + p);
p += 8; p += 8;
rules[ruleCount].v.intRange.end = (uint32_t) (Utils::loadBigEndian<uint64_t>(data + p) - rules[ruleCount].v.intRange.start); rules[ruleCount].v.intRange.end =
(uint32_t)(Utils::loadBigEndian<uint64_t>(data + p) - rules[ruleCount].v.intRange.start);
p += 8; p += 8;
rules[ruleCount].v.intRange.idx = Utils::loadBigEndian<uint16_t>(data + p); rules[ruleCount].v.intRange.idx = Utils::loadBigEndian<uint16_t>(data + p);
p += 2; p += 2;

View file

@ -14,15 +14,17 @@
#ifndef ZT_CAPABILITY_HPP #ifndef ZT_CAPABILITY_HPP
#define ZT_CAPABILITY_HPP #define ZT_CAPABILITY_HPP
#include "Constants.hpp"
#include "Credential.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "C25519.hpp" #include "C25519.hpp"
#include "Utils.hpp" #include "Constants.hpp"
#include "Credential.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "Utils.hpp"
#define ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX 21 #define ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX 21
#define ZT_CAPABILITY_MARSHAL_SIZE_MAX (8 + 8 + 4 + 1 + 2 + (ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX * ZT_MAX_CAPABILITY_RULES) + 2 + (5 + 5 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE)) #define ZT_CAPABILITY_MARSHAL_SIZE_MAX \
(8 + 8 + 4 + 1 + 2 + (ZT_VIRTUALNETWORKRULE_MARSHAL_SIZE_MAX * ZT_MAX_CAPABILITY_RULES) + 2 \
+ (5 + 5 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE))
namespace ZeroTier { namespace ZeroTier {
@ -46,16 +48,19 @@ class Context;
* Note that this is after evaluation of network scope rules and only if * Note that this is after evaluation of network scope rules and only if
* network scope rules do not deliver an explicit match. * network scope rules do not deliver an explicit match.
*/ */
class CapabilityCredential : public Credential class CapabilityCredential : public Credential {
{
friend class Credential; friend class Credential;
public: public:
static constexpr ZT_CredentialType credentialType() noexcept static constexpr ZT_CredentialType credentialType() noexcept
{ return ZT_CREDENTIAL_TYPE_CAPABILITY; } {
return ZT_CREDENTIAL_TYPE_CAPABILITY;
}
ZT_INLINE CapabilityCredential() noexcept ZT_INLINE CapabilityCredential() noexcept
{ memoryZero(this); } {
memoryZero(this);
}
/** /**
* @param id Capability ID * @param id Capability ID
@ -69,44 +74,64 @@ public:
const uint32_t id, const uint32_t id,
const uint64_t nwid, const uint64_t nwid,
const int64_t timestamp, const int64_t timestamp,
const ZT_VirtualNetworkRule *const rules, const ZT_VirtualNetworkRule* const rules,
const unsigned int ruleCount) noexcept; const unsigned int ruleCount) noexcept;
/** /**
* @return Rules -- see ruleCount() for size of array * @return Rules -- see ruleCount() for size of array
*/ */
ZT_INLINE const ZT_VirtualNetworkRule *rules() const noexcept ZT_INLINE const ZT_VirtualNetworkRule* rules() const noexcept
{ return m_rules; } {
return m_rules;
}
/** /**
* @return Number of rules in rules() * @return Number of rules in rules()
*/ */
ZT_INLINE unsigned int ruleCount() const noexcept ZT_INLINE unsigned int ruleCount() const noexcept
{ return m_ruleCount; } {
return m_ruleCount;
}
ZT_INLINE uint32_t id() const noexcept ZT_INLINE uint32_t id() const noexcept
{ return m_id; } {
return m_id;
}
ZT_INLINE uint64_t networkId() const noexcept ZT_INLINE uint64_t networkId() const noexcept
{ return m_nwid; } {
return m_nwid;
}
ZT_INLINE int64_t timestamp() const noexcept ZT_INLINE int64_t timestamp() const noexcept
{ return m_timestamp; } {
return m_timestamp;
}
ZT_INLINE int64_t revision() const noexcept ZT_INLINE int64_t revision() const noexcept
{ return m_timestamp; } {
return m_timestamp;
}
ZT_INLINE const Address &issuedTo() const noexcept ZT_INLINE const Address& issuedTo() const noexcept
{ return m_issuedTo; } {
return m_issuedTo;
}
ZT_INLINE const Address &signer() const noexcept ZT_INLINE const Address& signer() const noexcept
{ return m_signedBy; } {
return m_signedBy;
}
ZT_INLINE const uint8_t *signature() const noexcept ZT_INLINE const uint8_t* signature() const noexcept
{ return m_signature; } {
return m_signature;
}
ZT_INLINE unsigned int signatureLength() const noexcept ZT_INLINE unsigned int signatureLength() const noexcept
{ return m_signatureLength; } {
return m_signatureLength;
}
/** /**
* Sign this capability and add signature to its chain of custody * Sign this capability and add signature to its chain of custody
@ -121,21 +146,25 @@ public:
* @param to Recipient of this signature * @param to Recipient of this signature
* @return True if signature successful and chain of custody appended * @return True if signature successful and chain of custody appended
*/ */
bool sign(const Identity &from, const Address &to) noexcept; bool sign(const Identity& from, const Address& to) noexcept;
/** /**
* Verify this capability's chain of custody and signatures * Verify this capability's chain of custody and signatures
* *
* @param RR Runtime environment to provide for peer lookup, etc. * @param RR Runtime environment to provide for peer lookup, etc.
*/ */
ZT_INLINE Credential::VerifyResult verify(const Context &ctx, const CallContext &cc) const noexcept ZT_INLINE Credential::VerifyResult verify(const Context& ctx, const CallContext& cc) const noexcept
{ return s_verify(ctx, cc, *this); } {
return s_verify(ctx, cc, *this);
}
static constexpr int marshalSizeMax() noexcept static constexpr int marshalSizeMax() noexcept
{ return ZT_CAPABILITY_MARSHAL_SIZE_MAX; } {
return ZT_CAPABILITY_MARSHAL_SIZE_MAX;
}
int marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX], bool forSign = false) const noexcept; int marshal(uint8_t data[ZT_CAPABILITY_MARSHAL_SIZE_MAX], bool forSign = false) const noexcept;
int unmarshal(const uint8_t *data, int len) noexcept; int unmarshal(const uint8_t* data, int len) noexcept;
/** /**
* Marshal a set of virtual network rules * Marshal a set of virtual network rules
@ -145,7 +174,8 @@ public:
* @param ruleCount Number of rules * @param ruleCount Number of rules
* @return Number of bytes written or -1 on error * @return Number of bytes written or -1 on error
*/ */
static int marshalVirtualNetworkRules(uint8_t *data, const ZT_VirtualNetworkRule *rules, unsigned int ruleCount) noexcept; static int
marshalVirtualNetworkRules(uint8_t* data, const ZT_VirtualNetworkRule* rules, unsigned int ruleCount) noexcept;
/** /**
* Unmarshal a set of virtual network rules * Unmarshal a set of virtual network rules
@ -157,19 +187,30 @@ public:
* @param maxRuleCount Capacity of rules buffer * @param maxRuleCount Capacity of rules buffer
* @return Number of bytes unmarshaled or -1 on error * @return Number of bytes unmarshaled or -1 on error
*/ */
static int unmarshalVirtualNetworkRules(const uint8_t *data, int len, ZT_VirtualNetworkRule *rules, unsigned int &ruleCount, unsigned int maxRuleCount) noexcept; static int unmarshalVirtualNetworkRules(
const uint8_t* data,
int len,
ZT_VirtualNetworkRule* rules,
unsigned int& ruleCount,
unsigned int maxRuleCount) noexcept;
// Provides natural sort order by ID // Provides natural sort order by ID
ZT_INLINE bool operator<(const CapabilityCredential &c) const noexcept ZT_INLINE bool operator<(const CapabilityCredential& c) const noexcept
{ return (m_id < c.m_id); } {
return (m_id < c.m_id);
}
ZT_INLINE bool operator==(const CapabilityCredential &c) const noexcept ZT_INLINE bool operator==(const CapabilityCredential& c) const noexcept
{ return (memcmp(this, &c, sizeof(CapabilityCredential)) == 0); } {
return (memcmp(this, &c, sizeof(CapabilityCredential)) == 0);
}
ZT_INLINE bool operator!=(const CapabilityCredential &c) const noexcept ZT_INLINE bool operator!=(const CapabilityCredential& c) const noexcept
{ return (memcmp(this, &c, sizeof(CapabilityCredential)) != 0); } {
return (memcmp(this, &c, sizeof(CapabilityCredential)) != 0);
}
private: private:
uint64_t m_nwid; uint64_t m_nwid;
int64_t m_timestamp; int64_t m_timestamp;
uint32_t m_id; uint32_t m_id;

View file

@ -12,34 +12,38 @@
/****/ /****/
#include "Certificate.hpp" #include "Certificate.hpp"
#include "SHA512.hpp"
#include "ECC384.hpp" #include "ECC384.hpp"
#include "SHA512.hpp"
#include "ScopedPtr.hpp" #include "ScopedPtr.hpp"
namespace ZeroTier { namespace ZeroTier {
Certificate::Certificate() noexcept Certificate::Certificate() noexcept
{ {
ZT_Certificate *const sup = this; ZT_Certificate* const sup = this;
Utils::zero< sizeof(ZT_Certificate) >(sup); Utils::zero<sizeof(ZT_Certificate)>(sup);
} }
Certificate::Certificate(const ZT_Certificate &apiCert) : Certificate::Certificate(const ZT_Certificate& apiCert) : Certificate()
Certificate() {
{ *this = apiCert; } *this = apiCert;
}
Certificate::Certificate(const Certificate &cert) : Certificate::Certificate(const Certificate& cert) : Certificate()
Certificate() {
{ *this = cert; } *this = cert;
}
Certificate::~Certificate() Certificate::~Certificate()
{} {
}
Certificate &Certificate::operator=(const ZT_Certificate &cert) Certificate& Certificate::operator=(const ZT_Certificate& cert)
{ {
m_clear(); m_clear();
Utils::copy< sizeof(this->serialNo) >(this->serialNo, cert.serialNo); Utils::copy<sizeof(this->serialNo)>(this->serialNo, cert.serialNo);
this->usageFlags = cert.usageFlags; this->usageFlags = cert.usageFlags;
this->timestamp = cert.timestamp; this->timestamp = cert.timestamp;
this->validity[0] = cert.validity[0]; this->validity[0] = cert.validity[0];
@ -51,9 +55,12 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert)
for (unsigned int i = 0; i < cert.subject.identityCount; ++i) { for (unsigned int i = 0; i < cert.subject.identityCount; ++i) {
if (cert.subject.identities[i].identity) { if (cert.subject.identities[i].identity) {
if (cert.subject.identities[i].locator) { if (cert.subject.identities[i].locator) {
addSubjectIdentity(*reinterpret_cast<const Identity *>(cert.subject.identities[i].identity), *reinterpret_cast<const Locator *>(cert.subject.identities[i].locator)); addSubjectIdentity(
} else { *reinterpret_cast<const Identity*>(cert.subject.identities[i].identity),
addSubjectIdentity(*reinterpret_cast<const Identity *>(cert.subject.identities[i].identity)); *reinterpret_cast<const Locator*>(cert.subject.identities[i].locator));
}
else {
addSubjectIdentity(*reinterpret_cast<const Identity*>(cert.subject.identities[i].identity));
} }
} }
} }
@ -79,17 +86,19 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert)
this->subject.networkCount = cert.subject.networkCount; this->subject.networkCount = cert.subject.networkCount;
this->subject.updateURLCount = cert.subject.updateURLCount; this->subject.updateURLCount = cert.subject.updateURLCount;
Utils::copy< sizeof(ZT_Certificate_Name) >(&(this->subject.name), &(cert.subject.name)); Utils::copy<sizeof(ZT_Certificate_Name)>(&(this->subject.name), &(cert.subject.name));
Utils::copy< sizeof(this->subject.uniqueId) >(this->subject.uniqueId, cert.subject.uniqueId); Utils::copy<sizeof(this->subject.uniqueId)>(this->subject.uniqueId, cert.subject.uniqueId);
Utils::copy< sizeof(this->subject.uniqueIdSignature) >(this->subject.uniqueIdSignature, cert.subject.uniqueIdSignature); Utils::copy<sizeof(this->subject.uniqueIdSignature)>(
this->subject.uniqueIdSignature,
cert.subject.uniqueIdSignature);
this->subject.uniqueIdSize = cert.subject.uniqueIdSize; this->subject.uniqueIdSize = cert.subject.uniqueIdSize;
this->subject.uniqueIdSignatureSize = cert.subject.uniqueIdSignatureSize; this->subject.uniqueIdSignatureSize = cert.subject.uniqueIdSignatureSize;
Utils::copy< sizeof(this->issuer) >(this->issuer, cert.issuer); Utils::copy<sizeof(this->issuer)>(this->issuer, cert.issuer);
Utils::copy< sizeof(this->issuerPublicKey) >(this->issuerPublicKey, cert.issuerPublicKey); Utils::copy<sizeof(this->issuerPublicKey)>(this->issuerPublicKey, cert.issuerPublicKey);
Utils::copy< sizeof(this->publicKey) >(this->publicKey, cert.publicKey); Utils::copy<sizeof(this->publicKey)>(this->publicKey, cert.publicKey);
this->issuerPublicKeySize = cert.issuerPublicKeySize; this->issuerPublicKeySize = cert.issuerPublicKeySize;
this->publicKeySize = cert.publicKeySize; this->publicKeySize = cert.publicKeySize;
@ -99,7 +108,7 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert)
this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size(); this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size();
} }
Utils::copy< sizeof(this->signature) >(this->signature, cert.signature); Utils::copy<sizeof(this->signature)>(this->signature, cert.signature);
this->signatureSize = cert.signatureSize; this->signatureSize = cert.signatureSize;
this->maxPathLength = cert.maxPathLength; this->maxPathLength = cert.maxPathLength;
@ -107,7 +116,7 @@ Certificate &Certificate::operator=(const ZT_Certificate &cert)
return *this; return *this;
} }
ZT_Certificate_Identity *Certificate::addSubjectIdentity(const Identity &id) ZT_Certificate_Identity* Certificate::addSubjectIdentity(const Identity& id)
{ {
// Store a local copy of the actual identity. // Store a local copy of the actual identity.
m_identities.push_front(id); m_identities.push_front(id);
@ -124,10 +133,10 @@ ZT_Certificate_Identity *Certificate::addSubjectIdentity(const Identity &id)
return &(m_subjectIdentities.back()); return &(m_subjectIdentities.back());
} }
ZT_Certificate_Identity *Certificate::addSubjectIdentity(const Identity &id, const Locator &loc) ZT_Certificate_Identity* Certificate::addSubjectIdentity(const Identity& id, const Locator& loc)
{ {
// Add identity as above. // Add identity as above.
ZT_Certificate_Identity *const n = addSubjectIdentity(id); ZT_Certificate_Identity* const n = addSubjectIdentity(id);
// Store local copy of locator. // Store local copy of locator.
m_locators.push_front(loc); m_locators.push_front(loc);
@ -138,7 +147,7 @@ ZT_Certificate_Identity *Certificate::addSubjectIdentity(const Identity &id, con
return n; return n;
} }
ZT_Certificate_Network *Certificate::addSubjectNetwork(const uint64_t id, const ZT_Fingerprint &controller) ZT_Certificate_Network* Certificate::addSubjectNetwork(const uint64_t id, const ZT_Fingerprint& controller)
{ {
// Enlarge array of ZT_Certificate_Network and set pointer to potentially reallocated array. // Enlarge array of ZT_Certificate_Network and set pointer to potentially reallocated array.
m_subjectNetworks.resize(++this->subject.networkCount); m_subjectNetworks.resize(++this->subject.networkCount);
@ -146,12 +155,12 @@ ZT_Certificate_Network *Certificate::addSubjectNetwork(const uint64_t id, const
// Set fields in new ZT_Certificate_Network structure. // Set fields in new ZT_Certificate_Network structure.
m_subjectNetworks.back().id = id; m_subjectNetworks.back().id = id;
Utils::copy< sizeof(ZT_Fingerprint) >(&(m_subjectNetworks.back().controller), &controller); Utils::copy<sizeof(ZT_Fingerprint)>(&(m_subjectNetworks.back().controller), &controller);
return &(m_subjectNetworks.back()); return &(m_subjectNetworks.back());
} }
void Certificate::addSubjectUpdateUrl(const char *url) void Certificate::addSubjectUpdateUrl(const char* url)
{ {
if ((url != nullptr) && (url[0] != 0)) { if ((url != nullptr) && (url[0] != 0)) {
// Store local copy of URL. // Store local copy of URL.
@ -165,9 +174,9 @@ void Certificate::addSubjectUpdateUrl(const char *url)
} }
} }
Vector< uint8_t > Certificate::encode(const bool omitSignature) const Vector<uint8_t> Certificate::encode(const bool omitSignature) const
{ {
Vector< uint8_t > enc; Vector<uint8_t> enc;
Dictionary d; Dictionary d;
/* /*
@ -191,7 +200,7 @@ Vector< uint8_t > Certificate::encode(const bool omitSignature) const
m_encodeSubject(this->subject, d, false); m_encodeSubject(this->subject, d, false);
if (!Utils::allZero(this->issuer, sizeof(this->issuer))) if (! Utils::allZero(this->issuer, sizeof(this->issuer)))
d.add("i", this->issuer, sizeof(this->issuer)); d.add("i", this->issuer, sizeof(this->issuer));
if (this->issuerPublicKeySize > 0) if (this->issuerPublicKeySize > 0)
@ -203,7 +212,7 @@ Vector< uint8_t > Certificate::encode(const bool omitSignature) const
if ((this->extendedAttributes != nullptr) && (this->extendedAttributesSize > 0)) if ((this->extendedAttributes != nullptr) && (this->extendedAttributesSize > 0))
d["x"].assign(this->extendedAttributes, this->extendedAttributes + this->extendedAttributesSize); d["x"].assign(this->extendedAttributes, this->extendedAttributes + this->extendedAttributesSize);
if ((!omitSignature) && (this->signatureSize > 0)) if ((! omitSignature) && (this->signatureSize > 0))
d["si"].assign(this->signature, this->signature + this->signatureSize); d["si"].assign(this->signature, this->signature + this->signatureSize);
if (this->maxPathLength > 0) if (this->maxPathLength > 0)
@ -213,12 +222,12 @@ Vector< uint8_t > Certificate::encode(const bool omitSignature) const
return enc; return enc;
} }
bool Certificate::decode(const void *const data, const unsigned int len) bool Certificate::decode(const void* const data, const unsigned int len)
{ {
char tmp[32], tmp2[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1]; char tmp[32], tmp2[ZT_CERTIFICATE_MAX_STRING_LENGTH + 1];
Dictionary d; Dictionary d;
if (!d.decode(data, len)) if (! d.decode(data, len))
return false; return false;
m_clear(); m_clear();
@ -232,8 +241,8 @@ bool Certificate::decode(const void *const data, const unsigned int len)
unsigned int cnt = (unsigned int)d.getUI("s.i$"); unsigned int cnt = (unsigned int)d.getUI("s.i$");
for (unsigned int i = 0; i < cnt; ++i) { for (unsigned int i = 0; i < cnt; ++i) {
const Vector< uint8_t > &identityData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i)]; const Vector<uint8_t>& identityData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i)];
const Vector< uint8_t > &locatorData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.l", i)]; const Vector<uint8_t>& locatorData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.l", i)];
if (identityData.empty()) if (identityData.empty())
return false; return false;
Identity id; Identity id;
@ -241,7 +250,8 @@ bool Certificate::decode(const void *const data, const unsigned int len)
return false; return false;
if (locatorData.empty()) { if (locatorData.empty()) {
this->addSubjectIdentity(id); this->addSubjectIdentity(id);
} else { }
else {
Locator loc; Locator loc;
if (loc.unmarshal(locatorData.data(), (unsigned int)locatorData.size()) <= 0) if (loc.unmarshal(locatorData.data(), (unsigned int)locatorData.size()) <= 0)
return false; return false;
@ -252,7 +262,7 @@ bool Certificate::decode(const void *const data, const unsigned int len)
cnt = (unsigned int)d.getUI("s.nw$"); cnt = (unsigned int)d.getUI("s.nw$");
for (unsigned int i = 0; i < cnt; ++i) { for (unsigned int i = 0; i < cnt; ++i) {
const uint64_t nwid = d.getUI(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.i", i)); const uint64_t nwid = d.getUI(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.i", i));
const Vector< uint8_t > &fingerprintData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.c", i)]; const Vector<uint8_t>& fingerprintData = d[Dictionary::arraySubscript(tmp, sizeof(tmp), "s.nw$.c", i)];
if ((nwid == 0) || (fingerprintData.empty())) if ((nwid == 0) || (fingerprintData.empty()))
return false; return false;
Fingerprint fp; Fingerprint fp;
@ -278,72 +288,80 @@ bool Certificate::decode(const void *const data, const unsigned int len)
d.getS("s.n.ur", this->subject.name.url, sizeof(this->subject.name.url)); d.getS("s.n.ur", this->subject.name.url, sizeof(this->subject.name.url));
d.getS("s.n.h", this->subject.name.host, sizeof(this->subject.name.host)); d.getS("s.n.h", this->subject.name.host, sizeof(this->subject.name.host));
const Vector< uint8_t > &uniqueId = d["s.uI"]; const Vector<uint8_t>& uniqueId = d["s.uI"];
if ((!uniqueId.empty()) && (uniqueId.size() <= sizeof(this->subject.uniqueId))) { if ((! uniqueId.empty()) && (uniqueId.size() <= sizeof(this->subject.uniqueId))) {
Utils::copy(this->subject.uniqueId, uniqueId.data(), uniqueId.size()); Utils::copy(this->subject.uniqueId, uniqueId.data(), uniqueId.size());
this->subject.uniqueIdSize = (unsigned int)uniqueId.size(); this->subject.uniqueIdSize = (unsigned int)uniqueId.size();
} }
const Vector< uint8_t > &uniqueIdSignature = d["s.uS"]; const Vector<uint8_t>& uniqueIdSignature = d["s.uS"];
if ((!uniqueIdSignature.empty()) && (uniqueIdSignature.size() <= sizeof(this->subject.uniqueIdSignature))) { if ((! uniqueIdSignature.empty()) && (uniqueIdSignature.size() <= sizeof(this->subject.uniqueIdSignature))) {
Utils::copy(this->subject.uniqueIdSignature, uniqueIdSignature.data(), uniqueIdSignature.size()); Utils::copy(this->subject.uniqueIdSignature, uniqueIdSignature.data(), uniqueIdSignature.size());
this->subject.uniqueIdSignatureSize = (unsigned int)uniqueIdSignature.size(); this->subject.uniqueIdSignatureSize = (unsigned int)uniqueIdSignature.size();
} }
const Vector< uint8_t > &issuerData = d["i"]; const Vector<uint8_t>& issuerData = d["i"];
if (issuerData.size() == sizeof(this->issuer)) { if (issuerData.size() == sizeof(this->issuer)) {
Utils::copy< sizeof(this->issuer) >(this->issuer, issuerData.data()); Utils::copy<sizeof(this->issuer)>(this->issuer, issuerData.data());
} }
const Vector< uint8_t > &issuerPublicKey = d["iPK"]; const Vector<uint8_t>& issuerPublicKey = d["iPK"];
if ((!issuerPublicKey.empty()) && (issuerPublicKey.size() <= sizeof(this->issuerPublicKey))) { if ((! issuerPublicKey.empty()) && (issuerPublicKey.size() <= sizeof(this->issuerPublicKey))) {
Utils::copy(this->issuerPublicKey, issuerPublicKey.data(), issuerPublicKey.size()); Utils::copy(this->issuerPublicKey, issuerPublicKey.data(), issuerPublicKey.size());
this->issuerPublicKeySize = (unsigned int)issuerPublicKey.size(); this->issuerPublicKeySize = (unsigned int)issuerPublicKey.size();
} }
const Vector< uint8_t > &publicKey = d["pK"]; const Vector<uint8_t>& publicKey = d["pK"];
if ((!publicKey.empty()) && (publicKey.size() <= sizeof(this->publicKey))) { if ((! publicKey.empty()) && (publicKey.size() <= sizeof(this->publicKey))) {
Utils::copy(this->publicKey, publicKey.data(), publicKey.size()); Utils::copy(this->publicKey, publicKey.data(), publicKey.size());
this->publicKeySize = (unsigned int)publicKey.size(); this->publicKeySize = (unsigned int)publicKey.size();
} }
m_extendedAttributes = d["x"]; m_extendedAttributes = d["x"];
if (!m_extendedAttributes.empty()) { if (! m_extendedAttributes.empty()) {
this->extendedAttributes = m_extendedAttributes.data(); this->extendedAttributes = m_extendedAttributes.data();
this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size(); this->extendedAttributesSize = (unsigned int)m_extendedAttributes.size();
} }
const Vector< uint8_t > &signature = d["si"]; const Vector<uint8_t>& signature = d["si"];
if ((!signature.empty()) && (signature.size() <= sizeof(this->signature))) { if ((! signature.empty()) && (signature.size() <= sizeof(this->signature))) {
Utils::copy(this->signature, signature.data(), signature.size()); Utils::copy(this->signature, signature.data(), signature.size());
this->signatureSize = (unsigned int)signature.size(); this->signatureSize = (unsigned int)signature.size();
} }
this->maxPathLength = (unsigned int)d.getUI("l"); this->maxPathLength = (unsigned int)d.getUI("l");
const Vector< uint8_t > enc(encode(true)); const Vector<uint8_t> enc(encode(true));
SHA384(this->serialNo, enc.data(), (unsigned int)enc.size()); SHA384(this->serialNo, enc.data(), (unsigned int)enc.size());
return true; return true;
} }
bool Certificate::sign(const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE], const void *const issuerPrivateKey, const unsigned int issuerPrivateKeySize) bool Certificate::sign(
const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE],
const void* const issuerPrivateKey,
const unsigned int issuerPrivateKeySize)
{ {
if ((!issuerPrivateKey) || (issuerPrivateKeySize == 0)) if ((! issuerPrivateKey) || (issuerPrivateKeySize == 0))
return false; return false;
switch (reinterpret_cast<const uint8_t *>(issuerPrivateKey)[0]) { switch (reinterpret_cast<const uint8_t*>(issuerPrivateKey)[0]) {
default: default:
return false; return false;
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384: case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
if (issuerPrivateKeySize == (1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE)) { if (issuerPrivateKeySize == (1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE)) {
Utils::copy< sizeof(this->issuer) >(this->issuer, issuer); Utils::copy<sizeof(this->issuer)>(this->issuer, issuer);
Utils::copy< 1 + ZT_ECC384_PUBLIC_KEY_SIZE >(this->issuerPublicKey, issuerPrivateKey); // private is prefixed with public Utils::copy<1 + ZT_ECC384_PUBLIC_KEY_SIZE>(
this->issuerPublicKey,
issuerPrivateKey); // private is prefixed with public
this->issuerPublicKeySize = 1 + ZT_ECC384_PUBLIC_KEY_SIZE; this->issuerPublicKeySize = 1 + ZT_ECC384_PUBLIC_KEY_SIZE;
const Vector< uint8_t > enc(encode(true)); const Vector<uint8_t> enc(encode(true));
SHA384(this->serialNo, enc.data(), (unsigned int)enc.size()); SHA384(this->serialNo, enc.data(), (unsigned int)enc.size());
ECC384ECDSASign(reinterpret_cast<const uint8_t *>(issuerPrivateKey) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE, this->serialNo, this->signature); ECC384ECDSASign(
reinterpret_cast<const uint8_t*>(issuerPrivateKey) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE,
this->serialNo,
this->signature);
this->signatureSize = ZT_ECC384_SIGNATURE_SIZE; this->signatureSize = ZT_ECC384_SIGNATURE_SIZE;
return true; return true;
@ -364,19 +382,24 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
if (this->subject.identityCount > 0) { if (this->subject.identityCount > 0) {
if (this->subject.identities) { if (this->subject.identities) {
for (unsigned int i = 0; i < this->subject.identityCount; ++i) { for (unsigned int i = 0; i < this->subject.identityCount; ++i) {
if (!this->subject.identities[i].identity) { if (! this->subject.identities[i].identity) {
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
} }
if (checkSignatures) { if (checkSignatures) {
if (!reinterpret_cast<const Identity *>(this->subject.identities[i].identity)->locallyValidate()) { if (! reinterpret_cast<const Identity*>(this->subject.identities[i].identity)
->locallyValidate()) {
return ZT_CERTIFICATE_ERROR_INVALID_IDENTITY; return ZT_CERTIFICATE_ERROR_INVALID_IDENTITY;
} }
if ((this->subject.identities[i].locator) && (!reinterpret_cast<const Locator *>(this->subject.identities[i].locator)->verify(*reinterpret_cast<const Identity *>(this->subject.identities[i].identity)))) { if ((this->subject.identities[i].locator)
&& (! reinterpret_cast<const Locator*>(this->subject.identities[i].locator)
->verify(
*reinterpret_cast<const Identity*>(this->subject.identities[i].identity)))) {
return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE; return ZT_CERTIFICATE_ERROR_INVALID_COMPONENT_SIGNATURE;
} }
} }
} }
} else { }
else {
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
} }
} }
@ -384,11 +407,12 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
if (this->subject.networkCount > 0) { if (this->subject.networkCount > 0) {
if (this->subject.networks) { if (this->subject.networks) {
for (unsigned int i = 0; i < this->subject.networkCount; ++i) { for (unsigned int i = 0; i < this->subject.networkCount; ++i) {
if (!this->subject.networks[i].id) { if (! this->subject.networks[i].id) {
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS; return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
} }
} }
} else { }
else {
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
} }
} }
@ -396,23 +420,26 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
if (this->subject.updateURLCount > 0) { if (this->subject.updateURLCount > 0) {
if (this->subject.updateURLs) { if (this->subject.updateURLs) {
for (unsigned int i = 0; i < this->subject.updateURLCount; ++i) { for (unsigned int i = 0; i < this->subject.updateURLCount; ++i) {
if (!this->subject.updateURLs[i]) if (! this->subject.updateURLs[i])
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS; return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
} }
} else { }
else {
return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS; return ZT_CERTIFICATE_ERROR_MISSING_REQUIRED_FIELDS;
} }
} }
if ((this->subject.uniqueIdSize > sizeof(this->subject.uniqueId)) || (this->subject.uniqueIdSignatureSize > sizeof(this->subject.uniqueIdSignature))) { if ((this->subject.uniqueIdSize > sizeof(this->subject.uniqueId))
|| (this->subject.uniqueIdSignatureSize > sizeof(this->subject.uniqueIdSignature))) {
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
} }
if ((this->issuerPublicKeySize > sizeof(this->issuerPublicKey)) || (this->publicKeySize > sizeof(this->publicKey))) { if ((this->issuerPublicKeySize > sizeof(this->issuerPublicKey))
|| (this->publicKeySize > sizeof(this->publicKey))) {
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
} }
if ((this->extendedAttributesSize > 0) && (!this->extendedAttributes)) { if ((this->extendedAttributesSize > 0) && (! this->extendedAttributes)) {
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
} }
@ -424,21 +451,25 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
// Signature check fails if main signature is not present or invalid. // Signature check fails if main signature is not present or invalid.
// Note that the serial number / SHA384 hash is computed on decode(), so // Note that the serial number / SHA384 hash is computed on decode(), so
// this value is not something we blindly trust from input. // this value is not something we blindly trust from input.
if ((this->issuerPublicKeySize > 0) && (this->issuerPublicKeySize <= (unsigned int)sizeof(this->issuerPublicKey))) { if ((this->issuerPublicKeySize > 0)
&& (this->issuerPublicKeySize <= (unsigned int)sizeof(this->issuerPublicKey))) {
switch (this->issuerPublicKey[0]) { switch (this->issuerPublicKey[0]) {
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384: case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
if ((this->issuerPublicKeySize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1)) && (this->signatureSize == ZT_ECC384_SIGNATURE_SIZE)) { if ((this->issuerPublicKeySize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1))
if (!ECC384ECDSAVerify(this->issuerPublicKey + 1, this->serialNo, this->signature)) { && (this->signatureSize == ZT_ECC384_SIGNATURE_SIZE)) {
if (! ECC384ECDSAVerify(this->issuerPublicKey + 1, this->serialNo, this->signature)) {
return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE; return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
} }
} else { }
else {
return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE; return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
} }
break; break;
default: default:
return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE; return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
} }
} else { }
else {
return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE; return ZT_CERTIFICATE_ERROR_INVALID_PRIMARY_SIGNATURE;
} }
@ -451,52 +482,66 @@ ZT_CertificateError Certificate::verify(const int64_t clock, const bool checkSig
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_NONE: case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_NONE:
break; break;
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384: case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
if ((this->subject.uniqueIdSize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1)) && (this->subject.uniqueIdSignatureSize == ZT_ECC384_SIGNATURE_SIZE)) { if ((this->subject.uniqueIdSize == (ZT_ECC384_PUBLIC_KEY_SIZE + 1))
&& (this->subject.uniqueIdSignatureSize == ZT_ECC384_SIGNATURE_SIZE)) {
Dictionary d; Dictionary d;
m_encodeSubject(this->subject, d, true); m_encodeSubject(this->subject, d, true);
Vector< uint8_t > enc; Vector<uint8_t> enc;
enc.reserve(1024); enc.reserve(1024);
d.encode(enc); d.encode(enc);
static_assert(ZT_ECC384_SIGNATURE_HASH_SIZE == ZT_SHA384_DIGEST_SIZE, "ECC384 should take 384-bit hash"); static_assert(
ZT_ECC384_SIGNATURE_HASH_SIZE == ZT_SHA384_DIGEST_SIZE,
"ECC384 should take 384-bit hash");
uint8_t h[ZT_SHA384_DIGEST_SIZE]; uint8_t h[ZT_SHA384_DIGEST_SIZE];
SHA384(h, enc.data(), (unsigned int)enc.size()); SHA384(h, enc.data(), (unsigned int)enc.size());
if (!ECC384ECDSAVerify(this->subject.uniqueId + 1, h, this->subject.uniqueIdSignature)) { if (! ECC384ECDSAVerify(
this->subject.uniqueId + 1,
h,
this->subject.uniqueIdSignature)) {
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF; return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
} }
} else { }
else {
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF; return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
} }
break; break;
default: default:
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF; return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
} }
} else { }
else {
return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF; return ZT_CERTIFICATE_ERROR_INVALID_UNIQUE_ID_PROOF;
} }
} }
} }
if (clock >= 0) { if (clock >= 0) {
if (!this->verifyTimeWindow(clock)) if (! this->verifyTimeWindow(clock))
return ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW; return ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW;
} }
} catch (...) { }
catch (...) {
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
} }
return ZT_CERTIFICATE_ERROR_NONE; return ZT_CERTIFICATE_ERROR_NONE;
} }
bool Certificate::newKeyPair(const ZT_CertificatePublicKeyAlgorithm type, uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE], int *const publicKeySize, uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE], int *const privateKeySize) bool Certificate::newKeyPair(
const ZT_CertificatePublicKeyAlgorithm type,
uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE],
int* const publicKeySize,
uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE],
int* const privateKeySize)
{ {
switch (type) { switch (type) {
case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384: case ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384:
publicKey[0] = (uint8_t)ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384; publicKey[0] = (uint8_t)ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384;
ZeroTier::ECC384GenerateKey(publicKey + 1, privateKey + ZT_ECC384_PUBLIC_KEY_SIZE + 1); ZeroTier::ECC384GenerateKey(publicKey + 1, privateKey + ZT_ECC384_PUBLIC_KEY_SIZE + 1);
ZeroTier::Utils::copy< ZT_ECC384_PUBLIC_KEY_SIZE + 1 >(privateKey, publicKey); ZeroTier::Utils::copy<ZT_ECC384_PUBLIC_KEY_SIZE + 1>(privateKey, publicKey);
*publicKeySize = ZT_ECC384_PUBLIC_KEY_SIZE + 1; *publicKeySize = ZT_ECC384_PUBLIC_KEY_SIZE + 1;
*privateKeySize = ZT_ECC384_PUBLIC_KEY_SIZE + 1 + ZT_ECC384_PRIVATE_KEY_SIZE; *privateKeySize = ZT_ECC384_PUBLIC_KEY_SIZE + 1 + ZT_ECC384_PRIVATE_KEY_SIZE;
return true; return true;
@ -506,12 +551,17 @@ bool Certificate::newKeyPair(const ZT_CertificatePublicKeyAlgorithm type, uint8_
return false; return false;
} }
Vector< uint8_t > Certificate::createCSR(const ZT_Certificate_Subject &s, const void *const certificatePublicKey, const unsigned int certificatePublicKeySize, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize) Vector<uint8_t> Certificate::createCSR(
const ZT_Certificate_Subject& s,
const void* const certificatePublicKey,
const unsigned int certificatePublicKeySize,
const void* uniqueIdPrivate,
unsigned int uniqueIdPrivateSize)
{ {
Vector< uint8_t > enc; Vector<uint8_t> enc;
ZT_Certificate_Subject sc; ZT_Certificate_Subject sc;
Utils::copy< sizeof(ZT_Certificate_Subject) >(&sc, &s); Utils::copy<sizeof(ZT_Certificate_Subject)>(&sc, &s);
if (m_setSubjectUniqueId(sc, uniqueIdPrivate, uniqueIdPrivateSize)) { if (m_setSubjectUniqueId(sc, uniqueIdPrivate, uniqueIdPrivateSize)) {
Dictionary d; Dictionary d;
@ -526,8 +576,8 @@ Vector< uint8_t > Certificate::createCSR(const ZT_Certificate_Subject &s, const
void Certificate::m_clear() void Certificate::m_clear()
{ {
ZT_Certificate *const sup = this; ZT_Certificate* const sup = this;
Utils::zero< sizeof(ZT_Certificate) >(sup); Utils::zero<sizeof(ZT_Certificate)>(sup);
m_identities.clear(); m_identities.clear();
m_locators.clear(); m_locators.clear();
@ -539,14 +589,20 @@ void Certificate::m_clear()
m_extendedAttributes.clear(); m_extendedAttributes.clear();
} }
bool Certificate::m_setSubjectUniqueId(ZT_Certificate_Subject &s, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize) bool Certificate::m_setSubjectUniqueId(
ZT_Certificate_Subject& s,
const void* uniqueIdPrivate,
unsigned int uniqueIdPrivateSize)
{ {
if (uniqueIdPrivateSize > 0) { if (uniqueIdPrivateSize > 0) {
if ((uniqueIdPrivate != nullptr) && (uniqueIdPrivateSize == (1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE)) && (reinterpret_cast<const uint8_t *>(uniqueIdPrivate)[0] == (uint8_t)ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384)) { if ((uniqueIdPrivate != nullptr)
Utils::copy< 1 + ZT_ECC384_PUBLIC_KEY_SIZE >(s.uniqueId, uniqueIdPrivate); && (uniqueIdPrivateSize == (1 + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE))
&& (reinterpret_cast<const uint8_t*>(uniqueIdPrivate)[0]
== (uint8_t)ZT_CERTIFICATE_PUBLIC_KEY_ALGORITHM_ECDSA_NIST_P_384)) {
Utils::copy<1 + ZT_ECC384_PUBLIC_KEY_SIZE>(s.uniqueId, uniqueIdPrivate);
s.uniqueIdSize = 1 + ZT_ECC384_PUBLIC_KEY_SIZE; // private is prefixed with public s.uniqueIdSize = 1 + ZT_ECC384_PUBLIC_KEY_SIZE; // private is prefixed with public
Vector< uint8_t > enc; Vector<uint8_t> enc;
Dictionary d; Dictionary d;
m_encodeSubject(s, d, true); m_encodeSubject(s, d, true);
d.encode(enc); d.encode(enc);
@ -554,21 +610,26 @@ bool Certificate::m_setSubjectUniqueId(ZT_Certificate_Subject &s, const void *un
uint8_t h[ZT_SHA384_DIGEST_SIZE]; uint8_t h[ZT_SHA384_DIGEST_SIZE];
SHA384(h, enc.data(), (unsigned int)enc.size()); SHA384(h, enc.data(), (unsigned int)enc.size());
ECC384ECDSASign(reinterpret_cast<const uint8_t *>(uniqueIdPrivate) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE, h, s.uniqueIdSignature); ECC384ECDSASign(
reinterpret_cast<const uint8_t*>(uniqueIdPrivate) + 1 + ZT_ECC384_PUBLIC_KEY_SIZE,
h,
s.uniqueIdSignature);
s.uniqueIdSignatureSize = ZT_ECC384_SIGNATURE_SIZE; s.uniqueIdSignatureSize = ZT_ECC384_SIGNATURE_SIZE;
} else { }
else {
return false; return false;
} }
} else { }
Utils::zero< sizeof(s.uniqueId) >(s.uniqueId); else {
Utils::zero<sizeof(s.uniqueId)>(s.uniqueId);
s.uniqueIdSize = 0; s.uniqueIdSize = 0;
Utils::zero< sizeof(s.uniqueIdSignature) >(s.uniqueIdSignature); Utils::zero<sizeof(s.uniqueIdSignature)>(s.uniqueIdSignature);
s.uniqueIdSignatureSize = 0; s.uniqueIdSignatureSize = 0;
} }
return true; return true;
} }
void Certificate::m_encodeSubject(const ZT_Certificate_Subject &s, Dictionary &d, bool omitUniqueIdProofSignature) void Certificate::m_encodeSubject(const ZT_Certificate_Subject& s, Dictionary& d, bool omitUniqueIdProofSignature)
{ {
char tmp[32]; char tmp[32];
@ -578,9 +639,13 @@ void Certificate::m_encodeSubject(const ZT_Certificate_Subject &s, Dictionary &d
d.add("s.i$", (uint64_t)s.identityCount); d.add("s.i$", (uint64_t)s.identityCount);
for (unsigned int i = 0; i < s.identityCount; ++i) { for (unsigned int i = 0; i < s.identityCount; ++i) {
if (s.identities[i].identity) if (s.identities[i].identity)
d.addO(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i), *reinterpret_cast<const Identity *>(s.identities[i].identity)); d.addO(
Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.i", i),
*reinterpret_cast<const Identity*>(s.identities[i].identity));
if (s.identities[i].locator) if (s.identities[i].locator)
d.addO(Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.l", i), *reinterpret_cast<const Locator *>(s.identities[i].locator)); d.addO(
Dictionary::arraySubscript(tmp, sizeof(tmp), "s.i$.l", i),
*reinterpret_cast<const Locator*>(s.identities[i].locator));
} }
} }
@ -626,7 +691,7 @@ void Certificate::m_encodeSubject(const ZT_Certificate_Subject &s, Dictionary &d
if (s.uniqueIdSize > 0) if (s.uniqueIdSize > 0)
d["s.uI"].assign(s.uniqueId, s.uniqueId + s.uniqueIdSize); d["s.uI"].assign(s.uniqueId, s.uniqueId + s.uniqueIdSize);
if ((!omitUniqueIdProofSignature) && (s.uniqueIdSignatureSize > 0)) if ((! omitUniqueIdProofSignature) && (s.uniqueIdSignatureSize > 0))
d["s.uS"].assign(s.uniqueIdSignature, s.uniqueIdSignature + s.uniqueIdSignatureSize); d["s.uS"].assign(s.uniqueIdSignature, s.uniqueIdSignature + s.uniqueIdSignatureSize);
} }

View file

@ -14,15 +14,15 @@
#ifndef ZT_CERTIFICATE_HPP #ifndef ZT_CERTIFICATE_HPP
#define ZT_CERTIFICATE_HPP #define ZT_CERTIFICATE_HPP
#include "Constants.hpp"
#include "SHA512.hpp"
#include "C25519.hpp" #include "C25519.hpp"
#include "Constants.hpp"
#include "Containers.hpp"
#include "Dictionary.hpp"
#include "ECC384.hpp" #include "ECC384.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "Locator.hpp" #include "Locator.hpp"
#include "Dictionary.hpp" #include "SHA512.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include "Containers.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -43,27 +43,28 @@ namespace ZeroTier {
* field, so these will not work correctly before sign() or decode() is * field, so these will not work correctly before sign() or decode() is
* called. * called.
*/ */
class Certificate : public ZT_Certificate class Certificate : public ZT_Certificate {
{ public:
public:
Certificate() noexcept; Certificate() noexcept;
explicit Certificate(const ZT_Certificate &apiCert); explicit Certificate(const ZT_Certificate& apiCert);
Certificate(const Certificate &cert); Certificate(const Certificate& cert);
~Certificate(); ~Certificate();
Certificate &operator=(const ZT_Certificate &cert); Certificate& operator=(const ZT_Certificate& cert);
ZT_INLINE Certificate &operator=(const Certificate &cert) noexcept ZT_INLINE Certificate& operator=(const Certificate& cert) noexcept
{ {
if (likely(&cert != this)) { if (likely(&cert != this)) {
const ZT_Certificate *const sup = &cert; const ZT_Certificate* const sup = &cert;
*this = *sup; *this = *sup;
} }
return *this; return *this;
} }
ZT_INLINE H384 getSerialNo() const noexcept ZT_INLINE H384 getSerialNo() const noexcept
{ return H384(this->serialNo); } {
return H384(this->serialNo);
}
/** /**
* Add a subject node/identity without a locator * Add a subject node/identity without a locator
@ -71,7 +72,7 @@ public:
* @param id Identity * @param id Identity
* @return Pointer to C struct * @return Pointer to C struct
*/ */
ZT_Certificate_Identity *addSubjectIdentity(const Identity &id); ZT_Certificate_Identity* addSubjectIdentity(const Identity& id);
/** /**
* Add a subject node/identity with a locator * Add a subject node/identity with a locator
@ -80,7 +81,7 @@ public:
* @param loc Locator signed by identity (signature is NOT checked here) * @param loc Locator signed by identity (signature is NOT checked here)
* @return Pointer to C struct * @return Pointer to C struct
*/ */
ZT_Certificate_Identity *addSubjectIdentity(const Identity &id, const Locator &loc); ZT_Certificate_Identity* addSubjectIdentity(const Identity& id, const Locator& loc);
/** /**
* Add a subject network * Add a subject network
@ -89,14 +90,14 @@ public:
* @param controller Network controller's full fingerprint * @param controller Network controller's full fingerprint
* @return Pointer to C struct * @return Pointer to C struct
*/ */
ZT_Certificate_Network *addSubjectNetwork(uint64_t id, const ZT_Fingerprint &controller); ZT_Certificate_Network* addSubjectNetwork(uint64_t id, const ZT_Fingerprint& controller);
/** /**
* Add an update URL to the updateUrls list * Add an update URL to the updateUrls list
* *
* @param url Update URL * @param url Update URL
*/ */
void addSubjectUpdateUrl(const char *url); void addSubjectUpdateUrl(const char* url);
/** /**
* Sign subject with unique ID private key and set. * Sign subject with unique ID private key and set.
@ -108,8 +109,10 @@ public:
* @param uniqueIdPrivateSize Size of private key * @param uniqueIdPrivateSize Size of private key
* @return True on success * @return True on success
*/ */
ZT_INLINE bool setSubjectUniqueId(const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize) ZT_INLINE bool setSubjectUniqueId(const void* uniqueIdPrivate, unsigned int uniqueIdPrivateSize)
{ return m_setSubjectUniqueId(this->subject, uniqueIdPrivate, uniqueIdPrivateSize); } {
return m_setSubjectUniqueId(this->subject, uniqueIdPrivate, uniqueIdPrivateSize);
}
/** /**
* Marshal this certificate in binary form * Marshal this certificate in binary form
@ -120,7 +123,7 @@ public:
* @param omitSignature If true omit the signature field (for signing and verification, default is false) * @param omitSignature If true omit the signature field (for signing and verification, default is false)
* @return Marshaled certificate * @return Marshaled certificate
*/ */
Vector< uint8_t > encode(bool omitSignature = false) const; Vector<uint8_t> encode(bool omitSignature = false) const;
/** /**
* Decode this certificate from marshaled bytes. * Decode this certificate from marshaled bytes.
@ -129,7 +132,7 @@ public:
* @param len Length of marshalled certificate * @param len Length of marshalled certificate
* @return True if input is valid and was unmarshalled (signature is NOT checked) * @return True if input is valid and was unmarshalled (signature is NOT checked)
*/ */
bool decode(const void *data, unsigned int len); bool decode(const void* data, unsigned int len);
/** /**
* Sign this certificate. * Sign this certificate.
@ -138,7 +141,10 @@ public:
* *
* @return True on success * @return True on success
*/ */
bool sign(const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE], const void *issuerPrivateKey, unsigned int issuerPrivateKeySize); bool sign(
const uint8_t issuer[ZT_CERTIFICATE_HASH_SIZE],
const void* issuerPrivateKey,
unsigned int issuerPrivateKeySize);
/** /**
* Verify self-contained signatures and validity of certificate structure * Verify self-contained signatures and validity of certificate structure
@ -159,7 +165,10 @@ public:
* @return True if certificate is not expired or outside window * @return True if certificate is not expired or outside window
*/ */
ZT_INLINE bool verifyTimeWindow(int64_t clock) const noexcept ZT_INLINE bool verifyTimeWindow(int64_t clock) const noexcept
{ return ((clock >= this->validity[0]) && (clock <= this->validity[1]) && (this->validity[0] <= this->validity[1])); } {
return (
(clock >= this->validity[0]) && (clock <= this->validity[1]) && (this->validity[0] <= this->validity[1]));
}
/** /**
* Create a new certificate public/private key pair * Create a new certificate public/private key pair
@ -171,7 +180,12 @@ public:
* @param privateKeySize Result parameter: set to size of private key * @param privateKeySize Result parameter: set to size of private key
* @return True on success * @return True on success
*/ */
static bool newKeyPair(const ZT_CertificatePublicKeyAlgorithm type, uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE], int *const publicKeySize, uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE], int *const privateKeySize); static bool newKeyPair(
const ZT_CertificatePublicKeyAlgorithm type,
uint8_t publicKey[ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE],
int* const publicKeySize,
uint8_t privateKey[ZT_CERTIFICATE_MAX_PRIVATE_KEY_SIZE],
int* const privateKeySize);
/** /**
* Create a CSR that encodes the subject of this certificate * Create a CSR that encodes the subject of this certificate
@ -183,46 +197,66 @@ public:
* @param uniqueIdPrivateSize Size of unique ID private key * @param uniqueIdPrivateSize Size of unique ID private key
* @return Encoded subject (without any unique ID fields) or empty vector on error * @return Encoded subject (without any unique ID fields) or empty vector on error
*/ */
static Vector< uint8_t > createCSR(const ZT_Certificate_Subject &s, const void *certificatePublicKey, unsigned int certificatePublicKeySize, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize); static Vector<uint8_t> createCSR(
const ZT_Certificate_Subject& s,
const void* certificatePublicKey,
unsigned int certificatePublicKeySize,
const void* uniqueIdPrivate,
unsigned int uniqueIdPrivateSize);
ZT_INLINE unsigned long hashCode() const noexcept ZT_INLINE unsigned long hashCode() const noexcept
{ return (unsigned long)Utils::loadMachineEndian< uint32_t >(this->serialNo); } {
return (unsigned long)Utils::loadMachineEndian<uint32_t>(this->serialNo);
}
ZT_INLINE bool operator==(const ZT_Certificate &c) const noexcept ZT_INLINE bool operator==(const ZT_Certificate& c) const noexcept
{ return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) == 0; } {
return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) == 0;
}
ZT_INLINE bool operator!=(const ZT_Certificate &c) const noexcept ZT_INLINE bool operator!=(const ZT_Certificate& c) const noexcept
{ return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) != 0; } {
return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) != 0;
}
ZT_INLINE bool operator<(const ZT_Certificate &c) const noexcept ZT_INLINE bool operator<(const ZT_Certificate& c) const noexcept
{ return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) < 0; } {
return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) < 0;
}
ZT_INLINE bool operator<=(const ZT_Certificate &c) const noexcept ZT_INLINE bool operator<=(const ZT_Certificate& c) const noexcept
{ return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) <= 0; } {
return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) <= 0;
}
ZT_INLINE bool operator>(const ZT_Certificate &c) const noexcept ZT_INLINE bool operator>(const ZT_Certificate& c) const noexcept
{ return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) > 0; } {
return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) > 0;
}
ZT_INLINE bool operator>=(const ZT_Certificate &c) const noexcept ZT_INLINE bool operator>=(const ZT_Certificate& c) const noexcept
{ return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) >= 0; } {
return memcmp(this->serialNo, c.serialNo, ZT_SHA384_DIGEST_SIZE) >= 0;
}
private: private:
void m_clear(); void m_clear();
static bool m_setSubjectUniqueId(ZT_Certificate_Subject &s, const void *uniqueIdPrivate, unsigned int uniqueIdPrivateSize); static bool
static void m_encodeSubject(const ZT_Certificate_Subject &s, Dictionary &d, bool omitUniqueIdProofSignature); m_setSubjectUniqueId(ZT_Certificate_Subject& s, const void* uniqueIdPrivate, unsigned int uniqueIdPrivateSize);
static void m_encodeSubject(const ZT_Certificate_Subject& s, Dictionary& d, bool omitUniqueIdProofSignature);
// These hold any identity or locator objects that are owned by and should // These hold any identity or locator objects that are owned by and should
// be deleted with this certificate. Lists are used so the pointers never // be deleted with this certificate. Lists are used so the pointers never
// change. // change.
ForwardList< Identity > m_identities; ForwardList<Identity> m_identities;
ForwardList< Locator > m_locators; ForwardList<Locator> m_locators;
ForwardList< String > m_strings; ForwardList<String> m_strings;
// These are stored in a vector because the memory needs to be contiguous. // These are stored in a vector because the memory needs to be contiguous.
Vector< ZT_Certificate_Identity > m_subjectIdentities; Vector<ZT_Certificate_Identity> m_subjectIdentities;
Vector< ZT_Certificate_Network > m_subjectNetworks; Vector<ZT_Certificate_Network> m_subjectNetworks;
Vector< const char * > m_updateUrls; Vector<const char*> m_updateUrls;
Vector< uint8_t > m_extendedAttributes; Vector<uint8_t> m_extendedAttributes;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -20,8 +20,8 @@
#define ZT_CORE 1 #define ZT_CORE 1
#include "OS.hpp" #include "OS.hpp"
#include "zerotier.h"
#include "version.h" #include "version.h"
#include "zerotier.h"
/** /**
* Length of a ZeroTier address in bytes * Length of a ZeroTier address in bytes
@ -190,7 +190,8 @@
#define ZT_PEER_WHOIS_RATE_LIMIT 100 #define ZT_PEER_WHOIS_RATE_LIMIT 100
/** /**
* General rate limit for other kinds of rate-limited packets (HELLO, credential request, etc.) both inbound and outbound * General rate limit for other kinds of rate-limited packets (HELLO, credential request, etc.) both inbound and
* outbound
*/ */
#define ZT_PEER_GENERAL_RATE_LIMIT 500 #define ZT_PEER_GENERAL_RATE_LIMIT 500

View file

@ -19,111 +19,104 @@
#include "Constants.hpp" #include "Constants.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include <map> #include <algorithm>
#include <vector>
#include <list> #include <list>
#include <map>
#include <set> #include <set>
#include <string> #include <string>
#include <algorithm> #include <vector>
#ifdef __CPP11__ #ifdef __CPP11__
#include <atomic> #include <atomic>
#include <unordered_map>
#include <forward_list> #include <forward_list>
#include <unordered_map>
#endif #endif
namespace ZeroTier { namespace ZeroTier {
template< typename V > template <typename V> class Vector : public std::vector<V> {
class Vector : public std::vector< V > public:
{ ZT_INLINE Vector() : std::vector<V>()
public: {
ZT_INLINE Vector() : }
std::vector< V >()
{}
template< typename I > template <typename I> ZT_INLINE Vector(I begin, I end) : std::vector<V>(begin, end)
ZT_INLINE Vector(I begin, I end) : {
std::vector< V >(begin, end) }
{}
}; };
template< typename V > template <typename V> class List : public std::list<V> {
class List : public std::list< V >
{
}; };
#ifdef __CPP11__ #ifdef __CPP11__
struct intl_MapHasher struct intl_MapHasher {
{ template <typename O> std::size_t operator()(const O& obj) const noexcept
template< typename O > {
std::size_t operator()(const O &obj) const noexcept return (std::size_t)obj.hashCode();
{ return (std::size_t)obj.hashCode(); } }
std::size_t operator()(const Vector< uint8_t > &bytes) const noexcept std::size_t operator()(const Vector<uint8_t>& bytes) const noexcept
{ return (std::size_t)Utils::fnv1a32(bytes.data(), (unsigned int)bytes.size()); } {
return (std::size_t)Utils::fnv1a32(bytes.data(), (unsigned int)bytes.size());
}
std::size_t operator()(const uint64_t i) const noexcept std::size_t operator()(const uint64_t i) const noexcept
{ return (std::size_t)Utils::hash64(i ^ Utils::s_mapNonce); } {
return (std::size_t)Utils::hash64(i ^ Utils::s_mapNonce);
}
std::size_t operator()(const int64_t i) const noexcept std::size_t operator()(const int64_t i) const noexcept
{ return (std::size_t)Utils::hash64((uint64_t)i ^ Utils::s_mapNonce); } {
return (std::size_t)Utils::hash64((uint64_t)i ^ Utils::s_mapNonce);
}
std::size_t operator()(const uint32_t i) const noexcept std::size_t operator()(const uint32_t i) const noexcept
{ return (std::size_t)Utils::hash32(i ^ (uint32_t)Utils::s_mapNonce); } {
return (std::size_t)Utils::hash32(i ^ (uint32_t)Utils::s_mapNonce);
}
std::size_t operator()(const int32_t i) const noexcept std::size_t operator()(const int32_t i) const noexcept
{ return (std::size_t)Utils::hash32((uint32_t)i ^ (uint32_t)Utils::s_mapNonce); } {
return (std::size_t)Utils::hash32((uint32_t)i ^ (uint32_t)Utils::s_mapNonce);
}
}; };
template< typename K, typename V > template <typename K, typename V> class Map : public std::unordered_map<K, V, intl_MapHasher> {
class Map : public std::unordered_map< K, V, intl_MapHasher >
{
}; };
template< typename K, typename V > template <typename K, typename V>
class MultiMap : public std::unordered_multimap< K, V, intl_MapHasher, std::equal_to< K > > class MultiMap : public std::unordered_multimap<K, V, intl_MapHasher, std::equal_to<K> > {
{
}; };
#else #else
template<typename K, typename V> template <typename K, typename V> class Map : public std::map<K, V> {
class Map : public std::map< K, V > };
{};
template<typename K, typename V> template <typename K, typename V> class MultiMap : public std::multimap<K, V> {
class MultiMap : public std::multimap< K, V > };
{};
#endif #endif
template< typename K, typename V > template <typename K, typename V> class SortedMap : public std::map<K, V> {
class SortedMap : public std::map< K, V >
{
}; };
#ifdef __CPP11__ #ifdef __CPP11__
template< typename V > template <typename V> class ForwardList : public std::forward_list<V> {
class ForwardList : public std::forward_list< V >
{
}; };
#else #else
template< typename V > template <typename V> class ForwardList : public std::list<V> {
class ForwardList : public std::list< V > };
{};
#endif #endif
template< typename V > template <typename V> class Set : public std::set<V, std::less<V> > {
class Set : public std::set< V, std::less< V > >
{
}; };
typedef std::string String; typedef std::string String;
@ -131,48 +124,72 @@ typedef std::string String;
/** /**
* A 384-bit hash * A 384-bit hash
*/ */
struct H384 struct H384 {
{
uint64_t data[6]; uint64_t data[6];
ZT_INLINE H384() noexcept ZT_INLINE H384() noexcept
{ Utils::zero< sizeof(data) >(data); }
ZT_INLINE H384(const H384 &b) noexcept
{ Utils::copy< 48 >(data, b.data); }
explicit ZT_INLINE H384(const void *const d) noexcept
{ Utils::copy< 48 >(data, d); }
ZT_INLINE H384 &operator=(const H384 &b) noexcept
{ {
Utils::copy< 48 >(data, b.data); Utils::zero<sizeof(data)>(data);
}
ZT_INLINE H384(const H384& b) noexcept
{
Utils::copy<48>(data, b.data);
}
explicit ZT_INLINE H384(const void* const d) noexcept
{
Utils::copy<48>(data, d);
}
ZT_INLINE H384& operator=(const H384& b) noexcept
{
Utils::copy<48>(data, b.data);
return *this; return *this;
} }
ZT_INLINE unsigned long hashCode() const noexcept ZT_INLINE unsigned long hashCode() const noexcept
{ return (unsigned long)data[0]; } {
return (unsigned long)data[0];
}
ZT_INLINE operator bool() const noexcept ZT_INLINE operator bool() const noexcept
{ return ((data[0] != 0) && (data[1] != 0) && (data[2] != 0) && (data[3] != 0) && (data[4] != 0) && (data[5] != 0)); } {
return (
(data[0] != 0) && (data[1] != 0) && (data[2] != 0) && (data[3] != 0) && (data[4] != 0) && (data[5] != 0));
}
ZT_INLINE bool operator==(const H384 &b) const noexcept ZT_INLINE bool operator==(const H384& b) const noexcept
{ return ((data[0] == b.data[0]) && (data[1] == b.data[1]) && (data[2] == b.data[2]) && (data[3] == b.data[3]) && (data[4] == b.data[4]) && (data[5] == b.data[5])); } {
return (
(data[0] == b.data[0]) && (data[1] == b.data[1]) && (data[2] == b.data[2]) && (data[3] == b.data[3])
&& (data[4] == b.data[4]) && (data[5] == b.data[5]));
}
ZT_INLINE bool operator!=(const H384 &b) const noexcept ZT_INLINE bool operator!=(const H384& b) const noexcept
{ return !(*this == b); } {
return ! (*this == b);
}
ZT_INLINE bool operator<(const H384 &b) const noexcept ZT_INLINE bool operator<(const H384& b) const noexcept
{ return std::lexicographical_compare(data, data + 6, b.data, b.data + 6); } {
return std::lexicographical_compare(data, data + 6, b.data, b.data + 6);
}
ZT_INLINE bool operator<=(const H384 &b) const noexcept ZT_INLINE bool operator<=(const H384& b) const noexcept
{ return !(b < *this); } {
return ! (b < *this);
}
ZT_INLINE bool operator>(const H384 &b) const noexcept ZT_INLINE bool operator>(const H384& b) const noexcept
{ return (b < *this); } {
return (b < *this);
}
ZT_INLINE bool operator>=(const H384 &b) const noexcept ZT_INLINE bool operator>=(const H384& b) const noexcept
{ return !(*this < b); } {
return ! (*this < b);
}
}; };
static_assert(sizeof(H384) == 48, "H384 contains unnecessary padding"); static_assert(sizeof(H384) == 48, "H384 contains unnecessary padding");
@ -182,21 +199,25 @@ static_assert(sizeof(H384) == 48, "H384 contains unnecessary padding");
* *
* @tparam S Size in bytes * @tparam S Size in bytes
*/ */
template< unsigned long S > template <unsigned long S> struct Blob {
struct Blob
{
uint8_t data[S]; uint8_t data[S];
ZT_INLINE Blob() noexcept ZT_INLINE Blob() noexcept
{ Utils::zero< S >(data); } {
Utils::zero<S>(data);
}
ZT_INLINE Blob(const Blob &b) noexcept ZT_INLINE Blob(const Blob& b) noexcept
{ Utils::copy< S >(data, b.data); } {
Utils::copy<S>(data, b.data);
}
explicit ZT_INLINE Blob(const void *const d) noexcept explicit ZT_INLINE Blob(const void* const d) noexcept
{ Utils::copy< S >(data, d); } {
Utils::copy<S>(data, d);
}
explicit ZT_INLINE Blob(const void *const d, const unsigned int l) noexcept explicit ZT_INLINE Blob(const void* const d, const unsigned int l) noexcept
{ {
Utils::copy(data, d, (l > (unsigned int)S) ? (unsigned int)S : l); Utils::copy(data, d, (l > (unsigned int)S) ? (unsigned int)S : l);
if (l < S) { if (l < S) {
@ -204,37 +225,53 @@ struct Blob
} }
} }
ZT_INLINE Blob &operator=(const Blob &b) noexcept ZT_INLINE Blob& operator=(const Blob& b) noexcept
{ {
Utils::copy< S >(data, b.data); Utils::copy<S>(data, b.data);
return *this; return *this;
} }
ZT_INLINE unsigned long hashCode() const noexcept ZT_INLINE unsigned long hashCode() const noexcept
{ return Utils::fnv1a32(data, (unsigned int)S); } {
return Utils::fnv1a32(data, (unsigned int)S);
}
ZT_INLINE operator bool() const noexcept ZT_INLINE operator bool() const noexcept
{ return Utils::allZero(data, (unsigned int)S); } {
return Utils::allZero(data, (unsigned int)S);
}
ZT_INLINE bool operator==(const Blob &b) const noexcept ZT_INLINE bool operator==(const Blob& b) const noexcept
{ return (memcmp(data, b.data, S) == 0); } {
return (memcmp(data, b.data, S) == 0);
}
ZT_INLINE bool operator!=(const Blob &b) const noexcept ZT_INLINE bool operator!=(const Blob& b) const noexcept
{ return (memcmp(data, b.data, S) != 0); } {
return (memcmp(data, b.data, S) != 0);
}
ZT_INLINE bool operator<(const Blob &b) const noexcept ZT_INLINE bool operator<(const Blob& b) const noexcept
{ return (memcmp(data, b.data, S) < 0); } {
return (memcmp(data, b.data, S) < 0);
}
ZT_INLINE bool operator<=(const Blob &b) const noexcept ZT_INLINE bool operator<=(const Blob& b) const noexcept
{ return (memcmp(data, b.data, S) <= 0); } {
return (memcmp(data, b.data, S) <= 0);
}
ZT_INLINE bool operator>(const Blob &b) const noexcept ZT_INLINE bool operator>(const Blob& b) const noexcept
{ return (memcmp(data, b.data, S) > 0); } {
return (memcmp(data, b.data, S) > 0);
}
ZT_INLINE bool operator>=(const Blob &b) const noexcept ZT_INLINE bool operator>=(const Blob& b) const noexcept
{ return (memcmp(data, b.data, S) >= 0); } {
return (memcmp(data, b.data, S) >= 0);
}
}; };
} // ZeroTier } // namespace ZeroTier
#endif #endif

View file

@ -14,12 +14,12 @@
#ifndef ZT_RUNTIMEENVIRONMENT_HPP #ifndef ZT_RUNTIMEENVIRONMENT_HPP
#define ZT_RUNTIMEENVIRONMENT_HPP #define ZT_RUNTIMEENVIRONMENT_HPP
#include "Constants.hpp"
#include "Utils.hpp"
#include "Identity.hpp"
#include "AES.hpp" #include "AES.hpp"
#include "TinyMap.hpp" #include "Constants.hpp"
#include "Identity.hpp"
#include "SharedPtr.hpp" #include "SharedPtr.hpp"
#include "TinyMap.hpp"
#include "Utils.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -38,55 +38,56 @@ class Network;
/** /**
* Node instance context * Node instance context
*/ */
class Context class Context {
{ public:
public: ZT_INLINE Context(Node* const n) noexcept
ZT_INLINE Context(Node *const n) noexcept: : instanceId(Utils::getSecureRandomU64())
instanceId(Utils::getSecureRandomU64()), , node(n)
node(n), , uPtr(nullptr)
uPtr(nullptr), , localNetworkController(nullptr)
localNetworkController(nullptr), , store(nullptr)
store(nullptr), , networks(nullptr)
networks(nullptr), , t(nullptr)
t(nullptr), , expect(nullptr)
expect(nullptr), , vl2(nullptr)
vl2(nullptr), , vl1(nullptr)
vl1(nullptr), , topology(nullptr)
topology(nullptr), , sa(nullptr)
sa(nullptr), , ts(nullptr)
ts(nullptr)
{ {
publicIdentityStr[0] = 0; publicIdentityStr[0] = 0;
secretIdentityStr[0] = 0; secretIdentityStr[0] = 0;
} }
ZT_INLINE ~Context() noexcept ZT_INLINE ~Context() noexcept
{ Utils::burn(secretIdentityStr, sizeof(secretIdentityStr)); } {
Utils::burn(secretIdentityStr, sizeof(secretIdentityStr));
}
// Unique ID generated on startup // Unique ID generated on startup
const uint64_t instanceId; const uint64_t instanceId;
// Node instance that owns this RuntimeEnvironment // Node instance that owns this RuntimeEnvironment
Node *const restrict node; Node* const restrict node;
// Callbacks specified by caller who created node // Callbacks specified by caller who created node
ZT_Node_Callbacks cb; ZT_Node_Callbacks cb;
// User pointer specified by external code via API // User pointer specified by external code via API
void *restrict uPtr; void* restrict uPtr;
// This is set externally to an instance of this base class // This is set externally to an instance of this base class
NetworkController *restrict localNetworkController; NetworkController* restrict localNetworkController;
Store *restrict store; Store* restrict store;
TinyMap< SharedPtr< Network > > *restrict networks; TinyMap<SharedPtr<Network> >* restrict networks;
Trace *restrict t; Trace* restrict t;
Expect *restrict expect; Expect* restrict expect;
VL2 *restrict vl2; VL2* restrict vl2;
VL1 *restrict vl1; VL1* restrict vl1;
Topology *restrict topology; Topology* restrict topology;
SelfAwareness *restrict sa; SelfAwareness* restrict sa;
TrustStore *restrict ts; TrustStore* restrict ts;
// This node's identity and string representations thereof // This node's identity and string representations thereof
Identity identity; Identity identity;

View file

@ -11,15 +11,16 @@
*/ */
/****/ /****/
#include "Credential.hpp"
#include "CapabilityCredential.hpp"
#include "Constants.hpp" #include "Constants.hpp"
#include "Context.hpp" #include "Context.hpp"
#include "Credential.hpp"
#include "CapabilityCredential.hpp"
#include "TagCredential.hpp"
#include "MembershipCredential.hpp" #include "MembershipCredential.hpp"
#include "Network.hpp"
#include "OwnershipCredential.hpp" #include "OwnershipCredential.hpp"
#include "RevocationCredential.hpp" #include "RevocationCredential.hpp"
#include "Network.hpp" #include "TagCredential.hpp"
#include "Topology.hpp" #include "Topology.hpp"
// These are compile-time asserts to make sure temporary marshal buffers here and // These are compile-time asserts to make sure temporary marshal buffers here and
@ -42,57 +43,77 @@
namespace ZeroTier { namespace ZeroTier {
template< typename CRED > template <typename CRED>
static ZT_INLINE Credential::VerifyResult p_credVerify(const Context &ctx, const CallContext &cc, CRED credential) static ZT_INLINE Credential::VerifyResult p_credVerify(const Context& ctx, const CallContext& cc, CRED credential)
{ {
uint8_t tmp[ZT_BUF_MEM_SIZE + 16]; uint8_t tmp[ZT_BUF_MEM_SIZE + 16];
const Address signedBy(credential.signer()); const Address signedBy(credential.signer());
const uint64_t networkId = credential.networkId(); const uint64_t networkId = credential.networkId();
if ((!signedBy) || (signedBy != Network::controllerFor(networkId))) if ((! signedBy) || (signedBy != Network::controllerFor(networkId)))
return Credential::VERIFY_BAD_SIGNATURE; return Credential::VERIFY_BAD_SIGNATURE;
const SharedPtr< Peer > peer(ctx.topology->peer(cc, signedBy)); const SharedPtr<Peer> peer(ctx.topology->peer(cc, signedBy));
if (!peer) if (! peer)
return Credential::VERIFY_NEED_IDENTITY; return Credential::VERIFY_NEED_IDENTITY;
try { try {
int l = credential.marshal(tmp, true); int l = credential.marshal(tmp, true);
if (l <= 0) if (l <= 0)
return Credential::VERIFY_BAD_SIGNATURE; return Credential::VERIFY_BAD_SIGNATURE;
return (peer->identity().verify(tmp, (unsigned int)l, credential.signature(), credential.signatureLength()) ? Credential::VERIFY_OK : Credential::VERIFY_BAD_SIGNATURE); return (
} catch (...) {} peer->identity().verify(tmp, (unsigned int)l, credential.signature(), credential.signatureLength())
? Credential::VERIFY_OK
: Credential::VERIFY_BAD_SIGNATURE);
}
catch (...) {
}
return Credential::VERIFY_BAD_SIGNATURE; return Credential::VERIFY_BAD_SIGNATURE;
} }
Credential::VerifyResult Credential::s_verify(const Context &ctx, const CallContext &cc, const RevocationCredential &credential) Credential::VerifyResult
{ return p_credVerify(ctx, cc, credential); } Credential::s_verify(const Context& ctx, const CallContext& cc, const RevocationCredential& credential)
{
return p_credVerify(ctx, cc, credential);
}
Credential::VerifyResult Credential::s_verify(const Context &ctx, const CallContext &cc, const TagCredential &credential) Credential::VerifyResult
{ return p_credVerify(ctx, cc, credential); } Credential::s_verify(const Context& ctx, const CallContext& cc, const TagCredential& credential)
{
return p_credVerify(ctx, cc, credential);
}
Credential::VerifyResult Credential::s_verify(const Context &ctx, const CallContext &cc, const CapabilityCredential &credential) Credential::VerifyResult
{ return p_credVerify(ctx, cc, credential); } Credential::s_verify(const Context& ctx, const CallContext& cc, const CapabilityCredential& credential)
{
return p_credVerify(ctx, cc, credential);
}
Credential::VerifyResult Credential::s_verify(const Context &ctx, const CallContext &cc, const OwnershipCredential &credential) Credential::VerifyResult
{ return p_credVerify(ctx, cc, credential); } Credential::s_verify(const Context& ctx, const CallContext& cc, const OwnershipCredential& credential)
{
return p_credVerify(ctx, cc, credential);
}
Credential::VerifyResult Credential::s_verify(const Context &ctx, const CallContext &cc, const MembershipCredential &credential) Credential::VerifyResult
Credential::s_verify(const Context& ctx, const CallContext& cc, const MembershipCredential& credential)
{ {
// Sanity check network ID. // Sanity check network ID.
if ((!credential.m_signedBy) || (credential.m_signedBy != Network::controllerFor(credential.m_networkId))) if ((! credential.m_signedBy) || (credential.m_signedBy != Network::controllerFor(credential.m_networkId)))
return Credential::VERIFY_BAD_SIGNATURE; return Credential::VERIFY_BAD_SIGNATURE;
// If we don't know the peer, get its identity. This shouldn't happen here but should be handled. // If we don't know the peer, get its identity. This shouldn't happen here but should be handled.
const SharedPtr< Peer > peer(ctx.topology->peer(cc, credential.m_signedBy)); const SharedPtr<Peer> peer(ctx.topology->peer(cc, credential.m_signedBy));
if (!peer) if (! peer)
return Credential::VERIFY_NEED_IDENTITY; return Credential::VERIFY_NEED_IDENTITY;
// Now verify the controller's signature. // Now verify the controller's signature.
uint64_t buf[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX / 8]; uint64_t buf[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX / 8];
const unsigned int bufSize = credential.m_fillSigningBuf(buf); const unsigned int bufSize = credential.m_fillSigningBuf(buf);
return peer->identity().verify(buf, bufSize, credential.m_signature, credential.m_signatureLength) ? Credential::VERIFY_OK : Credential::VERIFY_BAD_SIGNATURE; return peer->identity().verify(buf, bufSize, credential.m_signature, credential.m_signatureLength)
? Credential::VERIFY_OK
: Credential::VERIFY_BAD_SIGNATURE;
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -14,9 +14,9 @@
#ifndef ZT_CREDENTIAL_HPP #ifndef ZT_CREDENTIAL_HPP
#define ZT_CREDENTIAL_HPP #define ZT_CREDENTIAL_HPP
#include "CallContext.hpp"
#include "Constants.hpp" #include "Constants.hpp"
#include "TriviallyCopyable.hpp" #include "TriviallyCopyable.hpp"
#include "CallContext.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -35,25 +35,19 @@ class Context;
* All credential verification methods are implemented in Credential.cpp as they share a lot * All credential verification methods are implemented in Credential.cpp as they share a lot
* of common code and logic and grouping them makes auditing easier. * of common code and logic and grouping them makes auditing easier.
*/ */
class Credential : public TriviallyCopyable class Credential : public TriviallyCopyable {
{ public:
public:
/** /**
* Result of verify() operations * Result of verify() operations
*/ */
enum VerifyResult enum VerifyResult { VERIFY_OK = 0, VERIFY_BAD_SIGNATURE = 1, VERIFY_NEED_IDENTITY = 2 };
{
VERIFY_OK = 0,
VERIFY_BAD_SIGNATURE = 1,
VERIFY_NEED_IDENTITY = 2
};
protected: protected:
static VerifyResult s_verify(const Context &ctx, const CallContext &cc, const MembershipCredential &credential); static VerifyResult s_verify(const Context& ctx, const CallContext& cc, const MembershipCredential& credential);
static VerifyResult s_verify(const Context &ctx, const CallContext &cc, const RevocationCredential &credential); static VerifyResult s_verify(const Context& ctx, const CallContext& cc, const RevocationCredential& credential);
static VerifyResult s_verify(const Context &ctx, const CallContext &cc, const TagCredential &credential); static VerifyResult s_verify(const Context& ctx, const CallContext& cc, const TagCredential& credential);
static VerifyResult s_verify(const Context &ctx, const CallContext &cc, const OwnershipCredential &credential); static VerifyResult s_verify(const Context& ctx, const CallContext& cc, const OwnershipCredential& credential);
static VerifyResult s_verify(const Context &ctx, const CallContext &cc, const CapabilityCredential &credential); static VerifyResult s_verify(const Context& ctx, const CallContext& cc, const CapabilityCredential& credential);
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -16,7 +16,7 @@
namespace ZeroTier { namespace ZeroTier {
namespace Defaults { namespace Defaults {
const uint8_t *CERTIFICATE[DEFAULT_CERTIFICATE_COUNT] = {}; const uint8_t* CERTIFICATE[DEFAULT_CERTIFICATE_COUNT] = {};
unsigned int CERTIFICATE_SIZE[DEFAULT_CERTIFICATE_COUNT] = {}; unsigned int CERTIFICATE_SIZE[DEFAULT_CERTIFICATE_COUNT] = {};

View file

@ -21,7 +21,7 @@ namespace Defaults {
#define DEFAULT_CERTIFICATE_COUNT 0 #define DEFAULT_CERTIFICATE_COUNT 0
extern const uint8_t *CERTIFICATE[DEFAULT_CERTIFICATE_COUNT]; extern const uint8_t* CERTIFICATE[DEFAULT_CERTIFICATE_COUNT];
extern unsigned int CERTIFICATE_SIZE[DEFAULT_CERTIFICATE_COUNT]; extern unsigned int CERTIFICATE_SIZE[DEFAULT_CERTIFICATE_COUNT];
} // namespace Defaults } // namespace Defaults

View file

@ -14,13 +14,13 @@
#ifndef ZT_DEFRAGMENTER_HPP #ifndef ZT_DEFRAGMENTER_HPP
#define ZT_DEFRAGMENTER_HPP #define ZT_DEFRAGMENTER_HPP
#include "Constants.hpp"
#include "Buf.hpp" #include "Buf.hpp"
#include "SharedPtr.hpp" #include "Constants.hpp"
#include "Containers.hpp"
#include "FCV.hpp"
#include "Mutex.hpp" #include "Mutex.hpp"
#include "Path.hpp" #include "Path.hpp"
#include "FCV.hpp" #include "SharedPtr.hpp"
#include "Containers.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -40,25 +40,24 @@ namespace ZeroTier {
* the ones used throughout the ZeroTier core. * the ones used throughout the ZeroTier core.
* *
* @tparam MF Maximum number of fragments that each message can possess (default: ZT_MAX_PACKET_FRAGMENTS) * @tparam MF Maximum number of fragments that each message can possess (default: ZT_MAX_PACKET_FRAGMENTS)
* @tparam MFP Maximum number of incoming fragments per path (if paths are specified) (default: ZT_MAX_INCOMING_FRAGMENTS_PER_PATH) * @tparam MFP Maximum number of incoming fragments per path (if paths are specified) (default:
* ZT_MAX_INCOMING_FRAGMENTS_PER_PATH)
* @tparam GCS Garbage collection target size for the incoming message queue (default: ZT_MAX_PACKET_FRAGMENTS * 2) * @tparam GCS Garbage collection target size for the incoming message queue (default: ZT_MAX_PACKET_FRAGMENTS * 2)
* @tparam GCT Garbage collection trigger threshold, usually 2X GCS (default: ZT_MAX_PACKET_FRAGMENTS * 4) * @tparam GCT Garbage collection trigger threshold, usually 2X GCS (default: ZT_MAX_PACKET_FRAGMENTS * 4)
* @tparam P Type for pointer to a path object (default: SharedPtr<Path>) * @tparam P Type for pointer to a path object (default: SharedPtr<Path>)
*/ */
template< template <
unsigned int MF = ZT_MAX_PACKET_FRAGMENTS, unsigned int MF = ZT_MAX_PACKET_FRAGMENTS,
unsigned int MFP = ZT_MAX_INCOMING_FRAGMENTS_PER_PATH, unsigned int MFP = ZT_MAX_INCOMING_FRAGMENTS_PER_PATH,
unsigned int GCS = (ZT_MAX_PACKET_FRAGMENTS * 2), unsigned int GCS = (ZT_MAX_PACKET_FRAGMENTS * 2),
unsigned int GCT = (ZT_MAX_PACKET_FRAGMENTS * 4), unsigned int GCT = (ZT_MAX_PACKET_FRAGMENTS * 4),
typename P = SharedPtr< Path > > typename P = SharedPtr<Path> >
class Defragmenter class Defragmenter {
{ public:
public:
/** /**
* Return values from assemble() * Return values from assemble()
*/ */
enum ResultCode enum ResultCode {
{
/** /**
* No error occurred, fragment accepted * No error occurred, fragment accepted
*/ */
@ -97,7 +96,8 @@ public:
}; };
ZT_INLINE Defragmenter() ZT_INLINE Defragmenter()
{} {
}
/** /**
* Process a fragment of a multi-part message * Process a fragment of a multi-part message
@ -142,14 +142,14 @@ public:
*/ */
ZT_INLINE ResultCode assemble( ZT_INLINE ResultCode assemble(
const uint64_t messageId, const uint64_t messageId,
FCV< Buf::Slice, MF > &message, FCV<Buf::Slice, MF>& message,
SharedPtr< Buf > &fragment, SharedPtr<Buf>& fragment,
const unsigned int fragmentDataIndex, const unsigned int fragmentDataIndex,
const unsigned int fragmentDataSize, const unsigned int fragmentDataSize,
const unsigned int fragmentNo, const unsigned int fragmentNo,
const unsigned int totalFragmentsExpected, const unsigned int totalFragmentsExpected,
const int64_t ts, const int64_t ts,
const P &via) const P& via)
{ {
// Sanity checks for malformed fragments or invalid input parameters. // Sanity checks for malformed fragments or invalid input parameters.
if ((fragmentNo >= totalFragmentsExpected) || (totalFragmentsExpected > MF) || (totalFragmentsExpected == 0)) if ((fragmentNo >= totalFragmentsExpected) || (totalFragmentsExpected > MF) || (totalFragmentsExpected == 0))
@ -167,34 +167,37 @@ public:
// under the target size. This tries to minimize the amount of time the write // under the target size. This tries to minimize the amount of time the write
// lock is held since many threads can hold the read lock but all threads must // lock is held since many threads can hold the read lock but all threads must
// wait if someone holds the write lock. // wait if someone holds the write lock.
std::vector< std::pair< int64_t, uint64_t > > messagesByLastUsedTime; std::vector<std::pair<int64_t, uint64_t> > messagesByLastUsedTime;
messagesByLastUsedTime.reserve(m_messages.size()); messagesByLastUsedTime.reserve(m_messages.size());
for (typename Map< uint64_t, p_E >::const_iterator i(m_messages.begin()); i != m_messages.end(); ++i) for (typename Map<uint64_t, p_E>::const_iterator i(m_messages.begin()); i != m_messages.end(); ++i)
messagesByLastUsedTime.push_back(std::pair< int64_t, uint64_t >(i->second.lastUsed, i->first)); messagesByLastUsedTime.push_back(std::pair<int64_t, uint64_t>(i->second.lastUsed, i->first));
std::sort(messagesByLastUsedTime.begin(), messagesByLastUsedTime.end()); std::sort(messagesByLastUsedTime.begin(), messagesByLastUsedTime.end());
ml.writing(); // acquire write lock on _messages ml.writing(); // acquire write lock on _messages
for (unsigned long x = 0, y = (messagesByLastUsedTime.size() - GCS); x <= y; ++x) for (unsigned long x = 0, y = (messagesByLastUsedTime.size() - GCS); x <= y; ++x)
m_messages.erase(messagesByLastUsedTime[x].second); m_messages.erase(messagesByLastUsedTime[x].second);
} catch (...) { }
catch (...) {
return ERR_OUT_OF_MEMORY; return ERR_OUT_OF_MEMORY;
} }
} }
// Get or create message fragment. // Get or create message fragment.
Defragmenter< MF, MFP, GCS, GCT, P >::p_E *e; Defragmenter<MF, MFP, GCS, GCT, P>::p_E* e;
{ {
typename Map< uint64_t, Defragmenter< MF, MFP, GCS, GCT, P >::p_E >::iterator ee(m_messages.find(messageId)); typename Map<uint64_t, Defragmenter<MF, MFP, GCS, GCT, P>::p_E>::iterator ee(m_messages.find(messageId));
if (ee == m_messages.end()) { if (ee == m_messages.end()) {
ml.writing(); // acquire write lock on _messages if not already ml.writing(); // acquire write lock on _messages if not already
try { try {
e = &(m_messages[messageId]); e = &(m_messages[messageId]);
} catch (...) { }
catch (...) {
return ERR_OUT_OF_MEMORY; return ERR_OUT_OF_MEMORY;
} }
e->id = messageId; e->id = messageId;
} else { }
else {
e = &(ee->second); e = &(ee->second);
} }
} }
@ -220,17 +223,19 @@ public:
// If there is a path associated with this fragment make sure we've registered // If there is a path associated with this fragment make sure we've registered
// ourselves as in flight, check the limit, and abort if exceeded. // ourselves as in flight, check the limit, and abort if exceeded.
if ((via) && (!e->via)) { if ((via) && (! e->via)) {
e->via = via; e->via = via;
bool tooManyPerPath = false; bool tooManyPerPath = false;
via->m_inboundFragmentedMessages_l.lock(); via->m_inboundFragmentedMessages_l.lock();
try { try {
if (via->m_inboundFragmentedMessages.size() < MFP) { if (via->m_inboundFragmentedMessages.size() < MFP) {
via->m_inboundFragmentedMessages.insert(messageId); via->m_inboundFragmentedMessages.insert(messageId);
} else { }
else {
tooManyPerPath = true; tooManyPerPath = true;
} }
} catch (...) { }
catch (...) {
// This would indicate something like bad_alloc thrown by the set. Treat // This would indicate something like bad_alloc thrown by the set. Treat
// it as limit exceeded. // it as limit exceeded.
tooManyPerPath = true; tooManyPerPath = true;
@ -245,7 +250,7 @@ public:
// data would just mean the transfer is corrupt and would be detected // data would just mean the transfer is corrupt and would be detected
// later e.g. by packet MAC check. Other use cases of this code like // later e.g. by packet MAC check. Other use cases of this code like
// network configs check each fragment so this basically can't happen. // network configs check each fragment so this basically can't happen.
Buf::Slice &s = e->message.at(fragmentNo); Buf::Slice& s = e->message.at(fragmentNo);
if (s.b) if (s.b)
return ERR_DUPLICATE_FRAGMENT; return ERR_DUPLICATE_FRAGMENT;
@ -296,26 +301,27 @@ public:
return m_messages.size(); return m_messages.size();
} }
private: private:
// p_E is an entry in the message queue. // p_E is an entry in the message queue.
struct p_E struct p_E {
ZT_INLINE p_E() noexcept
: id(0)
, lastUsed(0)
, totalFragmentsExpected(0)
, fragmentsReceived(0)
{ {
ZT_INLINE p_E() noexcept: }
id(0),
lastUsed(0),
totalFragmentsExpected(0),
fragmentsReceived(0)
{}
ZT_INLINE p_E(const p_E &e) noexcept: ZT_INLINE p_E(const p_E& e) noexcept
id(e.id), : id(e.id)
lastUsed(e.lastUsed), , lastUsed(e.lastUsed)
totalFragmentsExpected(e.totalFragmentsExpected), , totalFragmentsExpected(e.totalFragmentsExpected)
fragmentsReceived(e.fragmentsReceived), , fragmentsReceived(e.fragmentsReceived)
via(e.via), , via(e.via)
message(e.message), , message(e.message)
lock() , lock()
{} {
}
ZT_INLINE ~p_E() ZT_INLINE ~p_E()
{ {
@ -326,7 +332,7 @@ private:
} }
} }
ZT_INLINE p_E &operator=(const p_E &e) ZT_INLINE p_E& operator=(const p_E& e)
{ {
if (this != &e) { if (this != &e) {
id = e.id; id = e.id;
@ -344,11 +350,11 @@ private:
unsigned int totalFragmentsExpected; unsigned int totalFragmentsExpected;
unsigned int fragmentsReceived; unsigned int fragmentsReceived;
P via; P via;
FCV< Buf::Slice, MF > message; FCV<Buf::Slice, MF> message;
Mutex lock; Mutex lock;
}; };
Map< uint64_t, Defragmenter< MF, MFP, GCS, GCT, P >::p_E > m_messages; Map<uint64_t, Defragmenter<MF, MFP, GCS, GCT, P>::p_E> m_messages;
RWMutex m_messages_l; RWMutex m_messages_l;
}; };

View file

@ -15,44 +15,47 @@
namespace ZeroTier { namespace ZeroTier {
Vector< uint8_t > &Dictionary::operator[](const char *const k) Vector<uint8_t>& Dictionary::operator[](const char* const k)
{ return m_entries[k]; }
const Vector< uint8_t > &Dictionary::operator[](const char *const k) const
{ {
static const Vector< uint8_t > s_emptyEntry; return m_entries[k];
const SortedMap< String, Vector< uint8_t > >::const_iterator e(m_entries.find(k)); }
const Vector<uint8_t>& Dictionary::operator[](const char* const k) const
{
static const Vector<uint8_t> s_emptyEntry;
const SortedMap<String, Vector<uint8_t> >::const_iterator e(m_entries.find(k));
return (e == m_entries.end()) ? s_emptyEntry : e->second; return (e == m_entries.end()) ? s_emptyEntry : e->second;
} }
void Dictionary::add(const char *k, const Address &v) void Dictionary::add(const char* k, const Address& v)
{ {
char tmp[ZT_ADDRESS_STRING_SIZE_MAX]; char tmp[ZT_ADDRESS_STRING_SIZE_MAX];
v.toString(tmp); v.toString(tmp);
add(k, tmp); add(k, tmp);
} }
void Dictionary::add(const char *k, const char *v) void Dictionary::add(const char* k, const char* v)
{ {
Vector< uint8_t > &e = (*this)[k]; Vector<uint8_t>& e = (*this)[k];
e.clear(); e.clear();
if (v) { if (v) {
while (*v) while (*v)
e.push_back((uint8_t)*(v++)); e.push_back((uint8_t) * (v++));
} }
} }
void Dictionary::add(const char *k, const void *data, unsigned int len) void Dictionary::add(const char* k, const void* data, unsigned int len)
{ {
Vector< uint8_t > &e = (*this)[k]; Vector<uint8_t>& e = (*this)[k];
if (likely(len != 0)) { if (likely(len != 0)) {
e.assign((const uint8_t *)data, (const uint8_t *)data + len); e.assign((const uint8_t*)data, (const uint8_t*)data + len);
} else { }
else {
e.clear(); e.clear();
} }
} }
uint64_t Dictionary::getUI(const char *k, uint64_t dfl) const uint64_t Dictionary::getUI(const char* k, uint64_t dfl) const
{ {
char tmp[32]; char tmp[32];
getS(k, tmp, sizeof(tmp)); getS(k, tmp, sizeof(tmp));
@ -61,12 +64,12 @@ uint64_t Dictionary::getUI(const char *k, uint64_t dfl) const
return dfl; return dfl;
} }
char *Dictionary::getS(const char *k, char *v, const unsigned int cap) const char* Dictionary::getS(const char* k, char* v, const unsigned int cap) const
{ {
if (cap == 0) // sanity check if (cap == 0) // sanity check
return v; return v;
const Vector< uint8_t > &e = (*this)[k]; const Vector<uint8_t>& e = (*this)[k];
if (e.empty()) { if (e.empty()) {
v[0] = 0; v[0] = 0;
return v; return v;
@ -85,27 +88,29 @@ char *Dictionary::getS(const char *k, char *v, const unsigned int cap) const
} }
void Dictionary::clear() void Dictionary::clear()
{ m_entries.clear(); } {
m_entries.clear();
}
void Dictionary::encode(Vector< uint8_t > &out) const void Dictionary::encode(Vector<uint8_t>& out) const
{ {
out.clear(); out.clear();
for (SortedMap< String, Vector< uint8_t > >::const_iterator ti(m_entries.begin()); ti != m_entries.end(); ++ti) { for (SortedMap<String, Vector<uint8_t> >::const_iterator ti(m_entries.begin()); ti != m_entries.end(); ++ti) {
s_appendKey(out, ti->first.data()); s_appendKey(out, ti->first.data());
for (Vector< uint8_t >::const_iterator i(ti->second.begin()); i != ti->second.end(); ++i) for (Vector<uint8_t>::const_iterator i(ti->second.begin()); i != ti->second.end(); ++i)
s_appendValueByte(out, *i); s_appendValueByte(out, *i);
out.push_back((uint8_t)'\n'); out.push_back((uint8_t)'\n');
} }
} }
bool Dictionary::decode(const void *data, unsigned int len) bool Dictionary::decode(const void* data, unsigned int len)
{ {
clear(); clear();
String k; String k;
Vector< uint8_t > *v = nullptr; Vector<uint8_t>* v = nullptr;
bool escape = false; bool escape = false;
for (unsigned int di = 0; di < len; ++di) { for (unsigned int di = 0; di < len; ++di) {
const uint8_t c = reinterpret_cast<const uint8_t *>(data)[di]; const uint8_t c = reinterpret_cast<const uint8_t*>(data)[di];
if (c) { if (c) {
if (v) { if (v) {
if (escape) { if (escape) {
@ -127,31 +132,37 @@ bool Dictionary::decode(const void *data, unsigned int len)
v->push_back(c); v->push_back(c);
break; break;
} }
} else { }
else {
if (c == (uint8_t)'\n') { if (c == (uint8_t)'\n') {
k.clear(); k.clear();
v = nullptr; v = nullptr;
} else if (c == 92) { // backslash }
else if (c == 92) { // backslash
escape = true; escape = true;
} else { }
else {
v->push_back(c); v->push_back(c);
} }
} }
} else { }
else {
if (c == (uint8_t)'=') { if (c == (uint8_t)'=') {
v = &m_entries[k]; v = &m_entries[k];
} else { }
else {
k.push_back(c); k.push_back(c);
} }
} }
} else { }
else {
break; break;
} }
} }
return true; return true;
} }
char *Dictionary::arraySubscript(char *buf, unsigned int bufSize, const char *name, const unsigned long sub) noexcept char* Dictionary::arraySubscript(char* buf, unsigned int bufSize, const char* name, const unsigned long sub) noexcept
{ {
if (bufSize < 17) { // sanity check if (bufSize < 17) { // sanity check
buf[0] = 0; buf[0] = 0;

View file

@ -14,11 +14,11 @@
#ifndef ZT_DICTIONARY_HPP #ifndef ZT_DICTIONARY_HPP
#define ZT_DICTIONARY_HPP #define ZT_DICTIONARY_HPP
#include "Constants.hpp"
#include "Utils.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Buf.hpp" #include "Buf.hpp"
#include "Constants.hpp"
#include "Containers.hpp" #include "Containers.hpp"
#include "Utils.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -37,16 +37,17 @@ class Identity;
* The fastest way to build a dictionary to send is to use the append * The fastest way to build a dictionary to send is to use the append
* static functions, not to populate and then encode a Dictionary. * static functions, not to populate and then encode a Dictionary.
*/ */
class Dictionary class Dictionary {
{ public:
public: typedef SortedMap<String, Vector<uint8_t> >::const_iterator const_iterator;
typedef SortedMap< String, Vector< uint8_t > >::const_iterator const_iterator;
ZT_INLINE Dictionary() ZT_INLINE Dictionary()
{} {
}
ZT_INLINE ~Dictionary() ZT_INLINE ~Dictionary()
{} {
}
/* /*
ZT_INLINE void dump() const ZT_INLINE void dump() const
@ -81,7 +82,7 @@ public:
* @param k Key to look up * @param k Key to look up
* @return Reference to value * @return Reference to value
*/ */
Vector< uint8_t > &operator[](const char *k); Vector<uint8_t>& operator[](const char* k);
/** /**
* Get a const reference to a value * Get a const reference to a value
@ -89,19 +90,23 @@ public:
* @param k Key to look up * @param k Key to look up
* @return Reference to value or to empty vector if not found * @return Reference to value or to empty vector if not found
*/ */
const Vector< uint8_t > &operator[](const char *k) const; const Vector<uint8_t>& operator[](const char* k) const;
/** /**
* @return Start of key->value pairs * @return Start of key->value pairs
*/ */
ZT_INLINE const_iterator begin() const noexcept ZT_INLINE const_iterator begin() const noexcept
{ return m_entries.begin(); } {
return m_entries.begin();
}
/** /**
* @return End of key->value pairs * @return End of key->value pairs
*/ */
ZT_INLINE const_iterator end() const noexcept ZT_INLINE const_iterator end() const noexcept
{ return m_entries.end(); } {
return m_entries.end();
}
/** /**
* Add an integer as a hexadecimal string value * Add an integer as a hexadecimal string value
@ -109,7 +114,7 @@ public:
* @param k Key to set * @param k Key to set
* @param v Integer to set, will be cast to uint64_t and stored as hex * @param v Integer to set, will be cast to uint64_t and stored as hex
*/ */
ZT_INLINE void add(const char *const k, const uint64_t v) ZT_INLINE void add(const char* const k, const uint64_t v)
{ {
char buf[24]; char buf[24];
add(k, Utils::hex((uint64_t)(v), buf)); add(k, Utils::hex((uint64_t)(v), buf));
@ -121,7 +126,7 @@ public:
* @param k Key to set * @param k Key to set
* @param v Integer to set, will be cast to uint64_t and stored as hex * @param v Integer to set, will be cast to uint64_t and stored as hex
*/ */
ZT_INLINE void add(const char *const k, const int64_t v) ZT_INLINE void add(const char* const k, const int64_t v)
{ {
char buf[24]; char buf[24];
add(k, Utils::hex((uint64_t)(v), buf)); add(k, Utils::hex((uint64_t)(v), buf));
@ -130,17 +135,17 @@ public:
/** /**
* Add an address in 10-digit hex string format * Add an address in 10-digit hex string format
*/ */
void add(const char *k, const Address &v); void add(const char* k, const Address& v);
/** /**
* Add a C string as a value * Add a C string as a value
*/ */
void add(const char *k, const char *v); void add(const char* k, const char* v);
/** /**
* Add a binary blob as a value * Add a binary blob as a value
*/ */
void add(const char *k, const void *data, unsigned int len); void add(const char* k, const void* data, unsigned int len);
/** /**
* Get an integer * Get an integer
@ -149,7 +154,7 @@ public:
* @param dfl Default value (default: 0) * @param dfl Default value (default: 0)
* @return Value of key or default if not found * @return Value of key or default if not found
*/ */
uint64_t getUI(const char *k, uint64_t dfl = 0) const; uint64_t getUI(const char* k, uint64_t dfl = 0) const;
/** /**
* Get a C string * Get a C string
@ -161,7 +166,7 @@ public:
* @param v Buffer to hold string * @param v Buffer to hold string
* @param cap Maximum size of string (including terminating null) * @param cap Maximum size of string (including terminating null)
*/ */
char *getS(const char *k, char *v, unsigned int cap) const; char* getS(const char* k, char* v, unsigned int cap) const;
/** /**
* Get an object supporting the marshal/unmarshal interface pattern * Get an object supporting the marshal/unmarshal interface pattern
@ -171,10 +176,9 @@ public:
* @param obj Object to unmarshal() into * @param obj Object to unmarshal() into
* @return True if unmarshal was successful * @return True if unmarshal was successful
*/ */
template< typename T > template <typename T> ZT_INLINE bool getO(const char* k, T& obj) const
ZT_INLINE bool getO(const char *k, T &obj) const
{ {
const Vector< uint8_t > &d = (*this)[k]; const Vector<uint8_t>& d = (*this)[k];
if (d.empty()) if (d.empty())
return false; return false;
return (obj.unmarshal(d.data(), (unsigned int)d.size()) > 0); return (obj.unmarshal(d.data(), (unsigned int)d.size()) > 0);
@ -188,10 +192,9 @@ public:
* @param obj Object to marshal() into vector * @param obj Object to marshal() into vector
* @return True if successful * @return True if successful
*/ */
template< typename T > template <typename T> ZT_INLINE bool addO(const char* k, T& obj)
ZT_INLINE bool addO(const char *k, T &obj)
{ {
Vector< uint8_t > &d = (*this)[k]; Vector<uint8_t>& d = (*this)[k];
d.resize(T::marshalSizeMax()); d.resize(T::marshalSizeMax());
const int l = obj.marshal(d.data()); const int l = obj.marshal(d.data());
if (l > 0) { if (l > 0) {
@ -211,20 +214,24 @@ public:
* @return Number of entries * @return Number of entries
*/ */
ZT_INLINE unsigned int size() const noexcept ZT_INLINE unsigned int size() const noexcept
{ return (unsigned int)m_entries.size(); } {
return (unsigned int)m_entries.size();
}
/** /**
* @return True if dictionary is not empty * @return True if dictionary is not empty
*/ */
ZT_INLINE bool empty() const noexcept ZT_INLINE bool empty() const noexcept
{ return m_entries.empty(); } {
return m_entries.empty();
}
/** /**
* Encode to a string in the supplied vector * Encode to a string in the supplied vector
* *
* @param out String encoded dictionary * @param out String encoded dictionary
*/ */
void encode(Vector< uint8_t > &out) const; void encode(Vector<uint8_t>& out) const;
/** /**
* Decode a string encoded dictionary * Decode a string encoded dictionary
@ -236,7 +243,7 @@ public:
* @param len Length of data * @param len Length of data
* @return True if dictionary was formatted correctly and valid, false on error * @return True if dictionary was formatted correctly and valid, false on error
*/ */
bool decode(const void *data, unsigned int len); bool decode(const void* data, unsigned int len);
/** /**
* Append a key=value pair to a buffer (vector or FCV) * Append a key=value pair to a buffer (vector or FCV)
@ -245,8 +252,7 @@ public:
* @param k Key (must be <= 8 characters) * @param k Key (must be <= 8 characters)
* @param v Value * @param v Value
*/ */
template< typename V > template <typename V> ZT_INLINE static void append(V& out, const char* const k, const bool v)
ZT_INLINE static void append(V &out, const char *const k, const bool v)
{ {
s_appendKey(out, k); s_appendKey(out, k);
out.push_back((uint8_t)(v ? '1' : '0')); out.push_back((uint8_t)(v ? '1' : '0'));
@ -260,8 +266,7 @@ public:
* @param k Key (must be <= 8 characters) * @param k Key (must be <= 8 characters)
* @param v Value * @param v Value
*/ */
template< typename V > template <typename V> ZT_INLINE static void append(V& out, const char* const k, const Address v)
ZT_INLINE static void append(V &out, const char *const k, const Address v)
{ {
s_appendKey(out, k); s_appendKey(out, k);
const uint64_t a = v.toInt(); const uint64_t a = v.toInt();
@ -286,8 +291,7 @@ public:
* @param k Key (must be <= 8 characters) * @param k Key (must be <= 8 characters)
* @param v Value * @param v Value
*/ */
template< typename V > template <typename V> ZT_INLINE static void append(V& out, const char* const k, const uint64_t v)
ZT_INLINE static void append(V &out, const char *const k, const uint64_t v)
{ {
s_appendKey(out, k); s_appendKey(out, k);
char buf[17]; char buf[17];
@ -298,33 +302,40 @@ public:
out.push_back((uint8_t)'\n'); out.push_back((uint8_t)'\n');
} }
template< typename V > template <typename V> ZT_INLINE static void append(V& out, const char* const k, const int64_t v)
ZT_INLINE static void append(V &out, const char *const k, const int64_t v) {
{ append(out, k, (uint64_t)v); } append(out, k, (uint64_t)v);
}
template< typename V > template <typename V> ZT_INLINE static void append(V& out, const char* const k, const uint32_t v)
ZT_INLINE static void append(V &out, const char *const k, const uint32_t v) {
{ append(out, k, (uint64_t)v); } append(out, k, (uint64_t)v);
}
template< typename V > template <typename V> ZT_INLINE static void append(V& out, const char* const k, const int32_t v)
ZT_INLINE static void append(V &out, const char *const k, const int32_t v) {
{ append(out, k, (uint64_t)v); } append(out, k, (uint64_t)v);
}
template< typename V > template <typename V> ZT_INLINE static void append(V& out, const char* const k, const uint16_t v)
ZT_INLINE static void append(V &out, const char *const k, const uint16_t v) {
{ append(out, k, (uint64_t)v); } append(out, k, (uint64_t)v);
}
template< typename V > template <typename V> ZT_INLINE static void append(V& out, const char* const k, const int16_t v)
ZT_INLINE static void append(V &out, const char *const k, const int16_t v) {
{ append(out, k, (uint64_t)v); } append(out, k, (uint64_t)v);
}
template< typename V > template <typename V> ZT_INLINE static void append(V& out, const char* const k, const uint8_t v)
ZT_INLINE static void append(V &out, const char *const k, const uint8_t v) {
{ append(out, k, (uint64_t)v); } append(out, k, (uint64_t)v);
}
template< typename V > template <typename V> ZT_INLINE static void append(V& out, const char* const k, const int8_t v)
ZT_INLINE static void append(V &out, const char *const k, const int8_t v) {
{ append(out, k, (uint64_t)v); } append(out, k, (uint64_t)v);
}
/** /**
* Append a key=value pair to a buffer (vector or FCV) * Append a key=value pair to a buffer (vector or FCV)
@ -333,13 +344,12 @@ public:
* @param k Key (must be <= 8 characters) * @param k Key (must be <= 8 characters)
* @param v Value * @param v Value
*/ */
template< typename V > template <typename V> ZT_INLINE static void append(V& out, const char* const k, const char* v)
ZT_INLINE static void append(V &out, const char *const k, const char *v)
{ {
if ((v) && (*v)) { if ((v) && (*v)) {
s_appendKey(out, k); s_appendKey(out, k);
while (*v) while (*v)
s_appendValueByte(out, (uint8_t)*(v++)); s_appendValueByte(out, (uint8_t) * (v++));
out.push_back((uint8_t)'\n'); out.push_back((uint8_t)'\n');
} }
} }
@ -352,12 +362,12 @@ public:
* @param v Value * @param v Value
* @param vlen Value length in bytes * @param vlen Value length in bytes
*/ */
template< typename V > template <typename V>
ZT_INLINE static void append(V &out, const char *const k, const void *const v, const unsigned int vlen) ZT_INLINE static void append(V& out, const char* const k, const void* const v, const unsigned int vlen)
{ {
s_appendKey(out, k); s_appendKey(out, k);
for (unsigned int i = 0; i < vlen; ++i) for (unsigned int i = 0; i < vlen; ++i)
s_appendValueByte(out, reinterpret_cast<const uint8_t *>(v)[i]); s_appendValueByte(out, reinterpret_cast<const uint8_t*>(v)[i]);
out.push_back((uint8_t)'\n'); out.push_back((uint8_t)'\n');
} }
@ -368,9 +378,10 @@ public:
* @param k Key (must be <= 8 characters) * @param k Key (must be <= 8 characters)
* @param pid Packet ID * @param pid Packet ID
*/ */
template< typename V > template <typename V> static ZT_INLINE void appendPacketId(V& out, const char* const k, const uint64_t pid)
static ZT_INLINE void appendPacketId(V &out, const char *const k, const uint64_t pid) {
{ append(out, k, &pid, 8); } append(out, k, &pid, 8);
}
/** /**
* Append key=value with any object implementing the correct marshal interface * Append key=value with any object implementing the correct marshal interface
@ -380,8 +391,7 @@ public:
* @param v Marshal-able object * @param v Marshal-able object
* @return Bytes appended or negative on error (return value of marshal()) * @return Bytes appended or negative on error (return value of marshal())
*/ */
template< typename V, typename T > template <typename V, typename T> static ZT_INLINE int appendObject(V& out, const char* const k, const T& v)
static ZT_INLINE int appendObject(V &out, const char *const k, const T &v)
{ {
uint8_t tmp[2048]; // large enough for any current object uint8_t tmp[2048]; // large enough for any current object
if (T::marshalSizeMax() > sizeof(tmp)) if (T::marshalSizeMax() > sizeof(tmp))
@ -400,11 +410,10 @@ public:
* @param sub Subscript index * @param sub Subscript index
* @return Pointer to 'buf' * @return Pointer to 'buf'
*/ */
static char *arraySubscript(char *buf, unsigned int bufSize, const char *name, const unsigned long sub) noexcept; static char* arraySubscript(char* buf, unsigned int bufSize, const char* name, const unsigned long sub) noexcept;
private: private:
template< typename V > template <typename V> ZT_INLINE static void s_appendValueByte(V& out, const uint8_t c)
ZT_INLINE static void s_appendValueByte(V &out, const uint8_t c)
{ {
switch (c) { switch (c) {
case 0: case 0:
@ -433,8 +442,7 @@ private:
} }
} }
template< typename V > template <typename V> ZT_INLINE static void s_appendKey(V& out, const char* k)
ZT_INLINE static void s_appendKey(V &out, const char *k)
{ {
for (;;) { for (;;) {
const char c = *(k++); const char c = *(k++);
@ -448,7 +456,7 @@ private:
// Dictionary maps need to be sorted so that they always encode in the same order // Dictionary maps need to be sorted so that they always encode in the same order
// to yield blobs that can be hashed and signed reproducibly. Other than for areas // to yield blobs that can be hashed and signed reproducibly. Other than for areas
// where dictionaries are signed and verified the order doesn't matter. // where dictionaries are signed and verified the order doesn't matter.
SortedMap< String, Vector< uint8_t > > m_entries; SortedMap<String, Vector<uint8_t> > m_entries;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -2,8 +2,9 @@
// https://github.com/esxgx/easy-ecc // https://github.com/esxgx/easy-ecc
// This code is under the BSD 2-clause license, not ZeroTier's license // This code is under the BSD 2-clause license, not ZeroTier's license
#include "Constants.hpp"
#include "ECC384.hpp" #include "ECC384.hpp"
#include "Constants.hpp"
#include "Utils.hpp" #include "Utils.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -14,47 +15,67 @@ namespace {
#define secp384r1 48 #define secp384r1 48
#define ECC_CURVE secp384r1 #define ECC_CURVE secp384r1
#define ECC_BYTES ECC_CURVE #define ECC_BYTES ECC_CURVE
#define NUM_ECC_DIGITS (ECC_BYTES/8) #define NUM_ECC_DIGITS (ECC_BYTES / 8)
#define ECC_CREATE_KEY_MAX_ATTEMPTS 1024 #define ECC_CREATE_KEY_MAX_ATTEMPTS 1024
#ifdef ZT_HAVE_UINT128 #ifdef ZT_HAVE_UINT128
#define SUPPORTS_INT128 1 #define SUPPORTS_INT128 1
#else #else
#define SUPPORTS_INT128 0 #define SUPPORTS_INT128 0
typedef struct typedef struct {
{
uint64_t m_low; uint64_t m_low;
uint64_t m_high; uint64_t m_high;
} uint128_t; } uint128_t;
#endif #endif
typedef struct EccPoint typedef struct EccPoint {
{
uint64_t x[NUM_ECC_DIGITS]; uint64_t x[NUM_ECC_DIGITS];
uint64_t y[NUM_ECC_DIGITS]; uint64_t y[NUM_ECC_DIGITS];
} EccPoint; } EccPoint;
#define CONCAT1(a, b) a##b #define CONCAT1(a, b) a##b
#define CONCAT(a, b) CONCAT1(a, b) #define CONCAT(a, b) CONCAT1(a, b)
#define Curve_P_48 {0x00000000FFFFFFFF, 0xFFFFFFFF00000000, 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF} #define Curve_P_48 \
#define Curve_B_48 {0x2A85C8EDD3EC2AEF, 0xC656398D8A2ED19D, 0x0314088F5013875A, 0x181D9C6EFE814112, 0x988E056BE3F82D19, 0xB3312FA7E23EE7E4} { \
#define Curve_G_48 {{0x3A545E3872760AB7, 0x5502F25DBF55296C, 0x59F741E082542A38, 0x6E1D3B628BA79B98, 0x8EB1C71EF320AD74, 0xAA87CA22BE8B0537}, {0x7A431D7C90EA0E5F, 0x0A60B1CE1D7E819D, 0xE9DA3113B5F0B8C0, 0xF8F41DBD289A147C, 0x5D9E98BF9292DC29, 0x3617DE4A96262C6F}} 0x00000000FFFFFFFF, 0xFFFFFFFF00000000, 0xFFFFFFFFFFFFFFFE, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, \
#define Curve_N_48 {0xECEC196ACCC52973, 0x581A0DB248B0A77A, 0xC7634D81F4372DDF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF} 0xFFFFFFFFFFFFFFFF \
}
#define Curve_B_48 \
{ \
0x2A85C8EDD3EC2AEF, 0xC656398D8A2ED19D, 0x0314088F5013875A, 0x181D9C6EFE814112, 0x988E056BE3F82D19, \
0xB3312FA7E23EE7E4 \
}
#define Curve_G_48 \
{ \
{ 0x3A545E3872760AB7, 0x5502F25DBF55296C, 0x59F741E082542A38, \
0x6E1D3B628BA79B98, 0x8EB1C71EF320AD74, 0xAA87CA22BE8B0537 }, \
{ \
0x7A431D7C90EA0E5F, 0x0A60B1CE1D7E819D, 0xE9DA3113B5F0B8C0, 0xF8F41DBD289A147C, 0x5D9E98BF9292DC29, \
0x3617DE4A96262C6F \
} \
}
#define Curve_N_48 \
{ \
0xECEC196ACCC52973, 0x581A0DB248B0A77A, 0xC7634D81F4372DDF, 0xFFFFFFFFFFFFFFFF, 0xFFFFFFFFFFFFFFFF, \
0xFFFFFFFFFFFFFFFF \
}
const uint64_t curve_p[NUM_ECC_DIGITS] = CONCAT(Curve_P_, ECC_CURVE); const uint64_t curve_p[NUM_ECC_DIGITS] = CONCAT(Curve_P_, ECC_CURVE);
const uint64_t curve_b[NUM_ECC_DIGITS] = CONCAT(Curve_B_, ECC_CURVE); const uint64_t curve_b[NUM_ECC_DIGITS] = CONCAT(Curve_B_, ECC_CURVE);
const EccPoint curve_G = CONCAT(Curve_G_, ECC_CURVE); const EccPoint curve_G = CONCAT(Curve_G_, ECC_CURVE);
const uint64_t curve_n[NUM_ECC_DIGITS] = CONCAT(Curve_N_, ECC_CURVE); const uint64_t curve_n[NUM_ECC_DIGITS] = CONCAT(Curve_N_, ECC_CURVE);
ZT_INLINE int getRandomNumber(uint64_t *p_vli) ZT_INLINE int getRandomNumber(uint64_t* p_vli)
{ {
Utils::getSecureRandom(p_vli, ECC_BYTES); Utils::getSecureRandom(p_vli, ECC_BYTES);
return 1; return 1;
} }
ZT_INLINE void vli_clear(uint64_t *p_vli) ZT_INLINE void vli_clear(uint64_t* p_vli)
{ Utils::zero< sizeof(uint64_t) * NUM_ECC_DIGITS >(p_vli); } {
Utils::zero<sizeof(uint64_t) * NUM_ECC_DIGITS>(p_vli);
}
ZT_INLINE int vli_isZero(const uint64_t *p_vli) ZT_INLINE int vli_isZero(const uint64_t* p_vli)
{ {
uint i; uint i;
for (i = 0; i < NUM_ECC_DIGITS; ++i) { for (i = 0; i < NUM_ECC_DIGITS; ++i) {
@ -64,17 +85,19 @@ ZT_INLINE int vli_isZero(const uint64_t *p_vli)
return 1; return 1;
} }
ZT_INLINE uint64_t vli_testBit(const uint64_t *p_vli, uint p_bit) ZT_INLINE uint64_t vli_testBit(const uint64_t* p_vli, uint p_bit)
{ return (p_vli[p_bit / 64] & ((uint64_t)1 << (p_bit % 64))); } {
return (p_vli[p_bit / 64] & ((uint64_t)1 << (p_bit % 64)));
}
ZT_INLINE uint vli_numDigits(const uint64_t *p_vli) ZT_INLINE uint vli_numDigits(const uint64_t* p_vli)
{ {
int i; int i;
for (i = NUM_ECC_DIGITS - 1; i >= 0 && p_vli[i] == 0; --i) {} for (i = NUM_ECC_DIGITS - 1; i >= 0 && p_vli[i] == 0; --i) {}
return (uint)(i + 1); return (uint)(i + 1);
} }
ZT_INLINE uint vli_numBits(const uint64_t *p_vli) ZT_INLINE uint vli_numBits(const uint64_t* p_vli)
{ {
uint i; uint i;
uint64_t l_digit; uint64_t l_digit;
@ -92,25 +115,26 @@ ZT_INLINE uint vli_numBits(const uint64_t *p_vli)
return ((l_numDigits - 1) * 64 + i); return ((l_numDigits - 1) * 64 + i);
} }
ZT_INLINE void vli_set(uint64_t *p_dest, const uint64_t *p_src) ZT_INLINE void vli_set(uint64_t* p_dest, const uint64_t* p_src)
{ {
for (uint i = 0; i < NUM_ECC_DIGITS; ++i) for (uint i = 0; i < NUM_ECC_DIGITS; ++i)
p_dest[i] = p_src[i]; p_dest[i] = p_src[i];
} }
ZT_INLINE int vli_cmp(const uint64_t *p_left, const uint64_t *p_right) ZT_INLINE int vli_cmp(const uint64_t* p_left, const uint64_t* p_right)
{ {
for (int i = NUM_ECC_DIGITS - 1; i >= 0; --i) { for (int i = NUM_ECC_DIGITS - 1; i >= 0; --i) {
if (p_left[i] > p_right[i]) { if (p_left[i] > p_right[i]) {
return 1; return 1;
} else if (p_left[i] < p_right[i]) { }
else if (p_left[i] < p_right[i]) {
return -1; return -1;
} }
} }
return 0; return 0;
} }
ZT_INLINE uint64_t vli_lshift(uint64_t *p_result, const uint64_t *p_in, uint p_shift) ZT_INLINE uint64_t vli_lshift(uint64_t* p_result, const uint64_t* p_in, uint p_shift)
{ {
uint64_t l_carry = 0; uint64_t l_carry = 0;
for (uint i = 0; i < NUM_ECC_DIGITS; ++i) { for (uint i = 0; i < NUM_ECC_DIGITS; ++i) {
@ -121,9 +145,9 @@ ZT_INLINE uint64_t vli_lshift(uint64_t *p_result, const uint64_t *p_in, uint p_s
return l_carry; return l_carry;
} }
ZT_INLINE void vli_rshift1(uint64_t *p_vli) ZT_INLINE void vli_rshift1(uint64_t* p_vli)
{ {
uint64_t *l_end = p_vli; uint64_t* l_end = p_vli;
uint64_t l_carry = 0; uint64_t l_carry = 0;
p_vli += NUM_ECC_DIGITS; p_vli += NUM_ECC_DIGITS;
while (p_vli-- > l_end) { while (p_vli-- > l_end) {
@ -133,7 +157,7 @@ ZT_INLINE void vli_rshift1(uint64_t *p_vli)
} }
} }
ZT_INLINE uint64_t vli_add(uint64_t *p_result, const uint64_t *p_left, const uint64_t *p_right) ZT_INLINE uint64_t vli_add(uint64_t* p_result, const uint64_t* p_left, const uint64_t* p_right)
{ {
uint64_t l_carry = 0; uint64_t l_carry = 0;
for (uint i = 0; i < NUM_ECC_DIGITS; ++i) { for (uint i = 0; i < NUM_ECC_DIGITS; ++i) {
@ -146,7 +170,7 @@ ZT_INLINE uint64_t vli_add(uint64_t *p_result, const uint64_t *p_left, const uin
return l_carry; return l_carry;
} }
ZT_INLINE uint64_t vli_sub(uint64_t *p_result, const uint64_t *p_left, const uint64_t *p_right) ZT_INLINE uint64_t vli_sub(uint64_t* p_result, const uint64_t* p_left, const uint64_t* p_right)
{ {
uint64_t l_borrow = 0; uint64_t l_borrow = 0;
for (uint i = 0; i < NUM_ECC_DIGITS; ++i) { for (uint i = 0; i < NUM_ECC_DIGITS; ++i) {
@ -161,7 +185,7 @@ ZT_INLINE uint64_t vli_sub(uint64_t *p_result, const uint64_t *p_left, const uin
#if SUPPORTS_INT128 == 1 #if SUPPORTS_INT128 == 1
void vli_mult(uint64_t *p_result, const uint64_t *p_left, const uint64_t *p_right) void vli_mult(uint64_t* p_result, const uint64_t* p_left, const uint64_t* p_right)
{ {
uint128_t r01 = 0; uint128_t r01 = 0;
uint64_t r2 = 0; uint64_t r2 = 0;
@ -183,7 +207,7 @@ void vli_mult(uint64_t *p_result, const uint64_t *p_left, const uint64_t *p_righ
p_result[NUM_ECC_DIGITS * 2 - 1] = (uint64_t)r01; p_result[NUM_ECC_DIGITS * 2 - 1] = (uint64_t)r01;
} }
void vli_square(uint64_t *p_result, const uint64_t *p_left) void vli_square(uint64_t* p_result, const uint64_t* p_left)
{ {
uint128_t r01 = 0; uint128_t r01 = 0;
uint64_t r2 = 0; uint64_t r2 = 0;
@ -244,9 +268,9 @@ ZT_INLINE uint128_t add_128_128(uint128_t a, uint128_t b)
return l_result; return l_result;
} }
void vli_mult(uint64_t *p_result, uint64_t *p_left, const uint64_t *p_right) void vli_mult(uint64_t* p_result, uint64_t* p_left, const uint64_t* p_right)
{ {
uint128_t r01 = {0, 0}; uint128_t r01 = { 0, 0 };
uint64_t r2 = 0; uint64_t r2 = 0;
uint i, k; uint i, k;
@ -268,9 +292,9 @@ void vli_mult(uint64_t *p_result, uint64_t *p_left, const uint64_t *p_right)
p_result[NUM_ECC_DIGITS * 2 - 1] = r01.m_low; p_result[NUM_ECC_DIGITS * 2 - 1] = r01.m_low;
} }
void vli_square(uint64_t *p_result, uint64_t *p_left) void vli_square(uint64_t* p_result, uint64_t* p_left)
{ {
uint128_t r01 = {0, 0}; uint128_t r01 = { 0, 0 };
uint64_t r2 = 0; uint64_t r2 = 0;
uint i, k; uint i, k;
@ -297,7 +321,7 @@ void vli_square(uint64_t *p_result, uint64_t *p_left)
#endif /* SUPPORTS_INT128 */ #endif /* SUPPORTS_INT128 */
void vli_modAdd(uint64_t *p_result, uint64_t *p_left, const uint64_t *p_right, const uint64_t *p_mod) void vli_modAdd(uint64_t* p_result, uint64_t* p_left, const uint64_t* p_right, const uint64_t* p_mod)
{ {
uint64_t l_carry = vli_add(p_result, p_left, p_right); uint64_t l_carry = vli_add(p_result, p_left, p_right);
if (l_carry || vli_cmp(p_result, p_mod) >= 0) { if (l_carry || vli_cmp(p_result, p_mod) >= 0) {
@ -305,7 +329,7 @@ void vli_modAdd(uint64_t *p_result, uint64_t *p_left, const uint64_t *p_right, c
} }
} }
void vli_modSub(uint64_t *p_result, uint64_t *p_left, const uint64_t *p_right, const uint64_t *p_mod) void vli_modSub(uint64_t* p_result, uint64_t* p_left, const uint64_t* p_right, const uint64_t* p_mod)
{ {
uint64_t l_borrow = vli_sub(p_result, p_left, p_right); uint64_t l_borrow = vli_sub(p_result, p_left, p_right);
if (l_borrow) { if (l_borrow) {
@ -313,7 +337,7 @@ void vli_modSub(uint64_t *p_result, uint64_t *p_left, const uint64_t *p_right, c
} }
} }
void omega_mult(uint64_t *p_result, uint64_t *p_right) void omega_mult(uint64_t* p_result, uint64_t* p_right)
{ {
uint64_t l_tmp[NUM_ECC_DIGITS]; uint64_t l_tmp[NUM_ECC_DIGITS];
uint64_t l_carry, l_diff; uint64_t l_carry, l_diff;
@ -336,11 +360,11 @@ void omega_mult(uint64_t *p_result, uint64_t *p_right)
p_result[NUM_ECC_DIGITS] = l_diff; p_result[NUM_ECC_DIGITS] = l_diff;
} }
void vli_mmod_fast(uint64_t *p_result, uint64_t *p_product) void vli_mmod_fast(uint64_t* p_result, uint64_t* p_product)
{ {
uint64_t l_tmp[2 * NUM_ECC_DIGITS]; uint64_t l_tmp[2 * NUM_ECC_DIGITS];
while (!vli_isZero(p_product + NUM_ECC_DIGITS)) { while (! vli_isZero(p_product + NUM_ECC_DIGITS)) {
uint64_t l_carry = 0; uint64_t l_carry = 0;
uint i; uint i;
@ -364,26 +388,26 @@ void vli_mmod_fast(uint64_t *p_result, uint64_t *p_product)
vli_set(p_result, p_product); vli_set(p_result, p_product);
} }
ZT_INLINE void vli_modMult_fast(uint64_t *p_result, uint64_t *p_left, const uint64_t *p_right) ZT_INLINE void vli_modMult_fast(uint64_t* p_result, uint64_t* p_left, const uint64_t* p_right)
{ {
uint64_t l_product[2 * NUM_ECC_DIGITS]; uint64_t l_product[2 * NUM_ECC_DIGITS];
vli_mult(l_product, p_left, p_right); vli_mult(l_product, p_left, p_right);
vli_mmod_fast(p_result, l_product); vli_mmod_fast(p_result, l_product);
} }
ZT_INLINE void vli_modSquare_fast(uint64_t *p_result, uint64_t *p_left) ZT_INLINE void vli_modSquare_fast(uint64_t* p_result, uint64_t* p_left)
{ {
uint64_t l_product[2 * NUM_ECC_DIGITS]; uint64_t l_product[2 * NUM_ECC_DIGITS];
vli_square(l_product, p_left); vli_square(l_product, p_left);
vli_mmod_fast(p_result, l_product); vli_mmod_fast(p_result, l_product);
} }
#define vli_isEven(vli) (!(vli[0] & 1)) #define vli_isEven(vli) (! (vli[0] & 1))
/* Computes p_result = (1 / p_input) % p_mod. All VLIs are the same size. /* Computes p_result = (1 / p_input) % p_mod. All VLIs are the same size.
See "From Euclid's GCD to Montgomery Multiplication to the Great Divide" See "From Euclid's GCD to Montgomery Multiplication to the Great Divide"
https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf */ https://labs.oracle.com/techrep/2001/smli_tr-2001-95.pdf */
void vli_modInv(uint64_t *p_result, uint64_t *p_input, const uint64_t *p_mod) void vli_modInv(uint64_t* p_result, uint64_t* p_input, const uint64_t* p_mod)
{ {
uint64_t a[NUM_ECC_DIGITS], b[NUM_ECC_DIGITS], u[NUM_ECC_DIGITS], v[NUM_ECC_DIGITS]; uint64_t a[NUM_ECC_DIGITS], b[NUM_ECC_DIGITS], u[NUM_ECC_DIGITS], v[NUM_ECC_DIGITS];
uint64_t l_carry; uint64_t l_carry;
@ -404,44 +428,47 @@ void vli_modInv(uint64_t *p_result, uint64_t *p_input, const uint64_t *p_mod)
l_carry = 0; l_carry = 0;
if (vli_isEven(a)) { if (vli_isEven(a)) {
vli_rshift1(a); vli_rshift1(a);
if (!vli_isEven(u)) { if (! vli_isEven(u)) {
l_carry = vli_add(u, u, p_mod); l_carry = vli_add(u, u, p_mod);
} }
vli_rshift1(u); vli_rshift1(u);
if (l_carry) { if (l_carry) {
u[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull; u[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull;
} }
} else if (vli_isEven(b)) { }
else if (vli_isEven(b)) {
vli_rshift1(b); vli_rshift1(b);
if (!vli_isEven(v)) { if (! vli_isEven(v)) {
l_carry = vli_add(v, v, p_mod); l_carry = vli_add(v, v, p_mod);
} }
vli_rshift1(v); vli_rshift1(v);
if (l_carry) { if (l_carry) {
v[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull; v[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull;
} }
} else if (l_cmpResult > 0) { }
else if (l_cmpResult > 0) {
vli_sub(a, a, b); vli_sub(a, a, b);
vli_rshift1(a); vli_rshift1(a);
if (vli_cmp(u, v) < 0) { if (vli_cmp(u, v) < 0) {
vli_add(u, u, p_mod); vli_add(u, u, p_mod);
} }
vli_sub(u, u, v); vli_sub(u, u, v);
if (!vli_isEven(u)) { if (! vli_isEven(u)) {
l_carry = vli_add(u, u, p_mod); l_carry = vli_add(u, u, p_mod);
} }
vli_rshift1(u); vli_rshift1(u);
if (l_carry) { if (l_carry) {
u[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull; u[NUM_ECC_DIGITS - 1] |= 0x8000000000000000ull;
} }
} else { }
else {
vli_sub(b, b, a); vli_sub(b, b, a);
vli_rshift1(b); vli_rshift1(b);
if (vli_cmp(v, u) < 0) { if (vli_cmp(v, u) < 0) {
vli_add(v, v, p_mod); vli_add(v, v, p_mod);
} }
vli_sub(v, v, u); vli_sub(v, v, u);
if (!vli_isEven(v)) { if (! vli_isEven(v)) {
l_carry = vli_add(v, v, p_mod); l_carry = vli_add(v, v, p_mod);
} }
vli_rshift1(v); vli_rshift1(v);
@ -454,10 +481,12 @@ void vli_modInv(uint64_t *p_result, uint64_t *p_input, const uint64_t *p_mod)
vli_set(p_result, u); vli_set(p_result, u);
} }
ZT_INLINE int EccPoint_isZero(EccPoint *p_point) ZT_INLINE int EccPoint_isZero(EccPoint* p_point)
{ return (vli_isZero(p_point->x) && vli_isZero(p_point->y)); } {
return (vli_isZero(p_point->x) && vli_isZero(p_point->y));
}
void EccPoint_double_jacobian(uint64_t *X1, uint64_t *Y1, uint64_t *Z1) void EccPoint_double_jacobian(uint64_t* X1, uint64_t* Y1, uint64_t* Z1)
{ {
/* t1 = X, t2 = Y, t3 = Z */ /* t1 = X, t2 = Y, t3 = Z */
uint64_t t4[NUM_ECC_DIGITS]; uint64_t t4[NUM_ECC_DIGITS];
@ -484,7 +513,8 @@ void EccPoint_double_jacobian(uint64_t *X1, uint64_t *Y1, uint64_t *Z1)
uint64_t l_carry = vli_add(X1, X1, curve_p); uint64_t l_carry = vli_add(X1, X1, curve_p);
vli_rshift1(X1); vli_rshift1(X1);
X1[NUM_ECC_DIGITS - 1] |= l_carry << 63U; X1[NUM_ECC_DIGITS - 1] |= l_carry << 63U;
} else { }
else {
vli_rshift1(X1); vli_rshift1(X1);
} }
/* t1 = 3/2*(x1^2 - z1^4) = B */ /* t1 = 3/2*(x1^2 - z1^4) = B */
@ -501,7 +531,7 @@ void EccPoint_double_jacobian(uint64_t *X1, uint64_t *Y1, uint64_t *Z1)
vli_set(Y1, t4); vli_set(Y1, t4);
} }
void apply_z(uint64_t *X1, uint64_t *Y1, uint64_t *Z) void apply_z(uint64_t* X1, uint64_t* Y1, uint64_t* Z)
{ {
uint64_t t1[NUM_ECC_DIGITS]; uint64_t t1[NUM_ECC_DIGITS];
@ -511,7 +541,7 @@ void apply_z(uint64_t *X1, uint64_t *Y1, uint64_t *Z)
vli_modMult_fast(Y1, Y1, t1); /* y1 * z^3 */ vli_modMult_fast(Y1, Y1, t1); /* y1 * z^3 */
} }
void XYcZ_initial_double(uint64_t *X1, uint64_t *Y1, uint64_t *X2, uint64_t *Y2, uint64_t *p_initialZ) void XYcZ_initial_double(uint64_t* X1, uint64_t* Y1, uint64_t* X2, uint64_t* Y2, uint64_t* p_initialZ)
{ {
uint64_t z[NUM_ECC_DIGITS]; uint64_t z[NUM_ECC_DIGITS];
@ -531,7 +561,7 @@ void XYcZ_initial_double(uint64_t *X1, uint64_t *Y1, uint64_t *X2, uint64_t *Y2,
apply_z(X2, Y2, z); apply_z(X2, Y2, z);
} }
void XYcZ_add(uint64_t *X1, uint64_t *Y1, uint64_t *X2, uint64_t *Y2) void XYcZ_add(uint64_t* X1, uint64_t* Y1, uint64_t* X2, uint64_t* Y2)
{ {
/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
uint64_t t5[NUM_ECC_DIGITS]; uint64_t t5[NUM_ECC_DIGITS];
@ -554,7 +584,7 @@ void XYcZ_add(uint64_t *X1, uint64_t *Y1, uint64_t *X2, uint64_t *Y2)
vli_set(X2, t5); vli_set(X2, t5);
} }
void XYcZ_addC(uint64_t *X1, uint64_t *Y1, uint64_t *X2, uint64_t *Y2) void XYcZ_addC(uint64_t* X1, uint64_t* Y1, uint64_t* X2, uint64_t* Y2)
{ {
/* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */ /* t1 = X1, t2 = Y1, t3 = X2, t4 = Y2 */
uint64_t t5[NUM_ECC_DIGITS]; uint64_t t5[NUM_ECC_DIGITS];
@ -587,7 +617,7 @@ void XYcZ_addC(uint64_t *X1, uint64_t *Y1, uint64_t *X2, uint64_t *Y2)
vli_set(X1, t7); vli_set(X1, t7);
} }
void EccPoint_mult(EccPoint *p_result, const EccPoint *p_point, uint64_t *p_scalar, uint64_t *p_initialZ) void EccPoint_mult(EccPoint* p_result, const EccPoint* p_point, uint64_t* p_scalar, uint64_t* p_initialZ)
{ {
/* R0 and R1 */ /* R0 and R1 */
uint64_t Rx[2][NUM_ECC_DIGITS]; uint64_t Rx[2][NUM_ECC_DIGITS];
@ -602,12 +632,12 @@ void EccPoint_mult(EccPoint *p_result, const EccPoint *p_point, uint64_t *p_scal
XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], p_initialZ); XYcZ_initial_double(Rx[1], Ry[1], Rx[0], Ry[0], p_initialZ);
for (i = (int)vli_numBits(p_scalar) - 2; i > 0; --i) { for (i = (int)vli_numBits(p_scalar) - 2; i > 0; --i) {
nb = !vli_testBit(p_scalar, i); nb = ! vli_testBit(p_scalar, i);
XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb]); XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb]);
XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb]); XYcZ_add(Rx[nb], Ry[nb], Rx[1 - nb], Ry[1 - nb]);
} }
nb = !vli_testBit(p_scalar, 0); nb = ! vli_testBit(p_scalar, 0);
XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb]); XYcZ_addC(Rx[1 - nb], Ry[1 - nb], Rx[nb], Ry[nb]);
/* Find final 1/Z value. */ /* Find final 1/Z value. */
@ -630,16 +660,17 @@ void EccPoint_mult(EccPoint *p_result, const EccPoint *p_point, uint64_t *p_scal
ZT_INLINE void ecc_bytes2native(uint64_t p_native[NUM_ECC_DIGITS], const uint8_t p_bytes[ECC_BYTES]) ZT_INLINE void ecc_bytes2native(uint64_t p_native[NUM_ECC_DIGITS], const uint8_t p_bytes[ECC_BYTES])
{ {
for (uint i = 0; i < NUM_ECC_DIGITS; ++i) { for (uint i = 0; i < NUM_ECC_DIGITS; ++i) {
const uint8_t *p_digit = p_bytes + 8 * (NUM_ECC_DIGITS - 1 - i); const uint8_t* p_digit = p_bytes + 8 * (NUM_ECC_DIGITS - 1 - i);
p_native[i] = ((uint64_t)p_digit[0] << 56) | ((uint64_t)p_digit[1] << 48) | ((uint64_t)p_digit[2] << 40) | ((uint64_t)p_digit[3] << 32) | p_native[i] = ((uint64_t)p_digit[0] << 56) | ((uint64_t)p_digit[1] << 48) | ((uint64_t)p_digit[2] << 40)
((uint64_t)p_digit[4] << 24) | ((uint64_t)p_digit[5] << 16) | ((uint64_t)p_digit[6] << 8) | (uint64_t)p_digit[7]; | ((uint64_t)p_digit[3] << 32) | ((uint64_t)p_digit[4] << 24) | ((uint64_t)p_digit[5] << 16)
| ((uint64_t)p_digit[6] << 8) | (uint64_t)p_digit[7];
} }
} }
ZT_INLINE void ecc_native2bytes(uint8_t p_bytes[ECC_BYTES], const uint64_t p_native[NUM_ECC_DIGITS]) ZT_INLINE void ecc_native2bytes(uint8_t p_bytes[ECC_BYTES], const uint64_t p_native[NUM_ECC_DIGITS])
{ {
for (uint i = 0; i < NUM_ECC_DIGITS; ++i) { for (uint i = 0; i < NUM_ECC_DIGITS; ++i) {
uint8_t *p_digit = p_bytes + 8 * (NUM_ECC_DIGITS - 1 - i); uint8_t* p_digit = p_bytes + 8 * (NUM_ECC_DIGITS - 1 - i);
p_digit[0] = p_native[i] >> 56; p_digit[0] = p_native[i] >> 56;
p_digit[1] = p_native[i] >> 48; p_digit[1] = p_native[i] >> 48;
p_digit[2] = p_native[i] >> 40; p_digit[2] = p_native[i] >> 40;
@ -653,8 +684,8 @@ ZT_INLINE void ecc_native2bytes(uint8_t p_bytes[ECC_BYTES], const uint64_t p_nat
void mod_sqrt(uint64_t a[NUM_ECC_DIGITS]) void mod_sqrt(uint64_t a[NUM_ECC_DIGITS])
{ {
uint64_t p1[NUM_ECC_DIGITS] = {1}; uint64_t p1[NUM_ECC_DIGITS] = { 1 };
uint64_t l_result[NUM_ECC_DIGITS] = {1}; uint64_t l_result[NUM_ECC_DIGITS] = { 1 };
vli_add(p1, curve_p, p1); /* p1 = curve_p + 1 */ vli_add(p1, curve_p, p1); /* p1 = curve_p + 1 */
for (uint i = vli_numBits(p1) - 1; i > 1; --i) { for (uint i = vli_numBits(p1) - 1; i > 1; --i) {
@ -666,9 +697,9 @@ void mod_sqrt(uint64_t a[NUM_ECC_DIGITS])
vli_set(a, l_result); vli_set(a, l_result);
} }
void ecc_point_decompress(EccPoint *p_point, const uint8_t p_compressed[ECC_BYTES + 1]) void ecc_point_decompress(EccPoint* p_point, const uint8_t p_compressed[ECC_BYTES + 1])
{ {
uint64_t _3[NUM_ECC_DIGITS] = {3}; /* -a = 3 */ uint64_t _3[NUM_ECC_DIGITS] = { 3 }; /* -a = 3 */
ecc_bytes2native(p_point->x, p_compressed + 1); ecc_bytes2native(p_point->x, p_compressed + 1);
vli_modSquare_fast(p_point->y, p_point->x); /* y = x^2 */ vli_modSquare_fast(p_point->y, p_point->x); /* y = x^2 */
@ -690,7 +721,7 @@ ZT_INLINE int ecc_make_key(uint8_t p_publicKey[ECC_BYTES + 1], uint8_t p_private
unsigned l_tries = 0; unsigned l_tries = 0;
do { do {
if (!getRandomNumber(l_private) || (l_tries++ >= ECC_CREATE_KEY_MAX_ATTEMPTS)) { if (! getRandomNumber(l_private) || (l_tries++ >= ECC_CREATE_KEY_MAX_ATTEMPTS)) {
return 0; return 0;
} }
if (vli_isZero(l_private)) { if (vli_isZero(l_private)) {
@ -710,13 +741,16 @@ ZT_INLINE int ecc_make_key(uint8_t p_publicKey[ECC_BYTES + 1], uint8_t p_private
return 1; return 1;
} }
ZT_INLINE int ecdh_shared_secret(const uint8_t p_publicKey[ECC_BYTES + 1], const uint8_t p_privateKey[ECC_BYTES], uint8_t p_secret[ECC_BYTES]) ZT_INLINE int ecdh_shared_secret(
const uint8_t p_publicKey[ECC_BYTES + 1],
const uint8_t p_privateKey[ECC_BYTES],
uint8_t p_secret[ECC_BYTES])
{ {
EccPoint l_public; EccPoint l_public;
uint64_t l_private[NUM_ECC_DIGITS]; uint64_t l_private[NUM_ECC_DIGITS];
uint64_t l_random[NUM_ECC_DIGITS]; uint64_t l_random[NUM_ECC_DIGITS];
if (!getRandomNumber(l_random)) { if (! getRandomNumber(l_random)) {
return 0; return 0;
} }
@ -728,11 +762,11 @@ ZT_INLINE int ecdh_shared_secret(const uint8_t p_publicKey[ECC_BYTES + 1], const
ecc_native2bytes(p_secret, l_product.x); ecc_native2bytes(p_secret, l_product.x);
return !EccPoint_isZero(&l_product); return ! EccPoint_isZero(&l_product);
} }
/* Computes p_result = (p_left * p_right) % p_mod. */ /* Computes p_result = (p_left * p_right) % p_mod. */
void vli_modMult(uint64_t *p_result, uint64_t *p_left, uint64_t *p_right, const uint64_t *p_mod) void vli_modMult(uint64_t* p_result, uint64_t* p_left, uint64_t* p_right, const uint64_t* p_mod)
{ {
uint64_t l_product[2 * NUM_ECC_DIGITS]; uint64_t l_product[2 * NUM_ECC_DIGITS];
uint64_t l_modMultiple[2 * NUM_ECC_DIGITS]; uint64_t l_modMultiple[2 * NUM_ECC_DIGITS];
@ -744,7 +778,8 @@ void vli_modMult(uint64_t *p_result, uint64_t *p_left, uint64_t *p_right, const
l_productBits = vli_numBits(l_product + NUM_ECC_DIGITS); l_productBits = vli_numBits(l_product + NUM_ECC_DIGITS);
if (l_productBits) { if (l_productBits) {
l_productBits += NUM_ECC_DIGITS * 64; l_productBits += NUM_ECC_DIGITS * 64;
} else { }
else {
l_productBits = vli_numBits(l_product); l_productBits = vli_numBits(l_product);
} }
@ -761,7 +796,8 @@ void vli_modMult(uint64_t *p_result, uint64_t *p_left, uint64_t *p_right, const
l_bitShift = (l_productBits - l_modBits) % 64; l_bitShift = (l_productBits - l_modBits) % 64;
if (l_bitShift) { if (l_bitShift) {
l_modMultiple[l_digitShift + NUM_ECC_DIGITS] = vli_lshift(l_modMultiple + l_digitShift, p_mod, l_bitShift); l_modMultiple[l_digitShift + NUM_ECC_DIGITS] = vli_lshift(l_modMultiple + l_digitShift, p_mod, l_bitShift);
} else { }
else {
vli_set(l_modMultiple + l_digitShift, p_mod); vli_set(l_modMultiple + l_digitShift, p_mod);
} }
@ -791,7 +827,8 @@ ZT_INLINE uint umax(uint a, uint b)
return (a > b ? a : b); return (a > b ? a : b);
} }
ZT_INLINE int ecdsa_sign(const uint8_t p_privateKey[ECC_BYTES], const uint8_t p_hash[ECC_BYTES], uint8_t p_signature[ECC_BYTES * 2]) ZT_INLINE int
ecdsa_sign(const uint8_t p_privateKey[ECC_BYTES], const uint8_t p_hash[ECC_BYTES], uint8_t p_signature[ECC_BYTES * 2])
{ {
uint64_t k[NUM_ECC_DIGITS]; uint64_t k[NUM_ECC_DIGITS];
uint64_t l_tmp[NUM_ECC_DIGITS]; uint64_t l_tmp[NUM_ECC_DIGITS];
@ -800,7 +837,7 @@ ZT_INLINE int ecdsa_sign(const uint8_t p_privateKey[ECC_BYTES], const uint8_t p_
unsigned l_tries = 0; unsigned l_tries = 0;
do { do {
if (!getRandomNumber(k) || (l_tries++ >= ECC_CREATE_KEY_MAX_ATTEMPTS)) { if (! getRandomNumber(k) || (l_tries++ >= ECC_CREATE_KEY_MAX_ATTEMPTS)) {
return 0; return 0;
} }
if (vli_isZero(k)) { if (vli_isZero(k)) {
@ -833,7 +870,10 @@ ZT_INLINE int ecdsa_sign(const uint8_t p_privateKey[ECC_BYTES], const uint8_t p_
return 1; return 1;
} }
ZT_INLINE int ecdsa_verify(const uint8_t p_publicKey[ECC_BYTES + 1], const uint8_t p_hash[ECC_BYTES], const uint8_t p_signature[ECC_BYTES * 2]) ZT_INLINE int ecdsa_verify(
const uint8_t p_publicKey[ECC_BYTES + 1],
const uint8_t p_hash[ECC_BYTES],
const uint8_t p_signature[ECC_BYTES * 2])
{ {
uint64_t u1[NUM_ECC_DIGITS], u2[NUM_ECC_DIGITS]; uint64_t u1[NUM_ECC_DIGITS], u2[NUM_ECC_DIGITS];
uint64_t z[NUM_ECC_DIGITS]; uint64_t z[NUM_ECC_DIGITS];
@ -875,10 +915,11 @@ ZT_INLINE int ecdsa_verify(const uint8_t p_publicKey[ECC_BYTES + 1], const uint8
apply_z(l_sum.x, l_sum.y, z); apply_z(l_sum.x, l_sum.y, z);
/* Use Shamir's trick to calculate u1*G + u2*Q */ /* Use Shamir's trick to calculate u1*G + u2*Q */
const EccPoint *l_points[4] = {NULL, &curve_G, &l_public, &l_sum}; const EccPoint* l_points[4] = { NULL, &curve_G, &l_public, &l_sum };
uint l_numBits = umax(vli_numBits(u1), vli_numBits(u2)); uint l_numBits = umax(vli_numBits(u1), vli_numBits(u2));
const EccPoint *l_point = l_points[(!!vli_testBit(u1, l_numBits - 1)) | ((!!vli_testBit(u2, l_numBits - 1)) << 1)]; const EccPoint* l_point =
l_points[(! ! vli_testBit(u1, l_numBits - 1)) | ((! ! vli_testBit(u2, l_numBits - 1)) << 1)];
vli_set(rx, l_point->x); vli_set(rx, l_point->x);
vli_set(ry, l_point->y); vli_set(ry, l_point->y);
vli_clear(z); vli_clear(z);
@ -888,8 +929,8 @@ ZT_INLINE int ecdsa_verify(const uint8_t p_publicKey[ECC_BYTES + 1], const uint8
for (i = l_numBits - 2; i >= 0; --i) { for (i = l_numBits - 2; i >= 0; --i) {
EccPoint_double_jacobian(rx, ry, z); EccPoint_double_jacobian(rx, ry, z);
int l_index = (!!vli_testBit(u1, i)) | ((!!vli_testBit(u2, i)) << 1); int l_index = (! ! vli_testBit(u1, i)) | ((! ! vli_testBit(u2, i)) << 1);
const EccPoint *l_point = l_points[l_index]; const EccPoint* l_point = l_points[l_index];
if (l_point) { if (l_point) {
vli_set(tx, l_point->x); vli_set(tx, l_point->x);
vli_set(ty, l_point->y); vli_set(ty, l_point->y);
@ -916,26 +957,35 @@ ZT_INLINE int ecdsa_verify(const uint8_t p_publicKey[ECC_BYTES + 1], const uint8
void ECC384GenerateKey(uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE], uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE]) void ECC384GenerateKey(uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE], uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE])
{ {
if (!ecc_make_key(pub, priv)) { if (! ecc_make_key(pub, priv)) {
fprintf(stderr, "FATAL: ecdsa_make_key() failed!" ZT_EOL_S); fprintf(stderr, "FATAL: ecdsa_make_key() failed!" ZT_EOL_S);
abort(); abort();
} }
} }
void ECC384ECDSASign(const uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE], const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE], uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]) void ECC384ECDSASign(
const uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE],
const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE],
uint8_t sig[ZT_ECC384_SIGNATURE_SIZE])
{ {
if (!ecdsa_sign(priv, hash, sig)) { if (! ecdsa_sign(priv, hash, sig)) {
fprintf(stderr, "FATAL: ecdsa_sign() failed!" ZT_EOL_S); fprintf(stderr, "FATAL: ecdsa_sign() failed!" ZT_EOL_S);
abort(); abort();
} }
} }
bool ECC384ECDSAVerify(const uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE], const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE], const uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]) bool ECC384ECDSAVerify(
const uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE],
const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE],
const uint8_t sig[ZT_ECC384_SIGNATURE_SIZE])
{ {
return (ecdsa_verify(pub, hash, sig) != 0); return (ecdsa_verify(pub, hash, sig) != 0);
} }
bool ECC384ECDH(const uint8_t theirPub[ZT_ECC384_PUBLIC_KEY_SIZE], const uint8_t ourPriv[ZT_ECC384_PRIVATE_KEY_SIZE], uint8_t secret[ZT_ECC384_SHARED_SECRET_SIZE]) bool ECC384ECDH(
const uint8_t theirPub[ZT_ECC384_PUBLIC_KEY_SIZE],
const uint8_t ourPriv[ZT_ECC384_PRIVATE_KEY_SIZE],
uint8_t secret[ZT_ECC384_SHARED_SECRET_SIZE])
{ {
return (ecdh_shared_secret(theirPub, ourPriv, secret) != 0); return (ecdh_shared_secret(theirPub, ourPriv, secret) != 0);
} }

View file

@ -65,7 +65,7 @@ namespace ZeroTier {
* @param pub Buffer to receive point compressed public key * @param pub Buffer to receive point compressed public key
* @param priv Buffer to receiver private key * @param priv Buffer to receiver private key
*/ */
void ECC384GenerateKey(uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE],uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE]); void ECC384GenerateKey(uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE], uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE]);
/** /**
* Sign a hash with a NIST P-384 private key * Sign a hash with a NIST P-384 private key
@ -77,7 +77,10 @@ void ECC384GenerateKey(uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE],uint8_t priv[ZT_EC
* @param hash 48-byte hash * @param hash 48-byte hash
* @param sig Buffer to receive signature * @param sig Buffer to receive signature
*/ */
void ECC384ECDSASign(const uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE],const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE],uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]); void ECC384ECDSASign(
const uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE],
const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE],
uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]);
/** /**
* Verify a signature * Verify a signature
@ -87,7 +90,10 @@ void ECC384ECDSASign(const uint8_t priv[ZT_ECC384_PRIVATE_KEY_SIZE],const uint8_
* @param sig Signature to check * @param sig Signature to check
* @return True if signature is valid * @return True if signature is valid
*/ */
bool ECC384ECDSAVerify(const uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE],const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE],const uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]); bool ECC384ECDSAVerify(
const uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE],
const uint8_t hash[ZT_ECC384_SIGNATURE_HASH_SIZE],
const uint8_t sig[ZT_ECC384_SIGNATURE_SIZE]);
/** /**
* Perform ECDH key agreement * Perform ECDH key agreement
@ -99,7 +105,10 @@ bool ECC384ECDSAVerify(const uint8_t pub[ZT_ECC384_PUBLIC_KEY_SIZE],const uint8_
* @param ourPriv Local private key * @param ourPriv Local private key
* @param secret Buffer to receive 48-byte secret * @param secret Buffer to receive 48-byte secret
*/ */
bool ECC384ECDH(const uint8_t theirPub[ZT_ECC384_PUBLIC_KEY_SIZE],const uint8_t ourPriv[ZT_ECC384_PRIVATE_KEY_SIZE],uint8_t secret[ZT_ECC384_SHARED_SECRET_SIZE]); bool ECC384ECDH(
const uint8_t theirPub[ZT_ECC384_PUBLIC_KEY_SIZE],
const uint8_t ourPriv[ZT_ECC384_PRIVATE_KEY_SIZE],
uint8_t secret[ZT_ECC384_SHARED_SECRET_SIZE]);
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -12,41 +12,60 @@
/****/ /****/
#include "Endpoint.hpp" #include "Endpoint.hpp"
#include "Utils.hpp" #include "Utils.hpp"
namespace ZeroTier { namespace ZeroTier {
static ZT_INLINE char s_endpointTypeChar(const ZT_EndpointType t) static ZT_INLINE char s_endpointTypeChar(const ZT_EndpointType t)
{ {
switch(t) { switch (t) {
default: return '0'; default:
case ZT_ENDPOINT_TYPE_ZEROTIER: return 'z'; return '0';
case ZT_ENDPOINT_TYPE_ETHERNET: return 'e'; case ZT_ENDPOINT_TYPE_ZEROTIER:
case ZT_ENDPOINT_TYPE_WIFI_DIRECT: return 'd'; return 'z';
case ZT_ENDPOINT_TYPE_BLUETOOTH: return 'b'; case ZT_ENDPOINT_TYPE_ETHERNET:
case ZT_ENDPOINT_TYPE_IP: return 'i'; return 'e';
case ZT_ENDPOINT_TYPE_IP_UDP: return 'u'; case ZT_ENDPOINT_TYPE_WIFI_DIRECT:
case ZT_ENDPOINT_TYPE_IP_TCP: return 't'; return 'd';
case ZT_ENDPOINT_TYPE_IP_TCP_WS: return 'w'; case ZT_ENDPOINT_TYPE_BLUETOOTH:
return 'b';
case ZT_ENDPOINT_TYPE_IP:
return 'i';
case ZT_ENDPOINT_TYPE_IP_UDP:
return 'u';
case ZT_ENDPOINT_TYPE_IP_TCP:
return 't';
case ZT_ENDPOINT_TYPE_IP_TCP_WS:
return 'w';
} }
} }
static ZT_INLINE ZT_EndpointType s_charEndpointType(const char c) static ZT_INLINE ZT_EndpointType s_charEndpointType(const char c)
{ {
switch(c) { switch (c) {
default: return ZT_ENDPOINT_TYPE_NIL; default:
case 'z': return ZT_ENDPOINT_TYPE_ZEROTIER; return ZT_ENDPOINT_TYPE_NIL;
case 'e': return ZT_ENDPOINT_TYPE_ETHERNET; case 'z':
case 'd': return ZT_ENDPOINT_TYPE_WIFI_DIRECT; return ZT_ENDPOINT_TYPE_ZEROTIER;
case 'b': return ZT_ENDPOINT_TYPE_BLUETOOTH; case 'e':
case 'i': return ZT_ENDPOINT_TYPE_IP; return ZT_ENDPOINT_TYPE_ETHERNET;
case 'u': return ZT_ENDPOINT_TYPE_IP_UDP; case 'd':
case 't': return ZT_ENDPOINT_TYPE_IP_TCP; return ZT_ENDPOINT_TYPE_WIFI_DIRECT;
case 'w': return ZT_ENDPOINT_TYPE_IP_TCP_WS; case 'b':
return ZT_ENDPOINT_TYPE_BLUETOOTH;
case 'i':
return ZT_ENDPOINT_TYPE_IP;
case 'u':
return ZT_ENDPOINT_TYPE_IP_UDP;
case 't':
return ZT_ENDPOINT_TYPE_IP_TCP;
case 'w':
return ZT_ENDPOINT_TYPE_IP_TCP_WS;
} }
} }
char *Endpoint::toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept char* Endpoint::toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept
{ {
static_assert(ZT_ENDPOINT_STRING_SIZE_MAX > (ZT_INETADDRESS_STRING_SIZE_MAX + 4), "overflow"); static_assert(ZT_ENDPOINT_STRING_SIZE_MAX > (ZT_INETADDRESS_STRING_SIZE_MAX + 4), "overflow");
static_assert(ZT_ENDPOINT_STRING_SIZE_MAX > (ZT_FINGERPRINT_STRING_SIZE_MAX + 4), "overflow"); static_assert(ZT_ENDPOINT_STRING_SIZE_MAX > (ZT_FINGERPRINT_STRING_SIZE_MAX + 4), "overflow");
@ -78,26 +97,27 @@ char *Endpoint::toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept
return s; return s;
} }
bool Endpoint::fromString(const char *s) noexcept bool Endpoint::fromString(const char* s) noexcept
{ {
memoryZero(this); memoryZero(this);
if ((!s) || (!*s)) { if ((! s) || (! *s)) {
// Empty strings are considered NIL endpoints. // Empty strings are considered NIL endpoints.
return true; return true;
} else if (s[1] == '/') { }
else if (s[1] == '/') {
// type/ADDRESS is a fully qualified endpoint. // type/ADDRESS is a fully qualified endpoint.
this->type = s_charEndpointType(s[0]); this->type = s_charEndpointType(s[0]);
switch(this->type) { switch (this->type) {
case ZT_ENDPOINT_TYPE_NIL: case ZT_ENDPOINT_TYPE_NIL:
break; break;
case ZT_ENDPOINT_TYPE_ZEROTIER: case ZT_ENDPOINT_TYPE_ZEROTIER:
if (!s[2]) if (! s[2])
return false; return false;
break; break;
case ZT_ENDPOINT_TYPE_ETHERNET: case ZT_ENDPOINT_TYPE_ETHERNET:
case ZT_ENDPOINT_TYPE_WIFI_DIRECT: case ZT_ENDPOINT_TYPE_WIFI_DIRECT:
case ZT_ENDPOINT_TYPE_BLUETOOTH: { case ZT_ENDPOINT_TYPE_BLUETOOTH: {
if (!s[2]) if (! s[2])
return false; return false;
MAC tmpmac; MAC tmpmac;
tmpmac.fromString(s + 2); tmpmac.fromString(s + 2);
@ -107,13 +127,14 @@ bool Endpoint::fromString(const char *s) noexcept
case ZT_ENDPOINT_TYPE_IP_UDP: case ZT_ENDPOINT_TYPE_IP_UDP:
case ZT_ENDPOINT_TYPE_IP_TCP: case ZT_ENDPOINT_TYPE_IP_TCP:
case ZT_ENDPOINT_TYPE_IP_TCP_WS: { case ZT_ENDPOINT_TYPE_IP_TCP_WS: {
if (!s[2]) if (! s[2])
return false; return false;
if (!asInetAddress(this->value.ss).fromString(s + 2)) if (! asInetAddress(this->value.ss).fromString(s + 2))
return false; return false;
} break; } break;
} }
} else if (strchr(s, '/') != nullptr) { }
else if (strchr(s, '/') != nullptr) {
// IP/port is parsed as an IP_UDP endpoint for backward compatibility. // IP/port is parsed as an IP_UDP endpoint for backward compatibility.
this->type = ZT_ENDPOINT_TYPE_IP_UDP; this->type = ZT_ENDPOINT_TYPE_IP_UDP;
return asInetAddress(this->value.ss).fromString(s); return asInetAddress(this->value.ss).fromString(s);
@ -155,7 +176,7 @@ int Endpoint::marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept
} }
} }
int Endpoint::unmarshal(const uint8_t *restrict data, int len) noexcept int Endpoint::unmarshal(const uint8_t* restrict data, int len) noexcept
{ {
memoryZero(this); memoryZero(this);
if (unlikely(len <= 0)) if (unlikely(len <= 0))
@ -217,14 +238,14 @@ int Endpoint::unmarshal(const uint8_t *restrict data, int len) noexcept
this->type = ZT_ENDPOINT_TYPE_NIL; this->type = ZT_ENDPOINT_TYPE_NIL;
if (len < 3) if (len < 3)
return -1; return -1;
const int unrecLen = 1 + (int) Utils::loadBigEndian<uint16_t>(data + 1); const int unrecLen = 1 + (int)Utils::loadBigEndian<uint16_t>(data + 1);
return (unrecLen > len) ? -1 : unrecLen; return (unrecLen > len) ? -1 : unrecLen;
} }
bool Endpoint::operator==(const Endpoint &ep) const noexcept bool Endpoint::operator==(const Endpoint& ep) const noexcept
{ {
if (this->type == ep.type) { if (this->type == ep.type) {
switch(this->type) { switch (this->type) {
case ZT_ENDPOINT_TYPE_ZEROTIER: case ZT_ENDPOINT_TYPE_ZEROTIER:
return zt() == ep.zt(); return zt() == ep.zt();
case ZT_ENDPOINT_TYPE_ETHERNET: case ZT_ENDPOINT_TYPE_ETHERNET:
@ -243,10 +264,10 @@ bool Endpoint::operator==(const Endpoint &ep) const noexcept
return false; return false;
} }
bool Endpoint::operator<(const Endpoint &ep) const noexcept bool Endpoint::operator<(const Endpoint& ep) const noexcept
{ {
if (this->type == ep.type) { if (this->type == ep.type) {
switch(this->type) { switch (this->type) {
case ZT_ENDPOINT_TYPE_ZEROTIER: case ZT_ENDPOINT_TYPE_ZEROTIER:
return zt() < ep.zt(); return zt() < ep.zt();
case ZT_ENDPOINT_TYPE_ETHERNET: case ZT_ENDPOINT_TYPE_ETHERNET:

View file

@ -14,24 +14,32 @@
#ifndef ZT_ENDPOINT_HPP #ifndef ZT_ENDPOINT_HPP
#define ZT_ENDPOINT_HPP #define ZT_ENDPOINT_HPP
#include "Constants.hpp"
#include "InetAddress.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Utils.hpp" #include "Constants.hpp"
#include "TriviallyCopyable.hpp"
#include "Fingerprint.hpp" #include "Fingerprint.hpp"
#include "InetAddress.hpp"
#include "MAC.hpp" #include "MAC.hpp"
#include "TriviallyCopyable.hpp"
#include "Utils.hpp"
#define ZT_ENDPOINT_STRING_SIZE_MAX 256 #define ZT_ENDPOINT_STRING_SIZE_MAX 256
#define ZT_ENDPOINT_MARSHAL_SIZE_MAX 192 #define ZT_ENDPOINT_MARSHAL_SIZE_MAX 192
namespace ZeroTier { namespace ZeroTier {
static_assert((ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > ZT_INETADDRESS_MARSHAL_SIZE_MAX, "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough"); static_assert(
static_assert((ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(ZT_Fingerprint), "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough"); (ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > ZT_INETADDRESS_MARSHAL_SIZE_MAX,
static_assert((ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(InetAddress), "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough"); "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough");
static_assert(
(ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(ZT_Fingerprint),
"ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough");
static_assert(
(ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(InetAddress),
"ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough");
static_assert((ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(MAC), "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough"); static_assert((ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(MAC), "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough");
static_assert((ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(Fingerprint), "ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough"); static_assert(
(ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(Fingerprint),
"ZT_ENDPOINT_MARSHAL_SIZE_MAX not large enough");
/** /**
* Endpoint variant specifying some form of network endpoint. * Endpoint variant specifying some form of network endpoint.
@ -42,17 +50,22 @@ static_assert((ZT_ENDPOINT_MARSHAL_SIZE_MAX - 1) > sizeof(Fingerprint), "ZT_ENDP
* where InetAddress was used as long as only the UDP type is exchanged * where InetAddress was used as long as only the UDP type is exchanged
* with those nodes. * with those nodes.
*/ */
class Endpoint : public ZT_Endpoint, public TriviallyCopyable class Endpoint
{ : public ZT_Endpoint
public: , public TriviallyCopyable {
public:
/** /**
* Create a NIL/empty endpoint * Create a NIL/empty endpoint
*/ */
ZT_INLINE Endpoint() noexcept ZT_INLINE Endpoint() noexcept
{ memoryZero(this); } {
memoryZero(this);
}
ZT_INLINE Endpoint(const ZT_Endpoint &ep) noexcept ZT_INLINE Endpoint(const ZT_Endpoint& ep) noexcept
{ Utils::copy< sizeof(ZT_Endpoint) >((ZT_Endpoint *)this, &ep); } {
Utils::copy<sizeof(ZT_Endpoint)>((ZT_Endpoint*)this, &ep);
}
/** /**
* Create an endpoint for a type that uses an IP * Create an endpoint for a type that uses an IP
@ -60,12 +73,13 @@ public:
* @param a IP/port * @param a IP/port
* @param et Endpoint type (default: IP_UDP) * @param et Endpoint type (default: IP_UDP)
*/ */
ZT_INLINE Endpoint(const InetAddress &inaddr, const ZT_EndpointType et = ZT_ENDPOINT_TYPE_IP_UDP) noexcept ZT_INLINE Endpoint(const InetAddress& inaddr, const ZT_EndpointType et = ZT_ENDPOINT_TYPE_IP_UDP) noexcept
{ {
if (inaddr) { if (inaddr) {
this->type = et; this->type = et;
Utils::copy< sizeof(struct sockaddr_storage) >(&(this->value.ss), &(inaddr.as.ss)); Utils::copy<sizeof(struct sockaddr_storage)>(&(this->value.ss), &(inaddr.as.ss));
} else { }
else {
memoryZero(this); memoryZero(this);
} }
} }
@ -75,12 +89,13 @@ public:
* *
* @param zt_ ZeroTier identity fingerprint * @param zt_ ZeroTier identity fingerprint
*/ */
ZT_INLINE Endpoint(const Fingerprint &zt_) noexcept ZT_INLINE Endpoint(const Fingerprint& zt_) noexcept
{ {
if (zt_) { if (zt_) {
this->type = ZT_ENDPOINT_TYPE_ZEROTIER; this->type = ZT_ENDPOINT_TYPE_ZEROTIER;
this->value.fp = zt_; this->value.fp = zt_;
} else { }
else {
memoryZero(this); memoryZero(this);
} }
} }
@ -91,12 +106,13 @@ public:
* @param eth_ Ethernet address * @param eth_ Ethernet address
* @param et Endpoint type (default: ETHERNET) * @param et Endpoint type (default: ETHERNET)
*/ */
ZT_INLINE Endpoint(const MAC &eth_, const ZT_EndpointType et = ZT_ENDPOINT_TYPE_ETHERNET) noexcept ZT_INLINE Endpoint(const MAC& eth_, const ZT_EndpointType et = ZT_ENDPOINT_TYPE_ETHERNET) noexcept
{ {
if (eth_) { if (eth_) {
this->type = et; this->type = et;
this->value.mac = eth_.toInt(); this->value.mac = eth_.toInt();
} else { }
else {
memoryZero(this); memoryZero(this);
} }
} }
@ -105,7 +121,9 @@ public:
* @return True if endpoint type isn't NIL * @return True if endpoint type isn't NIL
*/ */
ZT_INLINE operator bool() const noexcept ZT_INLINE operator bool() const noexcept
{ return this->type != ZT_ENDPOINT_TYPE_NIL; } {
return this->type != ZT_ENDPOINT_TYPE_NIL;
}
/** /**
* @return True if this endpoint type has an InetAddress address type and thus ip() is valid * @return True if this endpoint type has an InetAddress address type and thus ip() is valid
@ -132,7 +150,7 @@ public:
* @param ep Endpoint to check * @param ep Endpoint to check
* @return True if endpoints seem to refer to the same address/host * @return True if endpoints seem to refer to the same address/host
*/ */
ZT_INLINE bool isSameAddress(const Endpoint &ep) const noexcept ZT_INLINE bool isSameAddress(const Endpoint& ep) const noexcept
{ {
switch (this->type) { switch (this->type) {
case ZT_ENDPOINT_TYPE_IP: case ZT_ENDPOINT_TYPE_IP:
@ -160,8 +178,10 @@ public:
* *
* @return InetAddress instance * @return InetAddress instance
*/ */
ZT_INLINE const InetAddress &ip() const noexcept ZT_INLINE const InetAddress& ip() const noexcept
{ return asInetAddress(this->value.ss); } {
return asInetAddress(this->value.ss);
}
/** /**
* Get MAC if this is an Ethernet, WiFi direct, or Bluetooth type (undefined otherwise) * Get MAC if this is an Ethernet, WiFi direct, or Bluetooth type (undefined otherwise)
@ -169,7 +189,9 @@ public:
* @return Ethernet MAC * @return Ethernet MAC
*/ */
ZT_INLINE MAC eth() const noexcept ZT_INLINE MAC eth() const noexcept
{ return MAC(this->value.mac); } {
return MAC(this->value.mac);
}
/** /**
* Get fingerprint if this is a ZeroTier endpoint type (undefined otherwise) * Get fingerprint if this is a ZeroTier endpoint type (undefined otherwise)
@ -177,7 +199,9 @@ public:
* @return ZeroTier fingerprint * @return ZeroTier fingerprint
*/ */
ZT_INLINE Fingerprint zt() const noexcept ZT_INLINE Fingerprint zt() const noexcept
{ return Fingerprint(this->value.fp); } {
return Fingerprint(this->value.fp);
}
ZT_INLINE unsigned long hashCode() const noexcept ZT_INLINE unsigned long hashCode() const noexcept
{ {
@ -198,7 +222,7 @@ public:
} }
} }
char *toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept; char* toString(char s[ZT_ENDPOINT_STRING_SIZE_MAX]) const noexcept;
ZT_INLINE String toString() const ZT_INLINE String toString() const
{ {
@ -206,30 +230,40 @@ public:
return String(toString(tmp)); return String(toString(tmp));
} }
bool fromString(const char *s) noexcept; bool fromString(const char* s) noexcept;
static constexpr int marshalSizeMax() noexcept static constexpr int marshalSizeMax() noexcept
{ return ZT_ENDPOINT_MARSHAL_SIZE_MAX; } {
return ZT_ENDPOINT_MARSHAL_SIZE_MAX;
}
int marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept; int marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept;
int unmarshal(const uint8_t *restrict data, int len) noexcept; int unmarshal(const uint8_t* restrict data, int len) noexcept;
bool operator==(const Endpoint &ep) const noexcept; bool operator==(const Endpoint& ep) const noexcept;
ZT_INLINE bool operator!=(const Endpoint &ep) const noexcept ZT_INLINE bool operator!=(const Endpoint& ep) const noexcept
{ return !((*this) == ep); } {
return ! ((*this) == ep);
}
bool operator<(const Endpoint &ep) const noexcept; bool operator<(const Endpoint& ep) const noexcept;
ZT_INLINE bool operator>(const Endpoint &ep) const noexcept ZT_INLINE bool operator>(const Endpoint& ep) const noexcept
{ return (ep < *this); } {
return (ep < *this);
}
ZT_INLINE bool operator<=(const Endpoint &ep) const noexcept ZT_INLINE bool operator<=(const Endpoint& ep) const noexcept
{ return !(ep < *this); } {
return ! (ep < *this);
}
ZT_INLINE bool operator>=(const Endpoint &ep) const noexcept ZT_INLINE bool operator>=(const Endpoint& ep) const noexcept
{ return !(*this < ep); } {
return ! (*this < ep);
}
}; };
static_assert(sizeof(Endpoint) == sizeof(ZT_Endpoint), "size mismatch"); static_assert(sizeof(Endpoint) == sizeof(ZT_Endpoint), "size mismatch");

View file

@ -36,12 +36,11 @@ namespace ZeroTier {
/** /**
* Tracker for expected OK replies to packet IDs of sent packets * Tracker for expected OK replies to packet IDs of sent packets
*/ */
class Expect class Expect {
{ public:
public: ZT_INLINE Expect() : m_packetIdSent()
ZT_INLINE Expect() : {
m_packetIdSent() }
{}
/** /**
* Called by other code when something is sending a packet that could potentially receive an OK response * Called by other code when something is sending a packet that could potentially receive an OK response
@ -50,7 +49,10 @@ public:
* @param now Current time * @param now Current time
*/ */
ZT_INLINE void sending(const uint64_t packetId, const int64_t now) noexcept ZT_INLINE void sending(const uint64_t packetId, const int64_t now) noexcept
{ m_packetIdSent[Utils::hash64(packetId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS] = (uint32_t)(now / ZT_EXPECT_TTL); } {
m_packetIdSent[Utils::hash64(packetId ^ Utils::s_mapNonce) % ZT_EXPECT_BUCKETS] =
(uint32_t)(now / ZT_EXPECT_TTL);
}
/** /**
* Check if an OK is expected and if so reset the corresponding bucket. * Check if an OK is expected and if so reset the corresponding bucket.
@ -64,11 +66,18 @@ public:
* @return True if we're expecting a reply (and a reset occurred) * @return True if we're expecting a reply (and a reset occurred)
*/ */
ZT_INLINE bool expecting(const uint64_t inRePacketId, const int64_t now) noexcept ZT_INLINE bool expecting(const uint64_t inRePacketId, const int64_t now) noexcept
{ return (((now / ZT_EXPECT_TTL) - (int64_t)m_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: private:
// Each bucket contains a timestamp in units of the max expect duration. // Each bucket contains a timestamp in units of the max expect duration.
std::atomic< uint32_t > m_packetIdSent[ZT_EXPECT_BUCKETS]; std::atomic<uint32_t> m_packetIdSent[ZT_EXPECT_BUCKETS];
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -16,8 +16,8 @@
#include "Constants.hpp" #include "Constants.hpp"
#include <iterator>
#include <algorithm> #include <algorithm>
#include <iterator>
#include <memory> #include <memory>
#include <stdexcept> #include <stdexcept>
@ -32,30 +32,28 @@ namespace ZeroTier {
* @tparam T Type to contain * @tparam T Type to contain
* @tparam C Maximum capacity of vector * @tparam C Maximum capacity of vector
*/ */
template< typename T, unsigned int C > template <typename T, unsigned int C> class FCV {
class FCV public:
{ typedef T* iterator;
public: typedef const T* const_iterator;
typedef T *iterator;
typedef const T *const_iterator;
ZT_INLINE FCV() noexcept: _s(0) ZT_INLINE FCV() noexcept : _s(0)
{} {
}
ZT_INLINE FCV(const FCV &v) : _s(0) ZT_INLINE FCV(const FCV& v) : _s(0)
{ *this = v; } {
*this = v;
}
ZT_INLINE FCV(const T *const contents, const unsigned int len) : ZT_INLINE FCV(const T* const contents, const unsigned int len) : _s(len)
_s(len)
{ {
const unsigned int l = std::min(len, C); const unsigned int l = std::min(len, C);
for (unsigned int i = 0; i < l; ++i) for (unsigned int i = 0; i < l; ++i)
new(reinterpret_cast<T *>(_m) + i) T(contents[i]); new (reinterpret_cast<T*>(_m) + i) T(contents[i]);
} }
template< typename I > template <typename I> ZT_INLINE FCV(I i, I end) : _s(0)
ZT_INLINE FCV(I i, I end) :
_s(0)
{ {
while (i != end) { while (i != end) {
push_back(*i); push_back(*i);
@ -64,16 +62,18 @@ public:
} }
ZT_INLINE ~FCV() ZT_INLINE ~FCV()
{ this->clear(); } {
this->clear();
}
ZT_INLINE FCV &operator=(const FCV &v) ZT_INLINE FCV& operator=(const FCV& v)
{ {
if (likely(&v != this)) { if (likely(&v != this)) {
this->clear(); this->clear();
const unsigned int s = v._s; const unsigned int s = v._s;
_s = s; _s = s;
for (unsigned int i = 0; i < s; ++i) for (unsigned int i = 0; i < s; ++i)
new(reinterpret_cast<T *>(_m) + i) T(*(reinterpret_cast<const T *>(v._m) + i)); new (reinterpret_cast<T*>(_m) + i) T(*(reinterpret_cast<const T*>(v._m) + i));
} }
return *this; return *this;
} }
@ -86,7 +86,7 @@ public:
const unsigned int s = _s; const unsigned int s = _s;
_s = 0; _s = 0;
for (unsigned int i = 0; i < s; ++i) for (unsigned int i = 0; i < s; ++i)
(reinterpret_cast<T *>(_m) + i)->~T(); (reinterpret_cast<T*>(_m) + i)->~T();
} }
/** /**
@ -94,52 +94,70 @@ public:
* *
* @param v Target vector * @param v Target vector
*/ */
ZT_INLINE void unsafeMoveTo(FCV &v) noexcept ZT_INLINE void unsafeMoveTo(FCV& v) noexcept
{ {
Utils::copy(v._m, _m, (v._s = _s) * sizeof(T)); Utils::copy(v._m, _m, (v._s = _s) * sizeof(T));
_s = 0; _s = 0;
} }
ZT_INLINE iterator begin() noexcept ZT_INLINE iterator begin() noexcept
{ return reinterpret_cast<T *>(_m); } {
return reinterpret_cast<T*>(_m);
}
ZT_INLINE iterator end() noexcept ZT_INLINE iterator end() noexcept
{ return reinterpret_cast<T *>(_m) + _s; } {
return reinterpret_cast<T*>(_m) + _s;
}
ZT_INLINE const_iterator begin() const noexcept ZT_INLINE const_iterator begin() const noexcept
{ return reinterpret_cast<const T *>(_m); } {
return reinterpret_cast<const T*>(_m);
}
ZT_INLINE const_iterator end() const noexcept ZT_INLINE const_iterator end() const noexcept
{ return reinterpret_cast<const T *>(_m) + _s; } {
return reinterpret_cast<const T*>(_m) + _s;
}
ZT_INLINE T &operator[](const unsigned int i) ZT_INLINE T& operator[](const unsigned int i)
{ {
if (likely(i < _s)) if (likely(i < _s))
return reinterpret_cast<T *>(_m)[i]; return reinterpret_cast<T*>(_m)[i];
throw Utils::OutOfRangeException; throw Utils::OutOfRangeException;
} }
ZT_INLINE const T &operator[](const unsigned int i) const ZT_INLINE const T& operator[](const unsigned int i) const
{ {
if (likely(i < _s)) if (likely(i < _s))
return reinterpret_cast<const T *>(_m)[i]; return reinterpret_cast<const T*>(_m)[i];
throw Utils::OutOfRangeException; throw Utils::OutOfRangeException;
} }
static constexpr unsigned int capacity() noexcept static constexpr unsigned int capacity() noexcept
{ return C; } {
return C;
}
ZT_INLINE unsigned int size() const noexcept ZT_INLINE unsigned int size() const noexcept
{ return _s; } {
return _s;
}
ZT_INLINE bool empty() const noexcept ZT_INLINE bool empty() const noexcept
{ return (_s == 0); } {
return (_s == 0);
}
ZT_INLINE T *data() noexcept ZT_INLINE T* data() noexcept
{ return reinterpret_cast<T *>(_m); } {
return reinterpret_cast<T*>(_m);
}
ZT_INLINE const T *data() const noexcept ZT_INLINE const T* data() const noexcept
{ return reinterpret_cast<const T *>(_m); } {
return reinterpret_cast<const T*>(_m);
}
/** /**
* Push a value onto the back of this vector * Push a value onto the back of this vector
@ -148,11 +166,12 @@ public:
* *
* @param v Value to push * @param v Value to push
*/ */
ZT_INLINE void push_back(const T &v) ZT_INLINE void push_back(const T& v)
{ {
if (likely(_s < C)) if (likely(_s < C))
new(reinterpret_cast<T *>(_m) + _s++) T(v); new (reinterpret_cast<T*>(_m) + _s++) T(v);
else throw Utils::OutOfRangeException; else
throw Utils::OutOfRangeException;
} }
/** /**
@ -160,12 +179,13 @@ public:
* *
* @return Reference to new item * @return Reference to new item
*/ */
ZT_INLINE T &push() ZT_INLINE T& push()
{ {
if (likely(_s < C)) { if (likely(_s < C)) {
return *(new(reinterpret_cast<T *>(_m) + _s++) T()); return *(new (reinterpret_cast<T*>(_m) + _s++) T());
} else { }
return *(reinterpret_cast<T *>(_m) + (C - 1)); else {
return *(reinterpret_cast<T*>(_m) + (C - 1));
} }
} }
@ -174,12 +194,13 @@ public:
* *
* @return Reference to new item * @return Reference to new item
*/ */
ZT_INLINE T &push(const T &v) ZT_INLINE T& push(const T& v)
{ {
if (likely(_s < C)) { if (likely(_s < C)) {
return *(new(reinterpret_cast<T *>(_m) + _s++) T(v)); return *(new (reinterpret_cast<T*>(_m) + _s++) T(v));
} else { }
T &tmp = *(reinterpret_cast<T *>(_m) + (C - 1)); else {
T& tmp = *(reinterpret_cast<T*>(_m) + (C - 1));
tmp = v; tmp = v;
return tmp; return tmp;
} }
@ -191,7 +212,7 @@ public:
ZT_INLINE void pop_back() ZT_INLINE void pop_back()
{ {
if (likely(_s != 0)) if (likely(_s != 0))
(reinterpret_cast<T *>(_m) + --_s)->~T(); (reinterpret_cast<T*>(_m) + --_s)->~T();
} }
/** /**
@ -205,9 +226,9 @@ public:
throw Utils::OutOfRangeException; throw Utils::OutOfRangeException;
unsigned int s = _s; unsigned int s = _s;
while (s < ns) while (s < ns)
new(reinterpret_cast<T *>(_m) + s++) T(); new (reinterpret_cast<T*>(_m) + s++) T();
while (s > ns) while (s > ns)
(reinterpret_cast<T *>(_m) + --s)->~T(); (reinterpret_cast<T*>(_m) + --s)->~T();
_s = s; _s = s;
} }
@ -217,7 +238,9 @@ public:
* @param ns New size * @param ns New size
*/ */
ZT_INLINE void unsafeSetSize(unsigned int ns) ZT_INLINE void unsafeSetSize(unsigned int ns)
{ _s = ns; } {
_s = ns;
}
/** /**
* This is a bounds checked auto-resizing variant of the [] operator * This is a bounds checked auto-resizing variant of the [] operator
@ -228,16 +251,16 @@ public:
* @param i Index to obtain as a reference, resizing if needed * @param i Index to obtain as a reference, resizing if needed
* @return Reference to value at this index * @return Reference to value at this index
*/ */
ZT_INLINE T &at(unsigned int i) ZT_INLINE T& at(unsigned int i)
{ {
if (i >= _s) { if (i >= _s) {
if (unlikely(i >= C)) if (unlikely(i >= C))
i = C - 1; i = C - 1;
do { do {
new(reinterpret_cast<T *>(_m) + _s++) T(); new (reinterpret_cast<T*>(_m) + _s++) T();
} while (i >= _s); } while (i >= _s);
} }
return *(reinterpret_cast<T *>(_m) + i); return *(reinterpret_cast<T*>(_m) + i);
} }
/** /**
@ -249,24 +272,24 @@ public:
* @param start Starting iterator * @param start Starting iterator
* @param end Ending iterator (must be greater than start) * @param end Ending iterator (must be greater than start)
*/ */
template< typename X > template <typename X> ZT_INLINE void assign(X start, const X& end)
ZT_INLINE void assign(X start, const X &end)
{ {
const int l = std::min((int)std::distance(start, end), (int)C); const int l = std::min((int)std::distance(start, end), (int)C);
if (l > 0) { if (l > 0) {
this->resize((unsigned int)l); this->resize((unsigned int)l);
for (int i = 0; i < l; ++i) for (int i = 0; i < l; ++i)
reinterpret_cast<T *>(_m)[i] = *(start++); reinterpret_cast<T*>(_m)[i] = *(start++);
} else { }
else {
this->clear(); this->clear();
} }
} }
ZT_INLINE bool operator==(const FCV &v) const noexcept ZT_INLINE bool operator==(const FCV& v) const noexcept
{ {
if (_s == v._s) { if (_s == v._s) {
for (unsigned int i = 0; i < _s; ++i) { for (unsigned int i = 0; i < _s; ++i) {
if (!(*(reinterpret_cast<const T *>(_m) + i) == *(reinterpret_cast<const T *>(v._m) + i))) if (! (*(reinterpret_cast<const T*>(_m) + i) == *(reinterpret_cast<const T*>(v._m) + i)))
return false; return false;
} }
return true; return true;
@ -274,22 +297,32 @@ public:
return false; return false;
} }
ZT_INLINE bool operator!=(const FCV &v) const noexcept ZT_INLINE bool operator!=(const FCV& v) const noexcept
{ return *this != v; } {
return *this != v;
}
ZT_INLINE bool operator<(const FCV &v) const noexcept ZT_INLINE bool operator<(const FCV& v) const noexcept
{ return std::lexicographical_compare(begin(), end(), v.begin(), v.end()); } {
return std::lexicographical_compare(begin(), end(), v.begin(), v.end());
}
ZT_INLINE bool operator>(const FCV &v) const noexcept ZT_INLINE bool operator>(const FCV& v) const noexcept
{ return (v < *this); } {
return (v < *this);
}
ZT_INLINE bool operator<=(const FCV &v) const noexcept ZT_INLINE bool operator<=(const FCV& v) const noexcept
{ return v >= *this; } {
return v >= *this;
}
ZT_INLINE bool operator>=(const FCV &v) const noexcept ZT_INLINE bool operator>=(const FCV& v) const noexcept
{ return *this >= v; } {
return *this >= v;
}
private: private:
#ifdef _MSC_VER #ifdef _MSC_VER
uint8_t _m[sizeof(T) * C]; uint8_t _m[sizeof(T) * C];
#else #else

View file

@ -14,9 +14,9 @@
#ifndef ZT_FINGERPRINT_HPP #ifndef ZT_FINGERPRINT_HPP
#define ZT_FINGERPRINT_HPP #define ZT_FINGERPRINT_HPP
#include "Address.hpp"
#include "Constants.hpp" #include "Constants.hpp"
#include "TriviallyCopyable.hpp" #include "TriviallyCopyable.hpp"
#include "Address.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#define ZT_FINGERPRINT_STRING_SIZE_MAX 128 #define ZT_FINGERPRINT_STRING_SIZE_MAX 128
@ -30,32 +30,43 @@ namespace ZeroTier {
* This is the same size as ZT_Fingerprint and should be cast-able back and forth. * This is the same size as ZT_Fingerprint and should be cast-able back and forth.
* This is checked in Tests.cpp. * This is checked in Tests.cpp.
*/ */
class Fingerprint : public ZT_Fingerprint, public TriviallyCopyable class Fingerprint
{ : public ZT_Fingerprint
public: , public TriviallyCopyable {
public:
ZT_INLINE Fingerprint() noexcept ZT_INLINE Fingerprint() noexcept
{ memoryZero(this); } {
memoryZero(this);
}
ZT_INLINE Fingerprint(const ZT_Fingerprint &fp) noexcept ZT_INLINE Fingerprint(const ZT_Fingerprint& fp) noexcept
{ Utils::copy< sizeof(ZT_Fingerprint) >(this, &fp); } {
Utils::copy<sizeof(ZT_Fingerprint)>(this, &fp);
}
/** /**
* @return True if hash is not all zero (missing/unspecified) * @return True if hash is not all zero (missing/unspecified)
*/ */
ZT_INLINE bool haveHash() const noexcept ZT_INLINE bool haveHash() const noexcept
{ return (!Utils::allZero(this->hash, ZT_FINGERPRINT_HASH_SIZE)); } {
return (! Utils::allZero(this->hash, ZT_FINGERPRINT_HASH_SIZE));
}
/** /**
* Get a base32-encoded representation of this fingerprint * Get a base32-encoded representation of this fingerprint
* *
* @param s Base32 string * @param s Base32 string
*/ */
ZT_INLINE char *toString(char s[ZT_FINGERPRINT_STRING_SIZE_MAX]) const noexcept ZT_INLINE char* toString(char s[ZT_FINGERPRINT_STRING_SIZE_MAX]) const noexcept
{ {
Address(this->address).toString(s); Address(this->address).toString(s);
if (haveHash()) { if (haveHash()) {
s[ZT_ADDRESS_LENGTH_HEX] = '-'; s[ZT_ADDRESS_LENGTH_HEX] = '-';
Utils::b32e(this->hash, ZT_FINGERPRINT_HASH_SIZE, s + (ZT_ADDRESS_LENGTH_HEX + 1), ZT_FINGERPRINT_STRING_SIZE_MAX - (ZT_ADDRESS_LENGTH_HEX + 1)); Utils::b32e(
this->hash,
ZT_FINGERPRINT_HASH_SIZE,
s + (ZT_ADDRESS_LENGTH_HEX + 1),
ZT_FINGERPRINT_STRING_SIZE_MAX - (ZT_ADDRESS_LENGTH_HEX + 1));
} }
return s; return s;
} }
@ -72,71 +83,95 @@ public:
* @param s String to decode * @param s String to decode
* @return True if string appears to be valid and of the proper length (no other checking is done) * @return True if string appears to be valid and of the proper length (no other checking is done)
*/ */
ZT_INLINE bool fromString(const char *const s) noexcept ZT_INLINE bool fromString(const char* const s) noexcept
{ {
if (!s) if (! s)
return false; return false;
const int l = (int)strlen(s); const int l = (int)strlen(s);
if (l < ZT_ADDRESS_LENGTH_HEX) if (l < ZT_ADDRESS_LENGTH_HEX)
return false; return false;
char a[ZT_ADDRESS_LENGTH_HEX + 1]; char a[ZT_ADDRESS_LENGTH_HEX + 1];
Utils::copy< ZT_ADDRESS_LENGTH_HEX >(a, s); Utils::copy<ZT_ADDRESS_LENGTH_HEX>(a, s);
a[ZT_ADDRESS_LENGTH_HEX] = 0; a[ZT_ADDRESS_LENGTH_HEX] = 0;
this->address = Utils::hexStrToU64(a) & ZT_ADDRESS_MASK; this->address = Utils::hexStrToU64(a) & ZT_ADDRESS_MASK;
if (l > (ZT_ADDRESS_LENGTH_HEX + 1)) { if (l > (ZT_ADDRESS_LENGTH_HEX + 1)) {
if (Utils::b32d(s + (ZT_ADDRESS_LENGTH_HEX + 1), this->hash, ZT_FINGERPRINT_HASH_SIZE) != ZT_FINGERPRINT_HASH_SIZE) if (Utils::b32d(s + (ZT_ADDRESS_LENGTH_HEX + 1), this->hash, ZT_FINGERPRINT_HASH_SIZE)
!= ZT_FINGERPRINT_HASH_SIZE)
return false; return false;
} else { }
Utils::zero< ZT_FINGERPRINT_HASH_SIZE >(this->hash); else {
Utils::zero<ZT_FINGERPRINT_HASH_SIZE>(this->hash);
} }
return true; return true;
} }
ZT_INLINE void zero() noexcept ZT_INLINE void zero() noexcept
{ memoryZero(this); } {
memoryZero(this);
}
ZT_INLINE unsigned long hashCode() const noexcept ZT_INLINE unsigned long hashCode() const noexcept
{ return (unsigned long)this->address; } {
return (unsigned long)this->address;
}
ZT_INLINE operator bool() const noexcept ZT_INLINE operator bool() const noexcept
{ return this->address != 0; } {
return this->address != 0;
}
static constexpr int marshalSizeMax() noexcept static constexpr int marshalSizeMax() noexcept
{ return ZT_FINGERPRINT_MARSHAL_SIZE; } {
return ZT_FINGERPRINT_MARSHAL_SIZE;
}
ZT_INLINE int marshal(uint8_t data[ZT_FINGERPRINT_MARSHAL_SIZE]) const noexcept ZT_INLINE int marshal(uint8_t data[ZT_FINGERPRINT_MARSHAL_SIZE]) const noexcept
{ {
Address(this->address).copyTo(data); Address(this->address).copyTo(data);
Utils::copy< ZT_FINGERPRINT_HASH_SIZE >(data + ZT_ADDRESS_LENGTH, this->hash); Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(data + ZT_ADDRESS_LENGTH, this->hash);
return ZT_FINGERPRINT_MARSHAL_SIZE; return ZT_FINGERPRINT_MARSHAL_SIZE;
} }
ZT_INLINE int unmarshal(const uint8_t *const data, int len) noexcept ZT_INLINE int unmarshal(const uint8_t* const data, int len) noexcept
{ {
if (unlikely(len < ZT_FINGERPRINT_MARSHAL_SIZE)) if (unlikely(len < ZT_FINGERPRINT_MARSHAL_SIZE))
return -1; return -1;
this->address = Address(data); this->address = Address(data);
Utils::copy< ZT_FINGERPRINT_HASH_SIZE >(hash, data + ZT_ADDRESS_LENGTH); Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(hash, data + ZT_ADDRESS_LENGTH);
return ZT_FINGERPRINT_MARSHAL_SIZE; return ZT_FINGERPRINT_MARSHAL_SIZE;
} }
ZT_INLINE bool operator==(const ZT_Fingerprint &h) const noexcept ZT_INLINE bool operator==(const ZT_Fingerprint& h) const noexcept
{ return ((this->address == h.address) && (memcmp(this->hash, h.hash, ZT_FINGERPRINT_HASH_SIZE) == 0)); } {
return ((this->address == h.address) && (memcmp(this->hash, h.hash, ZT_FINGERPRINT_HASH_SIZE) == 0));
}
ZT_INLINE bool operator!=(const ZT_Fingerprint &h) const noexcept ZT_INLINE bool operator!=(const ZT_Fingerprint& h) const noexcept
{ return !(*this == h); } {
return ! (*this == h);
}
ZT_INLINE bool operator<(const ZT_Fingerprint &h) const noexcept ZT_INLINE bool operator<(const ZT_Fingerprint& h) const noexcept
{ return ((this->address < h.address) || ((this->address == h.address) && (memcmp(this->hash, h.hash, ZT_FINGERPRINT_HASH_SIZE) < 0))); } {
return (
(this->address < h.address)
|| ((this->address == h.address) && (memcmp(this->hash, h.hash, ZT_FINGERPRINT_HASH_SIZE) < 0)));
}
ZT_INLINE bool operator>(const ZT_Fingerprint &h) const noexcept ZT_INLINE bool operator>(const ZT_Fingerprint& h) const noexcept
{ return (*reinterpret_cast<const Fingerprint *>(&h) < *this); } {
return (*reinterpret_cast<const Fingerprint*>(&h) < *this);
}
ZT_INLINE bool operator<=(const ZT_Fingerprint &h) const noexcept ZT_INLINE bool operator<=(const ZT_Fingerprint& h) const noexcept
{ return !(*reinterpret_cast<const Fingerprint *>(&h) < *this); } {
return ! (*reinterpret_cast<const Fingerprint*>(&h) < *this);
}
ZT_INLINE bool operator>=(const ZT_Fingerprint &h) const noexcept ZT_INLINE bool operator>=(const ZT_Fingerprint& h) const noexcept
{ return !(*this < h); } {
return ! (*this < h);
}
}; };
static_assert(sizeof(Fingerprint) == sizeof(ZT_Fingerprint), "size mismatch"); static_assert(sizeof(Fingerprint) == sizeof(ZT_Fingerprint), "size mismatch");

View file

@ -11,13 +11,14 @@
*/ */
/****/ /****/
#include "Constants.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "Constants.hpp"
#include "Endpoint.hpp"
#include "MIMC52.hpp"
#include "SHA512.hpp" #include "SHA512.hpp"
#include "Salsa20.hpp" #include "Salsa20.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include "Endpoint.hpp"
#include "MIMC52.hpp"
#include <memory> #include <memory>
#include <utility> #include <utility>
@ -29,7 +30,10 @@ namespace {
// This is the memory-intensive hash function used to compute v0 identities from v0 public keys. // This is the memory-intensive hash function used to compute v0 identities from v0 public keys.
#define ZT_V0_IDENTITY_GEN_MEMORY 2097152 #define ZT_V0_IDENTITY_GEN_MEMORY 2097152
void identityV0ProofOfWorkFrankenhash(const void *const restrict c25519CombinedPublicKey, void *const restrict digest, void *const restrict genmem) noexcept void identityV0ProofOfWorkFrankenhash(
const void* const restrict c25519CombinedPublicKey,
void* const restrict digest,
void* const restrict genmem) noexcept
{ {
// Digest publicKey[] to obtain initial digest // Digest publicKey[] to obtain initial digest
SHA512(digest, c25519CombinedPublicKey, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE); SHA512(digest, c25519CombinedPublicKey, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE);
@ -37,37 +41,40 @@ void identityV0ProofOfWorkFrankenhash(const void *const restrict c25519CombinedP
// Initialize genmem[] using Salsa20 in a CBC-like configuration since // Initialize genmem[] using Salsa20 in a CBC-like configuration since
// ordinary Salsa20 is randomly seek-able. This is good for a cipher // ordinary Salsa20 is randomly seek-able. This is good for a cipher
// but is not what we want for sequential memory-hardness. // but is not what we want for sequential memory-hardness.
Utils::zero< ZT_V0_IDENTITY_GEN_MEMORY >(genmem); Utils::zero<ZT_V0_IDENTITY_GEN_MEMORY>(genmem);
Salsa20 s20(digest, (char *)digest + 32); Salsa20 s20(digest, (char*)digest + 32);
s20.crypt20((char *)genmem, (char *)genmem, 64); s20.crypt20((char*)genmem, (char*)genmem, 64);
for (unsigned long i = 64; i < ZT_V0_IDENTITY_GEN_MEMORY; i += 64) { for (unsigned long i = 64; i < ZT_V0_IDENTITY_GEN_MEMORY; i += 64) {
unsigned long k = i - 64; unsigned long k = i - 64;
*((uint64_t *)((char *)genmem + i)) = *((uint64_t *)((char *)genmem + k)); *((uint64_t*)((char*)genmem + i)) = *((uint64_t*)((char*)genmem + k));
*((uint64_t *)((char *)genmem + i + 8)) = *((uint64_t *)((char *)genmem + k + 8)); *((uint64_t*)((char*)genmem + i + 8)) = *((uint64_t*)((char*)genmem + k + 8));
*((uint64_t *)((char *)genmem + i + 16)) = *((uint64_t *)((char *)genmem + k + 16)); *((uint64_t*)((char*)genmem + i + 16)) = *((uint64_t*)((char*)genmem + k + 16));
*((uint64_t *)((char *)genmem + i + 24)) = *((uint64_t *)((char *)genmem + k + 24)); *((uint64_t*)((char*)genmem + i + 24)) = *((uint64_t*)((char*)genmem + k + 24));
*((uint64_t *)((char *)genmem + i + 32)) = *((uint64_t *)((char *)genmem + k + 32)); *((uint64_t*)((char*)genmem + i + 32)) = *((uint64_t*)((char*)genmem + k + 32));
*((uint64_t *)((char *)genmem + i + 40)) = *((uint64_t *)((char *)genmem + k + 40)); *((uint64_t*)((char*)genmem + i + 40)) = *((uint64_t*)((char*)genmem + k + 40));
*((uint64_t *)((char *)genmem + i + 48)) = *((uint64_t *)((char *)genmem + k + 48)); *((uint64_t*)((char*)genmem + i + 48)) = *((uint64_t*)((char*)genmem + k + 48));
*((uint64_t *)((char *)genmem + i + 56)) = *((uint64_t *)((char *)genmem + k + 56)); *((uint64_t*)((char*)genmem + i + 56)) = *((uint64_t*)((char*)genmem + k + 56));
s20.crypt20((char *)genmem + i, (char *)genmem + i, 64); s20.crypt20((char*)genmem + i, (char*)genmem + i, 64);
} }
// Render final digest using genmem as a lookup table // Render final digest using genmem as a lookup table
for (unsigned long i = 0; i < (ZT_V0_IDENTITY_GEN_MEMORY / sizeof(uint64_t));) { for (unsigned long i = 0; i < (ZT_V0_IDENTITY_GEN_MEMORY / sizeof(uint64_t));) {
unsigned long idx1 = (unsigned long)(Utils::ntoh(((uint64_t *)genmem)[i++]) % (64 / sizeof(uint64_t))); unsigned long idx1 = (unsigned long)(Utils::ntoh(((uint64_t*)genmem)[i++]) % (64 / sizeof(uint64_t)));
unsigned long idx2 = (unsigned long)(Utils::ntoh(((uint64_t *)genmem)[i++]) % (ZT_V0_IDENTITY_GEN_MEMORY / sizeof(uint64_t))); unsigned long idx2 =
uint64_t tmp = ((uint64_t *)genmem)[idx2]; (unsigned long)(Utils::ntoh(((uint64_t*)genmem)[i++]) % (ZT_V0_IDENTITY_GEN_MEMORY / sizeof(uint64_t)));
((uint64_t *)genmem)[idx2] = ((uint64_t *)digest)[idx1]; uint64_t tmp = ((uint64_t*)genmem)[idx2];
((uint64_t *)digest)[idx1] = tmp; ((uint64_t*)genmem)[idx2] = ((uint64_t*)digest)[idx1];
((uint64_t*)digest)[idx1] = tmp;
s20.crypt20(digest, digest, 64); s20.crypt20(digest, digest, 64);
} }
} }
struct identityV0ProofOfWorkCriteria struct identityV0ProofOfWorkCriteria {
{ ZT_INLINE identityV0ProofOfWorkCriteria(unsigned char* restrict sb, char* restrict gm) noexcept
ZT_INLINE identityV0ProofOfWorkCriteria(unsigned char *restrict sb, char *restrict gm) noexcept: digest(sb), genmem(gm) : digest(sb)
{} , genmem(gm)
{
}
ZT_INLINE bool operator()(const uint8_t pub[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE]) const noexcept ZT_INLINE bool operator()(const uint8_t pub[ZT_C25519_COMBINED_PUBLIC_KEY_SIZE]) const noexcept
{ {
@ -75,8 +82,8 @@ struct identityV0ProofOfWorkCriteria
return (digest[0] < 17); return (digest[0] < 17);
} }
unsigned char *restrict digest; unsigned char* restrict digest;
char *restrict genmem; char* restrict genmem;
}; };
void v1ChallengeFromPub(const uint8_t pub[ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE], uint64_t challenge[4]) void v1ChallengeFromPub(const uint8_t pub[ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE], uint64_t challenge[4])
@ -85,17 +92,17 @@ void v1ChallengeFromPub(const uint8_t pub[ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_S
// a hash, just different for different public keys. Public keys are basically kind of hashes of // a hash, just different for different public keys. Public keys are basically kind of hashes of
// private keys, so that's good enough. This is only used to seed a PRNG in MIMC52 for a proof of // private keys, so that's good enough. This is only used to seed a PRNG in MIMC52 for a proof of
// sequential work. It's not used for authentication beyond checking PoW. // sequential work. It's not used for authentication beyond checking PoW.
Utils::copy< 32 >(challenge, pub + 7); Utils::copy<32>(challenge, pub + 7);
challenge[0] ^= Utils::loadMachineEndian< uint64_t >(pub + 40); challenge[0] ^= Utils::loadMachineEndian<uint64_t>(pub + 40);
challenge[1] ^= Utils::loadMachineEndian< uint64_t >(pub + 48); challenge[1] ^= Utils::loadMachineEndian<uint64_t>(pub + 48);
challenge[2] ^= Utils::loadMachineEndian< uint64_t >(pub + 56); challenge[2] ^= Utils::loadMachineEndian<uint64_t>(pub + 56);
challenge[3] ^= Utils::loadMachineEndian< uint64_t >(pub + 64); challenge[3] ^= Utils::loadMachineEndian<uint64_t>(pub + 64);
challenge[0] ^= Utils::loadMachineEndian< uint64_t >(pub + 72); challenge[0] ^= Utils::loadMachineEndian<uint64_t>(pub + 72);
challenge[1] ^= Utils::loadMachineEndian< uint64_t >(pub + 80); challenge[1] ^= Utils::loadMachineEndian<uint64_t>(pub + 80);
challenge[2] ^= Utils::loadMachineEndian< uint64_t >(pub + 88); challenge[2] ^= Utils::loadMachineEndian<uint64_t>(pub + 88);
challenge[3] ^= Utils::loadMachineEndian< uint64_t >(pub + 96); challenge[3] ^= Utils::loadMachineEndian<uint64_t>(pub + 96);
challenge[0] ^= Utils::loadMachineEndian< uint64_t >(pub + 104); challenge[0] ^= Utils::loadMachineEndian<uint64_t>(pub + 104);
challenge[1] ^= Utils::loadMachineEndian< uint64_t >(pub + 112); challenge[1] ^= Utils::loadMachineEndian<uint64_t>(pub + 112);
} }
} // anonymous namespace } // anonymous namespace
@ -108,12 +115,11 @@ bool Identity::generate(const Type t)
m_hasPrivate = true; m_hasPrivate = true;
switch (t) { switch (t) {
case C25519: { case C25519: {
// Generate C25519/Ed25519 key pair whose hash satisfies a "hashcash" criterion and generate the // Generate C25519/Ed25519 key pair whose hash satisfies a "hashcash" criterion and generate the
// address from the last 40 bits of this hash. This is different from the fingerprint hash for V0. // address from the last 40 bits of this hash. This is different from the fingerprint hash for V0.
uint8_t digest[64]; uint8_t digest[64];
char *const genmem = new char[ZT_V0_IDENTITY_GEN_MEMORY]; char* const genmem = new char[ZT_V0_IDENTITY_GEN_MEMORY];
Address address; Address address;
do { do {
C25519::generateSatisfying(identityV0ProofOfWorkCriteria(digest, genmem), m_pub, m_priv); C25519::generateSatisfying(identityV0ProofOfWorkCriteria(digest, genmem), m_pub, m_priv);
@ -122,17 +128,19 @@ bool Identity::generate(const Type t)
delete[] genmem; delete[] genmem;
m_fp.address = address; // address comes from PoW hash for type 0 identities m_fp.address = address; // address comes from PoW hash for type 0 identities
m_computeHash(); m_computeHash();
} } break;
break;
case P384: case P384:
for (;;) { for (;;) {
C25519::generateCombined(m_pub + 7, m_priv); C25519::generateCombined(m_pub + 7, m_priv);
ECC384GenerateKey(m_pub + 7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE); ECC384GenerateKey(
m_pub + 7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE,
m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE);
uint64_t challenge[4]; uint64_t challenge[4];
v1ChallengeFromPub(m_pub, challenge); v1ChallengeFromPub(m_pub, challenge);
const uint64_t proof = MIMC52::delay(reinterpret_cast<const uint8_t *>(challenge), ZT_IDENTITY_TYPE1_MIMC52_ROUNDS); const uint64_t proof =
MIMC52::delay(reinterpret_cast<const uint8_t*>(challenge), ZT_IDENTITY_TYPE1_MIMC52_ROUNDS);
m_pub[0] = (uint8_t)(proof >> 48U); m_pub[0] = (uint8_t)(proof >> 48U);
m_pub[1] = (uint8_t)(proof >> 40U); m_pub[1] = (uint8_t)(proof >> 40U);
m_pub[2] = (uint8_t)(proof >> 32U); m_pub[2] = (uint8_t)(proof >> 32U);
@ -143,7 +151,7 @@ bool Identity::generate(const Type t)
m_computeHash(); m_computeHash();
const Address addr(m_fp.hash); const Address addr(m_fp.hash);
if (!addr.isReserved()) { if (! addr.isReserved()) {
m_fp.address = addr; m_fp.address = addr;
break; break;
} }
@ -160,13 +168,12 @@ bool Identity::generate(const Type t)
bool Identity::locallyValidate() const noexcept bool Identity::locallyValidate() const noexcept
{ {
try { try {
if ((m_fp) && ((!Address(m_fp.address).isReserved()))) { if ((m_fp) && ((! Address(m_fp.address).isReserved()))) {
switch (m_type) { switch (m_type) {
case C25519: { case C25519: {
uint8_t digest[64]; uint8_t digest[64];
char *const genmem = (char *)malloc(ZT_V0_IDENTITY_GEN_MEMORY); char* const genmem = (char*)malloc(ZT_V0_IDENTITY_GEN_MEMORY);
if (!genmem) if (! genmem)
return false; return false;
identityV0ProofOfWorkFrankenhash(m_pub, digest, genmem); identityV0ProofOfWorkFrankenhash(m_pub, digest, genmem);
free(genmem); free(genmem);
@ -177,13 +184,19 @@ bool Identity::locallyValidate() const noexcept
if (Address(m_fp.hash) == m_fp.address) { if (Address(m_fp.hash) == m_fp.address) {
uint64_t challenge[4]; uint64_t challenge[4];
v1ChallengeFromPub(m_pub, challenge); v1ChallengeFromPub(m_pub, challenge);
return MIMC52::verify(reinterpret_cast<const uint8_t *>(challenge), ZT_IDENTITY_TYPE1_MIMC52_ROUNDS, ((uint64_t)m_pub[0] << 48U) | ((uint64_t)m_pub[1] << 40U) | ((uint64_t)m_pub[2] << 32U) | ((uint64_t)m_pub[3] << 24U) | ((uint64_t)m_pub[4] << 16U) | ((uint64_t)m_pub[5] << 8U) | (uint64_t)m_pub[6]); return MIMC52::verify(
reinterpret_cast<const uint8_t*>(challenge),
ZT_IDENTITY_TYPE1_MIMC52_ROUNDS,
((uint64_t)m_pub[0] << 48U) | ((uint64_t)m_pub[1] << 40U) | ((uint64_t)m_pub[2] << 32U)
| ((uint64_t)m_pub[3] << 24U) | ((uint64_t)m_pub[4] << 16U) | ((uint64_t)m_pub[5] << 8U)
| (uint64_t)m_pub[6]);
} }
return false; return false;
} }
} }
} catch (...) {} }
catch (...) {
}
return false; return false;
} }
@ -191,7 +204,6 @@ void Identity::hashWithPrivate(uint8_t h[ZT_FINGERPRINT_HASH_SIZE]) const
{ {
if (m_hasPrivate) { if (m_hasPrivate) {
switch (m_type) { switch (m_type) {
case C25519: case C25519:
SHA384(h, m_pub, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv, ZT_C25519_COMBINED_PRIVATE_KEY_SIZE); SHA384(h, m_pub, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv, ZT_C25519_COMBINED_PRIVATE_KEY_SIZE);
return; return;
@ -199,17 +211,15 @@ void Identity::hashWithPrivate(uint8_t h[ZT_FINGERPRINT_HASH_SIZE]) const
case P384: case P384:
SHA384(h, m_pub, sizeof(m_pub), m_priv, sizeof(m_priv)); SHA384(h, m_pub, sizeof(m_pub), m_priv, sizeof(m_priv));
return; return;
} }
} }
Utils::zero< ZT_FINGERPRINT_HASH_SIZE >(h); Utils::zero<ZT_FINGERPRINT_HASH_SIZE>(h);
} }
unsigned int Identity::sign(const void *data, unsigned int len, void *sig, unsigned int siglen) const unsigned int Identity::sign(const void* data, unsigned int len, void* sig, unsigned int siglen) const
{ {
if (m_hasPrivate) { if (m_hasPrivate) {
switch (m_type) { switch (m_type) {
case C25519: case C25519:
if (siglen >= ZT_C25519_SIGNATURE_LEN) { if (siglen >= ZT_C25519_SIGNATURE_LEN) {
C25519::sign(m_priv, m_pub, data, len, sig); C25519::sign(m_priv, m_pub, data, len, sig);
@ -222,20 +232,18 @@ unsigned int Identity::sign(const void *data, unsigned int len, void *sig, unsig
static_assert(ZT_ECC384_SIGNATURE_HASH_SIZE == ZT_SHA384_DIGEST_SIZE, "weird!"); static_assert(ZT_ECC384_SIGNATURE_HASH_SIZE == ZT_SHA384_DIGEST_SIZE, "weird!");
uint8_t h[ZT_ECC384_SIGNATURE_HASH_SIZE]; uint8_t h[ZT_ECC384_SIGNATURE_HASH_SIZE];
SHA384(h, data, len, m_pub, ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE); SHA384(h, data, len, m_pub, ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
ECC384ECDSASign(m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE, h, (uint8_t *)sig); ECC384ECDSASign(m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE, h, (uint8_t*)sig);
return ZT_ECC384_SIGNATURE_SIZE; return ZT_ECC384_SIGNATURE_SIZE;
} }
break; break;
} }
} }
return 0; return 0;
} }
bool Identity::verify(const void *data, unsigned int len, const void *sig, unsigned int siglen) const bool Identity::verify(const void* data, unsigned int len, const void* sig, unsigned int siglen) const
{ {
switch (m_type) { switch (m_type) {
case C25519: case C25519:
return C25519::verify(m_pub, data, len, sig, siglen); return C25519::verify(m_pub, data, len, sig, siglen);
@ -243,15 +251,14 @@ bool Identity::verify(const void *data, unsigned int len, const void *sig, unsig
if (siglen == ZT_ECC384_SIGNATURE_SIZE) { if (siglen == ZT_ECC384_SIGNATURE_SIZE) {
uint8_t h[ZT_ECC384_SIGNATURE_HASH_SIZE]; uint8_t h[ZT_ECC384_SIGNATURE_HASH_SIZE];
SHA384(h, data, len, m_pub, ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE); SHA384(h, data, len, m_pub, ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
return ECC384ECDSAVerify(m_pub + 7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, h, (const uint8_t *)sig); return ECC384ECDSAVerify(m_pub + 7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, h, (const uint8_t*)sig);
} }
break; break;
} }
return false; return false;
} }
bool Identity::agree(const Identity &id, uint8_t key[ZT_SYMMETRIC_KEY_SIZE]) const bool Identity::agree(const Identity& id, uint8_t key[ZT_SYMMETRIC_KEY_SIZE]) const
{ {
uint8_t rawkey[128], h[64]; uint8_t rawkey[128], h[64];
if (m_hasPrivate) { if (m_hasPrivate) {
@ -260,16 +267,20 @@ bool Identity::agree(const Identity &id, uint8_t key[ZT_SYMMETRIC_KEY_SIZE]) con
// C25519 portion of a type 1 P-384 key. // C25519 portion of a type 1 P-384 key.
C25519::agree(m_priv, id.m_pub, rawkey); C25519::agree(m_priv, id.m_pub, rawkey);
SHA512(h, rawkey, ZT_C25519_ECDH_SHARED_SECRET_SIZE); SHA512(h, rawkey, ZT_C25519_ECDH_SHARED_SECRET_SIZE);
Utils::copy< ZT_SYMMETRIC_KEY_SIZE >(key, h); Utils::copy<ZT_SYMMETRIC_KEY_SIZE>(key, h);
return true; return true;
} else if ((m_type == P384) && (id.m_type == P384)) { }
else if ((m_type == P384) && (id.m_type == P384)) {
// For another P384 identity we execute DH agreement with BOTH keys and then // 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 // hash the results together. For those (cough FIPS cough) who only consider
// P384 to be kosher, the C25519 secret can be considered a "salt" // 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 // or something. For those who don't trust P384 this means the privacy of
// your traffic is also protected by C25519. // your traffic is also protected by C25519.
C25519::agree(m_priv, id.m_pub, rawkey); C25519::agree(m_priv, id.m_pub, rawkey);
ECC384ECDH(id.m_pub + 7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE, m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE, rawkey + ZT_C25519_ECDH_SHARED_SECRET_SIZE); ECC384ECDH(
id.m_pub + 7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE,
m_priv + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE,
rawkey + ZT_C25519_ECDH_SHARED_SECRET_SIZE);
SHA384(key, rawkey, ZT_C25519_ECDH_SHARED_SECRET_SIZE + ZT_ECC384_SHARED_SECRET_SIZE); SHA384(key, rawkey, ZT_C25519_ECDH_SHARED_SECRET_SIZE + ZT_ECC384_SHARED_SECRET_SIZE);
return true; return true;
} }
@ -277,9 +288,9 @@ bool Identity::agree(const Identity &id, uint8_t key[ZT_SYMMETRIC_KEY_SIZE]) con
return false; return false;
} }
char *Identity::toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const char* Identity::toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const
{ {
char *p = buf; char* p = buf;
Address(m_fp.address).toString(p); Address(m_fp.address).toString(p);
p += 10; p += 10;
*(p++) = ':'; *(p++) = ':';
@ -301,13 +312,20 @@ char *Identity::toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER
case P384: { case P384: {
*(p++) = '1'; *(p++) = '1';
*(p++) = ':'; *(p++) = ':';
int el = Utils::b32e(m_pub, sizeof(m_pub), p, (int)(ZT_IDENTITY_STRING_BUFFER_LENGTH - (uintptr_t)(p - buf))); int el =
if (el <= 0) return nullptr; Utils::b32e(m_pub, sizeof(m_pub), p, (int)(ZT_IDENTITY_STRING_BUFFER_LENGTH - (uintptr_t)(p - buf)));
if (el <= 0)
return nullptr;
p += el; p += el;
if ((m_hasPrivate) && (includePrivate)) { if ((m_hasPrivate) && (includePrivate)) {
*(p++) = ':'; *(p++) = ':';
el = Utils::b32e(m_priv, sizeof(m_priv), p, (int)(ZT_IDENTITY_STRING_BUFFER_LENGTH - (uintptr_t)(p - buf))); el = Utils::b32e(
if (el <= 0) return nullptr; m_priv,
sizeof(m_priv),
p,
(int)(ZT_IDENTITY_STRING_BUFFER_LENGTH - (uintptr_t)(p - buf)));
if (el <= 0)
return nullptr;
p += el; p += el;
} }
*p = (char)0; *p = (char)0;
@ -320,18 +338,17 @@ char *Identity::toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER
return nullptr; return nullptr;
} }
bool Identity::fromString(const char *str) bool Identity::fromString(const char* str)
{ {
char tmp[ZT_IDENTITY_STRING_BUFFER_LENGTH]; char tmp[ZT_IDENTITY_STRING_BUFFER_LENGTH];
memoryZero(this); memoryZero(this);
if ((!str) || (!Utils::scopy(tmp, sizeof(tmp), str))) if ((! str) || (! Utils::scopy(tmp, sizeof(tmp), str)))
return false; return false;
int fno = 0; int fno = 0;
char *saveptr = nullptr; char* saveptr = nullptr;
for (char *f = Utils::stok(tmp, ":", &saveptr); ((f) && (fno < 4)); f = Utils::stok(nullptr, ":", &saveptr)) { for (char* f = Utils::stok(tmp, ":", &saveptr); ((f) && (fno < 4)); f = Utils::stok(nullptr, ":", &saveptr)) {
switch (fno++) { switch (fno++) {
case 0: case 0:
m_fp.address = Utils::hexStrToU64(f) & ZT_ADDRESS_MASK; m_fp.address = Utils::hexStrToU64(f) & ZT_ADDRESS_MASK;
if (Address(m_fp.address).isReserved()) if (Address(m_fp.address).isReserved())
@ -339,20 +356,22 @@ bool Identity::fromString(const char *str)
break; break;
case 1: case 1:
if ((f[0] == '0') && (!f[1])) { if ((f[0] == '0') && (! f[1])) {
m_type = C25519; m_type = C25519;
} else if ((f[0] == '1') && (!f[1])) { }
else if ((f[0] == '1') && (! f[1])) {
m_type = P384; m_type = P384;
} else { }
else {
return false; return false;
} }
break; break;
case 2: case 2:
switch (m_type) { switch (m_type) {
case C25519: case C25519:
if (Utils::unhex(f, strlen(f), m_pub, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE) != ZT_C25519_COMBINED_PUBLIC_KEY_SIZE) if (Utils::unhex(f, strlen(f), m_pub, ZT_C25519_COMBINED_PUBLIC_KEY_SIZE)
!= ZT_C25519_COMBINED_PUBLIC_KEY_SIZE)
return false; return false;
break; break;
@ -360,18 +379,18 @@ bool Identity::fromString(const char *str)
if (Utils::b32d(f, m_pub, sizeof(m_pub)) != sizeof(m_pub)) if (Utils::b32d(f, m_pub, sizeof(m_pub)) != sizeof(m_pub))
return false; return false;
break; break;
} }
break; break;
case 3: case 3:
if (strlen(f) > 1) { if (strlen(f) > 1) {
switch (m_type) { switch (m_type) {
case C25519: case C25519:
if (Utils::unhex(f, strlen(f), m_priv, ZT_C25519_COMBINED_PRIVATE_KEY_SIZE) != ZT_C25519_COMBINED_PRIVATE_KEY_SIZE) { if (Utils::unhex(f, strlen(f), m_priv, ZT_C25519_COMBINED_PRIVATE_KEY_SIZE)
!= ZT_C25519_COMBINED_PRIVATE_KEY_SIZE) {
return false; return false;
} else { }
else {
m_hasPrivate = true; m_hasPrivate = true;
} }
break; break;
@ -379,15 +398,14 @@ bool Identity::fromString(const char *str)
case P384: case P384:
if (Utils::b32d(f, m_priv, sizeof(m_priv)) != sizeof(m_priv)) { if (Utils::b32d(f, m_priv, sizeof(m_priv)) != sizeof(m_priv)) {
return false; return false;
} else { }
else {
m_hasPrivate = true; m_hasPrivate = true;
} }
break; break;
} }
break; break;
} }
} }
} }
@ -395,41 +413,46 @@ bool Identity::fromString(const char *str)
return false; return false;
m_computeHash(); m_computeHash();
return !((m_type == P384) && (Address(m_fp.hash) != m_fp.address)); return ! ((m_type == P384) && (Address(m_fp.hash) != m_fp.address));
} }
int Identity::marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX], const bool includePrivate) const noexcept int Identity::marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX], const bool includePrivate) const noexcept
{ {
Address(m_fp.address).copyTo(data); Address(m_fp.address).copyTo(data);
switch (m_type) { switch (m_type) {
case C25519: case C25519:
data[ZT_ADDRESS_LENGTH] = (uint8_t)C25519; data[ZT_ADDRESS_LENGTH] = (uint8_t)C25519;
Utils::copy< ZT_C25519_COMBINED_PUBLIC_KEY_SIZE >(data + ZT_ADDRESS_LENGTH + 1, m_pub); Utils::copy<ZT_C25519_COMBINED_PUBLIC_KEY_SIZE>(data + ZT_ADDRESS_LENGTH + 1, m_pub);
if ((includePrivate) && (m_hasPrivate)) { if ((includePrivate) && (m_hasPrivate)) {
data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE] = ZT_C25519_COMBINED_PRIVATE_KEY_SIZE; 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, m_priv); Utils::copy<ZT_C25519_COMBINED_PRIVATE_KEY_SIZE>(
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1 + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE; data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1,
m_priv);
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1
+ ZT_C25519_COMBINED_PRIVATE_KEY_SIZE;
} }
data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE] = 0; data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE] = 0;
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1; return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1;
case P384: case P384:
data[ZT_ADDRESS_LENGTH] = (uint8_t)P384; data[ZT_ADDRESS_LENGTH] = (uint8_t)P384;
Utils::copy< ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE >(data + ZT_ADDRESS_LENGTH + 1, m_pub); Utils::copy<ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE>(data + ZT_ADDRESS_LENGTH + 1, m_pub);
if ((includePrivate) && (m_hasPrivate)) { if ((includePrivate) && (m_hasPrivate)) {
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE; data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] =
Utils::copy< ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE >(data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1, m_priv); ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + 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,
m_priv);
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1
+ ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
} }
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = 0; data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = 0;
return 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;
} }
return -1; return -1;
} }
int Identity::unmarshal(const uint8_t *data, const int len) noexcept int Identity::unmarshal(const uint8_t* data, const int len) noexcept
{ {
memoryZero(this); memoryZero(this);
@ -439,22 +462,27 @@ int Identity::unmarshal(const uint8_t *data, const int len) noexcept
unsigned int privlen; unsigned int privlen;
switch ((m_type = (Type)data[ZT_ADDRESS_LENGTH])) { switch ((m_type = (Type)data[ZT_ADDRESS_LENGTH])) {
case C25519: case C25519:
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1)) if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1))
return -1; return -1;
Utils::copy< ZT_C25519_COMBINED_PUBLIC_KEY_SIZE >(m_pub, data + ZT_ADDRESS_LENGTH + 1); Utils::copy<ZT_C25519_COMBINED_PUBLIC_KEY_SIZE>(m_pub, data + ZT_ADDRESS_LENGTH + 1);
m_computeHash(); m_computeHash();
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE]; privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE];
if (privlen == ZT_C25519_COMBINED_PRIVATE_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)) if (len
< (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1
+ ZT_C25519_COMBINED_PRIVATE_KEY_SIZE))
return -1; return -1;
m_hasPrivate = true; m_hasPrivate = true;
Utils::copy< ZT_C25519_COMBINED_PRIVATE_KEY_SIZE >(m_priv, data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1); Utils::copy<ZT_C25519_COMBINED_PRIVATE_KEY_SIZE>(
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1 + ZT_C25519_COMBINED_PRIVATE_KEY_SIZE; m_priv,
} else if (privlen == 0) { 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) {
m_hasPrivate = false; m_hasPrivate = false;
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1; return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + 1;
} }
@ -464,7 +492,7 @@ 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)) if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1))
return -1; return -1;
Utils::copy< ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE >(m_pub, data + ZT_ADDRESS_LENGTH + 1); Utils::copy<ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE>(m_pub, data + ZT_ADDRESS_LENGTH + 1);
m_computeHash(); // this sets the address for P384 m_computeHash(); // this sets the address for P384
if (Address(m_fp.hash) != m_fp.address) // this sanity check is possible with V1 identities if (Address(m_fp.hash) != m_fp.address) // this sanity check is possible with V1 identities
return -1; return -1;
@ -473,15 +501,20 @@ int Identity::unmarshal(const uint8_t *data, const int len) noexcept
if (privlen == 0) { if (privlen == 0) {
m_hasPrivate = false; m_hasPrivate = false;
return 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;
} else 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)) else 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; return -1;
m_hasPrivate = true; 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); Utils::copy<ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE>(
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + 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;
} }
break; break;
} }
return -1; return -1;

View file

@ -14,20 +14,21 @@
#ifndef ZT_IDENTITY_HPP #ifndef ZT_IDENTITY_HPP
#define ZT_IDENTITY_HPP #define ZT_IDENTITY_HPP
#include "Constants.hpp"
#include "Utils.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "C25519.hpp" #include "C25519.hpp"
#include "SHA512.hpp" #include "Constants.hpp"
#include "ECC384.hpp"
#include "TriviallyCopyable.hpp"
#include "Fingerprint.hpp"
#include "Containers.hpp" #include "Containers.hpp"
#include "ECC384.hpp"
#include "Fingerprint.hpp"
#include "SHA512.hpp"
#include "TriviallyCopyable.hpp"
#include "Utils.hpp"
#define ZT_IDENTITY_STRING_BUFFER_LENGTH 1024 #define ZT_IDENTITY_STRING_BUFFER_LENGTH 1024
#define ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE (7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + ZT_ECC384_PUBLIC_KEY_SIZE) #define ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE (7 + ZT_C25519_COMBINED_PUBLIC_KEY_SIZE + ZT_ECC384_PUBLIC_KEY_SIZE)
#define ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE (ZT_C25519_COMBINED_PRIVATE_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE) #define ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE (ZT_C25519_COMBINED_PRIVATE_KEY_SIZE + ZT_ECC384_PRIVATE_KEY_SIZE)
#define ZT_IDENTITY_MARSHAL_SIZE_MAX (ZT_ADDRESS_LENGTH + 4 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE) #define ZT_IDENTITY_MARSHAL_SIZE_MAX \
(ZT_ADDRESS_LENGTH + 4 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE)
#define ZT_IDENTITY_TYPE1_MIMC52_ROUNDS 262144 #define ZT_IDENTITY_TYPE1_MIMC52_ROUNDS 262144
namespace ZeroTier { namespace ZeroTier {
@ -44,14 +45,12 @@ namespace ZeroTier {
* Type 1 identities are better in many ways but type 0 will remain the default until * Type 1 identities are better in many ways but type 0 will remain the default until
* 1.x nodes are pretty much dead in the wild. * 1.x nodes are pretty much dead in the wild.
*/ */
class Identity : public TriviallyCopyable class Identity : public TriviallyCopyable {
{ public:
public:
/** /**
* Identity type -- numeric values of these enums are protocol constants * Identity type -- numeric values of these enums are protocol constants
*/ */
enum Type enum Type {
{
C25519 = ZT_IDENTITY_TYPE_C25519, // Type 0 -- Curve25519 and Ed25519 (1.x and 2.x, default) C25519 = ZT_IDENTITY_TYPE_C25519, // Type 0 -- Curve25519 and Ed25519 (1.x and 2.x, default)
P384 = ZT_IDENTITY_TYPE_P384 // Type 1 -- NIST P-384 with linked Curve25519/Ed25519 secondaries (2.x+) P384 = ZT_IDENTITY_TYPE_P384 // Type 1 -- NIST P-384 with linked Curve25519/Ed25519 secondaries (2.x+)
}; };
@ -62,10 +61,14 @@ public:
static const Identity NIL; static const Identity NIL;
ZT_INLINE Identity() noexcept ZT_INLINE Identity() noexcept
{ memoryZero(this); } {
memoryZero(this);
}
ZT_INLINE Identity(const Identity &id) noexcept ZT_INLINE Identity(const Identity& id) noexcept
{ Utils::copy< sizeof(Identity) >(this, &id); } {
Utils::copy<sizeof(Identity)>(this, &id);
}
/** /**
* Construct identity from string * Construct identity from string
@ -75,16 +78,20 @@ public:
* *
* @param str Identity in canonical string format * @param str Identity in canonical string format
*/ */
explicit ZT_INLINE Identity(const char *str) explicit ZT_INLINE Identity(const char* str)
{ fromString(str); } {
fromString(str);
}
ZT_INLINE ~Identity() ZT_INLINE ~Identity()
{ Utils::burn(reinterpret_cast<void *>(&this->m_priv), sizeof(this->m_priv)); } {
Utils::burn(reinterpret_cast<void*>(&this->m_priv), sizeof(this->m_priv));
}
ZT_INLINE Identity &operator=(const Identity &id) noexcept ZT_INLINE Identity& operator=(const Identity& id) noexcept
{ {
if (likely(this != &id)) if (likely(this != &id))
Utils::copy< sizeof(Identity) >(this, &id); Utils::copy<sizeof(Identity)>(this, &id);
return *this; return *this;
} }
@ -92,13 +99,17 @@ public:
* Set identity to NIL value (all zero) * Set identity to NIL value (all zero)
*/ */
ZT_INLINE void zero() noexcept ZT_INLINE void zero() noexcept
{ memoryZero(this); } {
memoryZero(this);
}
/** /**
* @return Identity type (undefined if identity is null or invalid) * @return Identity type (undefined if identity is null or invalid)
*/ */
ZT_INLINE Type type() const noexcept ZT_INLINE Type type() const noexcept
{ return m_type; } {
return m_type;
}
/** /**
* Generate a new identity (address, key pair) * Generate a new identity (address, key pair)
@ -125,19 +136,25 @@ public:
* @return True if this identity contains a private key * @return True if this identity contains a private key
*/ */
ZT_INLINE bool hasPrivate() const noexcept ZT_INLINE bool hasPrivate() const noexcept
{ return m_hasPrivate; } {
return m_hasPrivate;
}
/** /**
* @return This identity's address * @return This identity's address
*/ */
ZT_INLINE Address address() const noexcept ZT_INLINE Address address() const noexcept
{ return Address(m_fp.address); } {
return Address(m_fp.address);
}
/** /**
* @return Full fingerprint of this identity (address plus SHA384 of keys) * @return Full fingerprint of this identity (address plus SHA384 of keys)
*/ */
ZT_INLINE const Fingerprint &fingerprint() const noexcept ZT_INLINE const Fingerprint& fingerprint() const noexcept
{ return m_fp; } {
return m_fp;
}
/** /**
* Compute a hash of this identity's public and private keys. * Compute a hash of this identity's public and private keys.
@ -160,7 +177,7 @@ public:
* @param siglen Length of buffer * @param siglen Length of buffer
* @return Number of bytes actually written to sig or 0 on error * @return Number of bytes actually written to sig or 0 on error
*/ */
unsigned int sign(const void *data, unsigned int len, void *sig, unsigned int siglen) const; unsigned int sign(const void* data, unsigned int len, void* sig, unsigned int siglen) const;
/** /**
* Verify a message signature against this identity * Verify a message signature against this identity
@ -171,7 +188,7 @@ public:
* @param siglen Length of signature in bytes * @param siglen Length of signature in bytes
* @return True if signature validates and data integrity checks * @return True if signature validates and data integrity checks
*/ */
bool verify(const void *data, unsigned int len, const void *sig, unsigned int siglen) const; bool verify(const void* data, unsigned int len, const void* sig, unsigned int siglen) const;
/** /**
* Shortcut method to perform key agreement with another identity * Shortcut method to perform key agreement with another identity
@ -182,7 +199,7 @@ public:
* @param key Result parameter to fill with key bytes * @param key Result parameter to fill with key bytes
* @return Was agreement successful? * @return Was agreement successful?
*/ */
bool agree(const Identity &id, uint8_t key[ZT_SYMMETRIC_KEY_SIZE]) const; bool agree(const Identity& id, uint8_t key[ZT_SYMMETRIC_KEY_SIZE]) const;
/** /**
* Serialize to a more human-friendly string * Serialize to a more human-friendly string
@ -191,7 +208,7 @@ public:
* @param buf Buffer to store string * @param buf Buffer to store string
* @return ASCII string representation of identity (pointer to buf) * @return ASCII string representation of identity (pointer to buf)
*/ */
char *toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const; char* toString(bool includePrivate, char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const;
ZT_INLINE String toString(const bool includePrivate = false) const ZT_INLINE String toString(const bool includePrivate = false) const
{ {
@ -209,7 +226,7 @@ public:
* @param str String to deserialize * @param str String to deserialize
* @return True if deserialization appears successful * @return True if deserialization appears successful
*/ */
bool fromString(const char *str); bool fromString(const char* str);
/** /**
* Erase any private key in this identity object * Erase any private key in this identity object
@ -224,36 +241,54 @@ public:
* @return True if this identity contains something * @return True if this identity contains something
*/ */
explicit ZT_INLINE operator bool() const noexcept explicit ZT_INLINE operator bool() const noexcept
{ return (m_fp); } {
return (m_fp);
}
ZT_INLINE unsigned long hashCode() const noexcept ZT_INLINE unsigned long hashCode() const noexcept
{ return m_fp.hashCode(); } {
return m_fp.hashCode();
}
ZT_INLINE bool operator==(const Identity &id) const noexcept ZT_INLINE bool operator==(const Identity& id) const noexcept
{ return (m_fp == id.m_fp); } {
return (m_fp == id.m_fp);
}
ZT_INLINE bool operator!=(const Identity &id) const noexcept ZT_INLINE bool operator!=(const Identity& id) const noexcept
{ return !(*this == id); } {
return ! (*this == id);
}
ZT_INLINE bool operator<(const Identity &id) const noexcept ZT_INLINE bool operator<(const Identity& id) const noexcept
{ return (m_fp < id.m_fp); } {
return (m_fp < id.m_fp);
}
ZT_INLINE bool operator>(const Identity &id) const noexcept ZT_INLINE bool operator>(const Identity& id) const noexcept
{ return (id < *this); } {
return (id < *this);
}
ZT_INLINE bool operator<=(const Identity &id) const noexcept ZT_INLINE bool operator<=(const Identity& id) const noexcept
{ return !(id < *this); } {
return ! (id < *this);
}
ZT_INLINE bool operator>=(const Identity &id) const noexcept ZT_INLINE bool operator>=(const Identity& id) const noexcept
{ return !(*this < id); } {
return ! (*this < id);
}
static constexpr int marshalSizeMax() noexcept static constexpr int marshalSizeMax() noexcept
{ return ZT_IDENTITY_MARSHAL_SIZE_MAX; } {
return ZT_IDENTITY_MARSHAL_SIZE_MAX;
}
int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX], bool includePrivate = false) const noexcept; int marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX], bool includePrivate = false) const noexcept;
int unmarshal(const uint8_t *data, int len) noexcept; int unmarshal(const uint8_t* data, int len) noexcept;
private: private:
void m_computeHash(); void m_computeHash();
Fingerprint m_fp; Fingerprint m_fp;

View file

@ -13,24 +13,31 @@
#define _WIN32_WINNT 0x06010000 #define _WIN32_WINNT 0x06010000
#include "Constants.hpp"
#include "InetAddress.hpp" #include "InetAddress.hpp"
#include "Constants.hpp"
#include "Utils.hpp" #include "Utils.hpp"
namespace ZeroTier { namespace ZeroTier {
static_assert(ZT_SOCKADDR_STORAGE_SIZE == sizeof(sockaddr_storage), "ZT_SOCKADDR_STORAGE_SIZE is incorrect on this platform, must be size of sockaddr_storage"); static_assert(
static_assert(ZT_SOCKADDR_STORAGE_SIZE == sizeof(InetAddress), "ZT_SOCKADDR_STORAGE_SIZE should equal InetAddress, which should equal size of sockaddr_storage"); ZT_SOCKADDR_STORAGE_SIZE == sizeof(sockaddr_storage),
static_assert(ZT_SOCKADDR_STORAGE_SIZE == sizeof(ZT_InetAddress), "ZT_SOCKADDR_STORAGE_SIZE should equal ZT_InetAddress, which should equal size of sockaddr_storage"); "ZT_SOCKADDR_STORAGE_SIZE is incorrect on this platform, must be size of sockaddr_storage");
static_assert(
ZT_SOCKADDR_STORAGE_SIZE == sizeof(InetAddress),
"ZT_SOCKADDR_STORAGE_SIZE should equal InetAddress, which should equal size of sockaddr_storage");
static_assert(
ZT_SOCKADDR_STORAGE_SIZE == sizeof(ZT_InetAddress),
"ZT_SOCKADDR_STORAGE_SIZE should equal ZT_InetAddress, which should equal size of sockaddr_storage");
const InetAddress InetAddress::LO4((const void *) ("\x7f\x00\x00\x01"), 4, 0); const InetAddress InetAddress::LO4((const void*)("\x7f\x00\x00\x01"), 4, 0);
const InetAddress InetAddress::LO6((const void *) ("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"), 16, 0); const InetAddress
InetAddress::LO6((const void*)("\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"), 16, 0);
const InetAddress InetAddress::NIL; const InetAddress InetAddress::NIL;
InetAddress::IpScope InetAddress::ipScope() const noexcept InetAddress::IpScope InetAddress::ipScope() const noexcept
{ {
switch (as.ss.ss_family) { switch (as.ss.ss_family) {
case AF_INET: { case AF_INET: {
const uint32_t ip = Utils::ntoh((uint32_t)as.sa_in.sin_addr.s_addr); const uint32_t ip = Utils::ntoh((uint32_t)as.sa_in.sin_addr.s_addr);
switch (ip >> 24U) { switch (ip >> 24U) {
@ -40,38 +47,48 @@ InetAddress::IpScope InetAddress::ipScope() const noexcept
return ZT_IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army) return ZT_IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army)
case 0x0a: case 0x0a:
return ZT_IP_SCOPE_PRIVATE; // 10.0.0.0/8 return ZT_IP_SCOPE_PRIVATE; // 10.0.0.0/8
case 0x15: //return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN) case 0x15: // return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN)
case 0x16: //return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA) case 0x16: // return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA)
case 0x19: //return IP_SCOPE_PSEUDOPRIVATE; // 25.0.0.0/8 (UK Ministry of Defense) case 0x19: // return IP_SCOPE_PSEUDOPRIVATE; // 25.0.0.0/8 (UK Ministry of
case 0x1a: //return IP_SCOPE_PSEUDOPRIVATE; // 26.0.0.0/8 (US DISA) // Defense)
case 0x1c: //return IP_SCOPE_PSEUDOPRIVATE; // 28.0.0.0/8 (US DSI-North) case 0x1a: // return IP_SCOPE_PSEUDOPRIVATE; // 26.0.0.0/8 (US DISA)
case 0x1d: //return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA) case 0x1c: // return IP_SCOPE_PSEUDOPRIVATE; // 28.0.0.0/8 (US DSI-North)
case 0x1e: //return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA) case 0x1d: // return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA)
case 0x33: //return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of Social Security) case 0x1e: // return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA)
case 0x37: //return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD) case 0x33: // return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of
// Social Security)
case 0x37: // return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD)
case 0x38: // 56.0.0.0/8 (US Postal Service) case 0x38: // 56.0.0.0/8 (US Postal Service)
return ZT_IP_SCOPE_PSEUDOPRIVATE; return ZT_IP_SCOPE_PSEUDOPRIVATE;
case 0x64: case 0x64:
if ((ip & 0xffc00000) == 0x64400000) return ZT_IP_SCOPE_PRIVATE; // 100.64.0.0/10 if ((ip & 0xffc00000) == 0x64400000)
return ZT_IP_SCOPE_PRIVATE; // 100.64.0.0/10
break; break;
case 0x7f: case 0x7f:
return ZT_IP_SCOPE_LOOPBACK; // 127.0.0.0/8 return ZT_IP_SCOPE_LOOPBACK; // 127.0.0.0/8
case 0xa9: case 0xa9:
if ((ip & 0xffff0000) == 0xa9fe0000) return ZT_IP_SCOPE_LINK_LOCAL; // 169.254.0.0/16 if ((ip & 0xffff0000) == 0xa9fe0000)
return ZT_IP_SCOPE_LINK_LOCAL; // 169.254.0.0/16
break; break;
case 0xac: case 0xac:
if ((ip & 0xfff00000) == 0xac100000) return ZT_IP_SCOPE_PRIVATE; // 172.16.0.0/12 if ((ip & 0xfff00000) == 0xac100000)
return ZT_IP_SCOPE_PRIVATE; // 172.16.0.0/12
break; break;
case 0xc0: case 0xc0:
if ((ip & 0xffff0000) == 0xc0a80000) return ZT_IP_SCOPE_PRIVATE; // 192.168.0.0/16 if ((ip & 0xffff0000) == 0xc0a80000)
if ((ip & 0xffffff00) == 0xc0000200) return ZT_IP_SCOPE_PRIVATE; // 192.0.2.0/24 return ZT_IP_SCOPE_PRIVATE; // 192.168.0.0/16
if ((ip & 0xffffff00) == 0xc0000200)
return ZT_IP_SCOPE_PRIVATE; // 192.0.2.0/24
break; break;
case 0xc6: case 0xc6:
if ((ip & 0xfffe0000) == 0xc6120000) return ZT_IP_SCOPE_PRIVATE; // 198.18.0.0/15 if ((ip & 0xfffe0000) == 0xc6120000)
if ((ip & 0xffffff00) == 0xc6336400) return ZT_IP_SCOPE_PRIVATE; // 198.51.100.0/24 return ZT_IP_SCOPE_PRIVATE; // 198.18.0.0/15
if ((ip & 0xffffff00) == 0xc6336400)
return ZT_IP_SCOPE_PRIVATE; // 198.51.100.0/24
break; break;
case 0xcb: case 0xcb:
if ((ip & 0xffffff00) == 0xcb007100) return ZT_IP_SCOPE_PRIVATE; // 203.0.113.0/24 if ((ip & 0xffffff00) == 0xcb007100)
return ZT_IP_SCOPE_PRIVATE; // 203.0.113.0/24
break; break;
case 0xff: case 0xff:
return ZT_IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable) return ZT_IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable)
@ -86,41 +103,48 @@ InetAddress::IpScope InetAddress::ipScope() const noexcept
} }
case AF_INET6: { case AF_INET6: {
const uint8_t *const ip = as.sa_in6.sin6_addr.s6_addr; const uint8_t* const ip = as.sa_in6.sin6_addr.s6_addr;
if ((ip[0] & 0xf0U) == 0xf0) { if ((ip[0] & 0xf0U) == 0xf0) {
if (ip[0] == 0xff) return ZT_IP_SCOPE_MULTICAST; // ff00::/8 if (ip[0] == 0xff)
return ZT_IP_SCOPE_MULTICAST; // ff00::/8
if ((ip[0] == 0xfe) && ((ip[1] & 0xc0U) == 0x80)) { if ((ip[0] == 0xfe) && ((ip[1] & 0xc0U) == 0x80)) {
unsigned int k = 2; unsigned int k = 2;
while ((!ip[k]) && (k < 15)) ++k; while ((! ip[k]) && (k < 15))
++k;
if ((k == 15) && (ip[15] == 0x01)) if ((k == 15) && (ip[15] == 0x01))
return ZT_IP_SCOPE_LOOPBACK; // fe80::1/128 return ZT_IP_SCOPE_LOOPBACK; // fe80::1/128
else return ZT_IP_SCOPE_LINK_LOCAL; // fe80::/10 else
return ZT_IP_SCOPE_LINK_LOCAL; // fe80::/10
} }
if ((ip[0] & 0xfeU) == 0xfc) return ZT_IP_SCOPE_PRIVATE; // fc00::/7 if ((ip[0] & 0xfeU) == 0xfc)
return ZT_IP_SCOPE_PRIVATE; // fc00::/7
} }
unsigned int k = 0; unsigned int k = 0;
while ((!ip[k]) && (k < 15)) ++k; while ((! ip[k]) && (k < 15))
++k;
if (k == 15) { // all 0's except last byte if (k == 15) { // all 0's except last byte
if (ip[15] == 0x01) return ZT_IP_SCOPE_LOOPBACK; // ::1/128 if (ip[15] == 0x01)
if (ip[15] == 0x00) return ZT_IP_SCOPE_NONE; // ::/128 return ZT_IP_SCOPE_LOOPBACK; // ::1/128
if (ip[15] == 0x00)
return ZT_IP_SCOPE_NONE; // ::/128
} }
return ZT_IP_SCOPE_GLOBAL; return ZT_IP_SCOPE_GLOBAL;
} }
} }
return ZT_IP_SCOPE_NONE; return ZT_IP_SCOPE_NONE;
} }
void InetAddress::set(const void *ipBytes, unsigned int ipLen, unsigned int port) noexcept void InetAddress::set(const void* ipBytes, unsigned int ipLen, unsigned int port) noexcept
{ {
memoryZero(this); memoryZero(this);
if (ipLen == 4) { if (ipLen == 4) {
as.sa_in.sin_family = AF_INET; as.sa_in.sin_family = AF_INET;
as.sa_in.sin_port = Utils::hton((uint16_t) port); as.sa_in.sin_port = Utils::hton((uint16_t)port);
as.sa_in.sin_addr.s_addr = Utils::loadMachineEndian< uint32_t >(ipBytes); as.sa_in.sin_addr.s_addr = Utils::loadMachineEndian<uint32_t>(ipBytes);
} else if (ipLen == 16) { }
else if (ipLen == 16) {
as.sa_in6.sin6_family = AF_INET6; as.sa_in6.sin6_family = AF_INET6;
as.sa_in6.sin6_port = Utils::hton((uint16_t) port); as.sa_in6.sin6_port = Utils::hton((uint16_t)port);
Utils::copy<16>(as.sa_in6.sin6_addr.s6_addr, ipBytes); Utils::copy<16>(as.sa_in6.sin6_addr.s6_addr, ipBytes);
} }
} }
@ -132,7 +156,7 @@ bool InetAddress::isDefaultRoute() const noexcept
return ((as.sa_in.sin_port == 0) && (as.sa_in.sin_addr.s_addr == 0)); return ((as.sa_in.sin_port == 0) && (as.sa_in.sin_addr.s_addr == 0));
case AF_INET6: case AF_INET6:
if (as.sa_in6.sin6_port == 0) { if (as.sa_in6.sin6_port == 0) {
for (unsigned int i = 0;i < 16;++i) { for (unsigned int i = 0; i < 16; ++i) {
if (as.sa_in6.sin6_addr.s6_addr[i]) if (as.sa_in6.sin6_addr.s6_addr[i])
return false; return false;
} }
@ -144,20 +168,21 @@ bool InetAddress::isDefaultRoute() const noexcept
} }
} }
char *InetAddress::toString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noexcept char* InetAddress::toString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noexcept
{ {
char *p = toIpString(buf); char* p = toIpString(buf);
if (*p) { if (*p) {
while (*p) ++p; while (*p)
++p;
*(p++) = '/'; *(p++) = '/';
Utils::decimal(port(), p); Utils::decimal(port(), p);
} }
return buf; return buf;
} }
char *InetAddress::toIpString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noexcept char* InetAddress::toIpString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noexcept
{ {
buf[0] = (char) 0; buf[0] = (char)0;
switch (as.ss.ss_family) { switch (as.ss.ss_family) {
case AF_INET: case AF_INET:
inet_ntop(AF_INET, &as.sa_in.sin_addr.s_addr, buf, INET_ADDRSTRLEN); inet_ntop(AF_INET, &as.sa_in.sin_addr.s_addr, buf, INET_ADDRSTRLEN);
@ -169,34 +194,35 @@ char *InetAddress::toIpString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const no
return buf; return buf;
} }
bool InetAddress::fromString(const char *ipSlashPort) noexcept bool InetAddress::fromString(const char* ipSlashPort) noexcept
{ {
char buf[64]; char buf[64];
memoryZero(this); memoryZero(this);
if (!*ipSlashPort) if (! *ipSlashPort)
return true; return true;
if (!Utils::scopy(buf, sizeof(buf), ipSlashPort)) if (! Utils::scopy(buf, sizeof(buf), ipSlashPort))
return false; return false;
char *portAt = buf; char* portAt = buf;
while ((*portAt) && (*portAt != '/')) while ((*portAt) && (*portAt != '/'))
++portAt; ++portAt;
unsigned int port = 0; unsigned int port = 0;
if (*portAt) { if (*portAt) {
*(portAt++) = (char) 0; *(portAt++) = (char)0;
port = Utils::strToUInt(portAt) & 0xffffU; port = Utils::strToUInt(portAt) & 0xffffU;
} }
if (strchr(buf, ':')) { if (strchr(buf, ':')) {
as.sa_in6.sin6_family = AF_INET6; as.sa_in6.sin6_family = AF_INET6;
as.sa_in6.sin6_port = Utils::hton((uint16_t) port); as.sa_in6.sin6_port = Utils::hton((uint16_t)port);
inet_pton(AF_INET6, buf, as.sa_in6.sin6_addr.s6_addr); inet_pton(AF_INET6, buf, as.sa_in6.sin6_addr.s6_addr);
return true; return true;
} else if (strchr(buf, '.')) { }
else if (strchr(buf, '.')) {
as.sa_in.sin_family = AF_INET; as.sa_in.sin_family = AF_INET;
as.sa_in.sin_port = Utils::hton((uint16_t) port); as.sa_in.sin_port = Utils::hton((uint16_t)port);
inet_pton(AF_INET, buf, &as.sa_in.sin_addr.s_addr); inet_pton(AF_INET, buf, &as.sa_in.sin_addr.s_addr);
return true; return true;
} }
@ -209,21 +235,22 @@ InetAddress InetAddress::netmask() const noexcept
InetAddress r(*this); InetAddress r(*this);
switch (r.as.ss.ss_family) { switch (r.as.ss.ss_family) {
case AF_INET: case AF_INET:
r.as.sa_in.sin_addr.s_addr = Utils::hton((uint32_t) (0xffffffffU << (32 - netmaskBits()))); r.as.sa_in.sin_addr.s_addr = Utils::hton((uint32_t)(0xffffffffU << (32 - netmaskBits())));
break; break;
case AF_INET6: { case AF_INET6: {
uint64_t nm[2]; uint64_t nm[2];
const unsigned int bits = netmaskBits(); const unsigned int bits = netmaskBits();
if (bits) { if (bits) {
nm[0] = Utils::hton((uint64_t) ((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits)))); nm[0] = Utils::hton(
nm[1] = Utils::hton((uint64_t) ((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits)))); (uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits))));
} else { nm[1] = Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits))));
}
else {
nm[0] = 0; nm[0] = 0;
nm[1] = 0; nm[1] = 0;
} }
Utils::copy<16>(r.as.sa_in6.sin6_addr.s6_addr, nm); Utils::copy<16>(r.as.sa_in6.sin6_addr.s6_addr, nm);
} } break;
break;
} }
return r; return r;
} }
@ -232,7 +259,7 @@ InetAddress InetAddress::broadcast() const noexcept
{ {
if (as.ss.ss_family == AF_INET) { if (as.ss.ss_family == AF_INET) {
InetAddress r(*this); InetAddress r(*this);
reinterpret_cast<sockaddr_in *>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t) (0xffffffffU >> netmaskBits())); reinterpret_cast<sockaddr_in*>(&r)->sin_addr.s_addr |= Utils::hton((uint32_t)(0xffffffffU >> netmaskBits()));
return r; return r;
} }
return InetAddress(); return InetAddress();
@ -243,33 +270,33 @@ InetAddress InetAddress::network() const noexcept
InetAddress r(*this); InetAddress r(*this);
switch (r.as.ss.ss_family) { switch (r.as.ss.ss_family) {
case AF_INET: case AF_INET:
r.as.sa_in.sin_addr.s_addr &= Utils::hton((uint32_t) (0xffffffffU << (32 - netmaskBits()))); r.as.sa_in.sin_addr.s_addr &= Utils::hton((uint32_t)(0xffffffffU << (32 - netmaskBits())));
break; break;
case AF_INET6: { case AF_INET6: {
uint64_t nm[2]; uint64_t nm[2];
const unsigned int bits = netmaskBits(); const unsigned int bits = netmaskBits();
Utils::copy<16>(nm, reinterpret_cast<sockaddr_in6 *>(&r)->sin6_addr.s6_addr); Utils::copy<16>(nm, reinterpret_cast<sockaddr_in6*>(&r)->sin6_addr.s6_addr);
nm[0] &= Utils::hton((uint64_t) ((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits)))); nm[0] &=
nm[1] &= Utils::hton((uint64_t) ((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits)))); Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits))));
nm[1] &= Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits))));
Utils::copy<16>(r.as.sa_in6.sin6_addr.s6_addr, nm); Utils::copy<16>(r.as.sa_in6.sin6_addr.s6_addr, nm);
} } break;
break;
} }
return r; return r;
} }
bool InetAddress::isEqualPrefix(const InetAddress &addr) const noexcept bool InetAddress::isEqualPrefix(const InetAddress& addr) const noexcept
{ {
if (addr.as.ss.ss_family == as.ss.ss_family) { if (addr.as.ss.ss_family == as.ss.ss_family) {
switch (as.ss.ss_family) { switch (as.ss.ss_family) {
case AF_INET6: { case AF_INET6: {
const InetAddress mask(netmask()); const InetAddress mask(netmask());
InetAddress addr_mask(addr.netmask()); InetAddress addr_mask(addr.netmask());
const uint8_t *const n = addr_mask.as.sa_in6.sin6_addr.s6_addr; const uint8_t* const n = addr_mask.as.sa_in6.sin6_addr.s6_addr;
const uint8_t *const m = mask.as.sa_in6.sin6_addr.s6_addr; const uint8_t* const m = mask.as.sa_in6.sin6_addr.s6_addr;
const uint8_t *const a = addr.as.sa_in6.sin6_addr.s6_addr; const uint8_t* const a = addr.as.sa_in6.sin6_addr.s6_addr;
const uint8_t *const b = as.sa_in6.sin6_addr.s6_addr; const uint8_t* const b = as.sa_in6.sin6_addr.s6_addr;
for (unsigned int i = 0;i < 16;++i) { for (unsigned int i = 0; i < 16; ++i) {
if ((a[i] & m[i]) != (b[i] & n[i])) if ((a[i] & m[i]) != (b[i] & n[i]))
return false; return false;
} }
@ -280,7 +307,7 @@ bool InetAddress::isEqualPrefix(const InetAddress &addr) const noexcept
return false; return false;
} }
bool InetAddress::containsAddress(const InetAddress &addr) const noexcept bool InetAddress::containsAddress(const InetAddress& addr) const noexcept
{ {
if (addr.as.ss.ss_family == as.ss.ss_family) { if (addr.as.ss.ss_family == as.ss.ss_family) {
switch (as.ss.ss_family) { switch (as.ss.ss_family) {
@ -289,16 +316,15 @@ bool InetAddress::containsAddress(const InetAddress &addr) const noexcept
if (bits == 0) if (bits == 0)
return true; return true;
return ( return (
(Utils::ntoh((uint32_t) addr.as.sa_in.sin_addr.s_addr) >> (32 - bits)) == (Utils::ntoh((uint32_t)addr.as.sa_in.sin_addr.s_addr) >> (32 - bits))
(Utils::ntoh((uint32_t) as.sa_in.sin_addr.s_addr) >> (32 - bits)) == (Utils::ntoh((uint32_t)as.sa_in.sin_addr.s_addr) >> (32 - bits)));
);
} }
case AF_INET6: { case AF_INET6: {
const InetAddress mask(netmask()); const InetAddress mask(netmask());
const uint8_t *const m = mask.as.sa_in6.sin6_addr.s6_addr; const uint8_t* const m = mask.as.sa_in6.sin6_addr.s6_addr;
const uint8_t *const a = addr.as.sa_in6.sin6_addr.s6_addr; const uint8_t* const a = addr.as.sa_in6.sin6_addr.s6_addr;
const uint8_t *const b = as.sa_in6.sin6_addr.s6_addr; const uint8_t* const b = as.sa_in6.sin6_addr.s6_addr;
for (unsigned int i = 0;i < 16;++i) { for (unsigned int i = 0; i < 16; ++i) {
if ((a[i] & m[i]) != b[i]) if ((a[i] & m[i]) != b[i])
return false; return false;
} }
@ -318,7 +344,7 @@ bool InetAddress::isNetwork() const noexcept
return false; return false;
if (bits >= 32) if (bits >= 32)
return false; return false;
const uint32_t ip = Utils::ntoh((uint32_t) as.sa_in.sin_addr.s_addr); const uint32_t ip = Utils::ntoh((uint32_t)as.sa_in.sin_addr.s_addr);
return ((ip & (0xffffffffU >> bits)) == 0); return ((ip & (0xffffffffU >> bits)) == 0);
} }
case AF_INET6: { case AF_INET6: {
@ -327,7 +353,7 @@ bool InetAddress::isNetwork() const noexcept
return false; return false;
if (bits >= 128) if (bits >= 128)
return false; return false;
const uint8_t *const ip = as.sa_in6.sin6_addr.s6_addr; const uint8_t* const ip = as.sa_in6.sin6_addr.s6_addr;
unsigned int p = bits / 8; unsigned int p = bits / 8;
if ((ip[p++] & (0xffU >> (bits % 8))) != 0) if ((ip[p++] & (0xffU >> (bits % 8))) != 0)
return false; return false;
@ -346,21 +372,21 @@ int InetAddress::marshal(uint8_t data[ZT_INETADDRESS_MARSHAL_SIZE_MAX]) const no
unsigned int port; unsigned int port;
switch (as.ss.ss_family) { switch (as.ss.ss_family) {
case AF_INET: case AF_INET:
port = Utils::ntoh((uint16_t) reinterpret_cast<const sockaddr_in *>(this)->sin_port); port = Utils::ntoh((uint16_t) reinterpret_cast<const sockaddr_in*>(this)->sin_port);
data[0] = 4; data[0] = 4;
data[1] = reinterpret_cast<const uint8_t *>(&as.sa_in.sin_addr.s_addr)[0]; data[1] = reinterpret_cast<const uint8_t*>(&as.sa_in.sin_addr.s_addr)[0];
data[2] = reinterpret_cast<const uint8_t *>(&as.sa_in.sin_addr.s_addr)[1]; data[2] = reinterpret_cast<const uint8_t*>(&as.sa_in.sin_addr.s_addr)[1];
data[3] = reinterpret_cast<const uint8_t *>(&as.sa_in.sin_addr.s_addr)[2]; data[3] = reinterpret_cast<const uint8_t*>(&as.sa_in.sin_addr.s_addr)[2];
data[4] = reinterpret_cast<const uint8_t *>(&as.sa_in.sin_addr.s_addr)[3]; data[4] = reinterpret_cast<const uint8_t*>(&as.sa_in.sin_addr.s_addr)[3];
data[5] = (uint8_t) (port >> 8U); data[5] = (uint8_t)(port >> 8U);
data[6] = (uint8_t) port; data[6] = (uint8_t)port;
return 7; return 7;
case AF_INET6: case AF_INET6:
port = Utils::ntoh((uint16_t) as.sa_in6.sin6_port); port = Utils::ntoh((uint16_t)as.sa_in6.sin6_port);
data[0] = 6; data[0] = 6;
Utils::copy<16>(data + 1, as.sa_in6.sin6_addr.s6_addr); Utils::copy<16>(data + 1, as.sa_in6.sin6_addr.s6_addr);
data[17] = (uint8_t) (port >> 8U); data[17] = (uint8_t)(port >> 8U);
data[18] = (uint8_t) port; data[18] = (uint8_t)port;
return 19; return 19;
default: default:
data[0] = 0; data[0] = 0;
@ -368,7 +394,7 @@ int InetAddress::marshal(uint8_t data[ZT_INETADDRESS_MARSHAL_SIZE_MAX]) const no
} }
} }
int InetAddress::unmarshal(const uint8_t *restrict data, const int len) noexcept int InetAddress::unmarshal(const uint8_t* restrict data, const int len) noexcept
{ {
memoryZero(this); memoryZero(this);
if (unlikely(len <= 0)) if (unlikely(len <= 0))
@ -380,14 +406,14 @@ int InetAddress::unmarshal(const uint8_t *restrict data, const int len) noexcept
if (unlikely(len < 7)) if (unlikely(len < 7))
return -1; return -1;
as.sa_in.sin_family = AF_INET; as.sa_in.sin_family = AF_INET;
as.sa_in.sin_port = Utils::loadMachineEndian< uint16_t >(data + 5); as.sa_in.sin_port = Utils::loadMachineEndian<uint16_t>(data + 5);
as.sa_in.sin_addr.s_addr = Utils::loadMachineEndian< uint32_t >(data + 1); as.sa_in.sin_addr.s_addr = Utils::loadMachineEndian<uint32_t>(data + 1);
return 7; return 7;
case 6: case 6:
if (unlikely(len < 19)) if (unlikely(len < 19))
return -1; return -1;
as.sa_in6.sin6_family = AF_INET6; as.sa_in6.sin6_family = AF_INET6;
as.sa_in6.sin6_port = Utils::loadMachineEndian< uint16_t >(data + 17); as.sa_in6.sin6_port = Utils::loadMachineEndian<uint16_t>(data + 17);
Utils::copy<16>(as.sa_in6.sin6_addr.s6_addr, data + 1); Utils::copy<16>(as.sa_in6.sin6_addr.s6_addr, data + 1);
return 19; return 19;
default: default:
@ -395,7 +421,7 @@ int InetAddress::unmarshal(const uint8_t *restrict data, const int len) noexcept
} }
} }
InetAddress InetAddress::makeIpv6LinkLocal(const MAC &mac) noexcept InetAddress InetAddress::makeIpv6LinkLocal(const MAC& mac) noexcept
{ {
InetAddress r; InetAddress r;
r.as.sa_in6.sin6_family = AF_INET6; r.as.sa_in6.sin6_family = AF_INET6;
@ -423,23 +449,24 @@ InetAddress InetAddress::makeIpv6rfc4193(uint64_t nwid, uint64_t zeroTierAddress
{ {
InetAddress r; InetAddress r;
r.as.sa_in6.sin6_family = AF_INET6; r.as.sa_in6.sin6_family = AF_INET6;
r.as.sa_in6.sin6_port = ZT_CONST_TO_BE_UINT16(88); // /88 includes 0xfd + network ID, discriminating by device ID below that r.as.sa_in6.sin6_port =
ZT_CONST_TO_BE_UINT16(88); // /88 includes 0xfd + network ID, discriminating by device ID below that
r.as.sa_in6.sin6_addr.s6_addr[0] = 0xfd; r.as.sa_in6.sin6_addr.s6_addr[0] = 0xfd;
r.as.sa_in6.sin6_addr.s6_addr[1] = (uint8_t) (nwid >> 56U); r.as.sa_in6.sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 56U);
r.as.sa_in6.sin6_addr.s6_addr[2] = (uint8_t) (nwid >> 48U); r.as.sa_in6.sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 48U);
r.as.sa_in6.sin6_addr.s6_addr[3] = (uint8_t) (nwid >> 40U); r.as.sa_in6.sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 40U);
r.as.sa_in6.sin6_addr.s6_addr[4] = (uint8_t) (nwid >> 32U); r.as.sa_in6.sin6_addr.s6_addr[4] = (uint8_t)(nwid >> 32U);
r.as.sa_in6.sin6_addr.s6_addr[5] = (uint8_t) (nwid >> 24U); r.as.sa_in6.sin6_addr.s6_addr[5] = (uint8_t)(nwid >> 24U);
r.as.sa_in6.sin6_addr.s6_addr[6] = (uint8_t) (nwid >> 16U); r.as.sa_in6.sin6_addr.s6_addr[6] = (uint8_t)(nwid >> 16U);
r.as.sa_in6.sin6_addr.s6_addr[7] = (uint8_t) (nwid >> 8U); r.as.sa_in6.sin6_addr.s6_addr[7] = (uint8_t)(nwid >> 8U);
r.as.sa_in6.sin6_addr.s6_addr[8] = (uint8_t) nwid; r.as.sa_in6.sin6_addr.s6_addr[8] = (uint8_t)nwid;
r.as.sa_in6.sin6_addr.s6_addr[9] = 0x99; r.as.sa_in6.sin6_addr.s6_addr[9] = 0x99;
r.as.sa_in6.sin6_addr.s6_addr[10] = 0x93; r.as.sa_in6.sin6_addr.s6_addr[10] = 0x93;
r.as.sa_in6.sin6_addr.s6_addr[11] = (uint8_t) (zeroTierAddress >> 32U); r.as.sa_in6.sin6_addr.s6_addr[11] = (uint8_t)(zeroTierAddress >> 32U);
r.as.sa_in6.sin6_addr.s6_addr[12] = (uint8_t) (zeroTierAddress >> 24U); r.as.sa_in6.sin6_addr.s6_addr[12] = (uint8_t)(zeroTierAddress >> 24U);
r.as.sa_in6.sin6_addr.s6_addr[13] = (uint8_t) (zeroTierAddress >> 16U); r.as.sa_in6.sin6_addr.s6_addr[13] = (uint8_t)(zeroTierAddress >> 16U);
r.as.sa_in6.sin6_addr.s6_addr[14] = (uint8_t) (zeroTierAddress >> 8U); r.as.sa_in6.sin6_addr.s6_addr[14] = (uint8_t)(zeroTierAddress >> 8U);
r.as.sa_in6.sin6_addr.s6_addr[15] = (uint8_t) zeroTierAddress; r.as.sa_in6.sin6_addr.s6_addr[15] = (uint8_t)zeroTierAddress;
return r; return r;
} }
@ -450,15 +477,15 @@ InetAddress InetAddress::makeIpv66plane(uint64_t nwid, uint64_t zeroTierAddress)
r.as.sa_in6.sin6_family = AF_INET6; r.as.sa_in6.sin6_family = AF_INET6;
r.as.sa_in6.sin6_port = ZT_CONST_TO_BE_UINT16(40); r.as.sa_in6.sin6_port = ZT_CONST_TO_BE_UINT16(40);
r.as.sa_in6.sin6_addr.s6_addr[0] = 0xfc; r.as.sa_in6.sin6_addr.s6_addr[0] = 0xfc;
r.as.sa_in6.sin6_addr.s6_addr[1] = (uint8_t) (nwid >> 24U); r.as.sa_in6.sin6_addr.s6_addr[1] = (uint8_t)(nwid >> 24U);
r.as.sa_in6.sin6_addr.s6_addr[2] = (uint8_t) (nwid >> 16U); r.as.sa_in6.sin6_addr.s6_addr[2] = (uint8_t)(nwid >> 16U);
r.as.sa_in6.sin6_addr.s6_addr[3] = (uint8_t) (nwid >> 8U); r.as.sa_in6.sin6_addr.s6_addr[3] = (uint8_t)(nwid >> 8U);
r.as.sa_in6.sin6_addr.s6_addr[4] = (uint8_t) nwid; r.as.sa_in6.sin6_addr.s6_addr[4] = (uint8_t)nwid;
r.as.sa_in6.sin6_addr.s6_addr[5] = (uint8_t) (zeroTierAddress >> 32U); r.as.sa_in6.sin6_addr.s6_addr[5] = (uint8_t)(zeroTierAddress >> 32U);
r.as.sa_in6.sin6_addr.s6_addr[6] = (uint8_t) (zeroTierAddress >> 24U); r.as.sa_in6.sin6_addr.s6_addr[6] = (uint8_t)(zeroTierAddress >> 24U);
r.as.sa_in6.sin6_addr.s6_addr[7] = (uint8_t) (zeroTierAddress >> 16U); r.as.sa_in6.sin6_addr.s6_addr[7] = (uint8_t)(zeroTierAddress >> 16U);
r.as.sa_in6.sin6_addr.s6_addr[8] = (uint8_t) (zeroTierAddress >> 8U); r.as.sa_in6.sin6_addr.s6_addr[8] = (uint8_t)(zeroTierAddress >> 8U);
r.as.sa_in6.sin6_addr.s6_addr[9] = (uint8_t) zeroTierAddress; r.as.sa_in6.sin6_addr.s6_addr[9] = (uint8_t)zeroTierAddress;
r.as.sa_in6.sin6_addr.s6_addr[15] = 0x01; r.as.sa_in6.sin6_addr.s6_addr[15] = 0x01;
return r; return r;
} }

View file

@ -15,10 +15,10 @@
#define ZT_INETADDRESS_HPP #define ZT_INETADDRESS_HPP
#include "Constants.hpp" #include "Constants.hpp"
#include "Utils.hpp"
#include "MAC.hpp"
#include "Containers.hpp" #include "Containers.hpp"
#include "MAC.hpp"
#include "TriviallyCopyable.hpp" #include "TriviallyCopyable.hpp"
#include "Utils.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -33,9 +33,8 @@ namespace ZeroTier {
* sockaddr_storage and used interchangeably. DO NOT change this by e.g. * sockaddr_storage and used interchangeably. DO NOT change this by e.g.
* adding non-static fields, since much code depends on this identity. * adding non-static fields, since much code depends on this identity.
*/ */
struct InetAddress : public TriviallyCopyable struct InetAddress : public TriviallyCopyable {
{ public:
public:
/** /**
* Loopback IPv4 address (no port) * Loopback IPv4 address (no port)
*/ */
@ -61,63 +60,88 @@ public:
typedef ZT_InetAddress_IpScope IpScope; typedef ZT_InetAddress_IpScope IpScope;
ZT_INLINE InetAddress() noexcept ZT_INLINE InetAddress() noexcept
{ memoryZero(this); } {
memoryZero(this);
}
explicit ZT_INLINE InetAddress(const sockaddr_storage &ss) noexcept explicit ZT_INLINE InetAddress(const sockaddr_storage& ss) noexcept
{ *this = ss; } {
*this = ss;
}
explicit ZT_INLINE InetAddress(const sockaddr_storage *const ss) noexcept explicit ZT_INLINE InetAddress(const sockaddr_storage* const ss) noexcept
{ *this = ss; } {
*this = ss;
}
explicit ZT_INLINE InetAddress(const sockaddr &sa) noexcept explicit ZT_INLINE InetAddress(const sockaddr& sa) noexcept
{ *this = sa; } {
*this = sa;
}
explicit ZT_INLINE InetAddress(const sockaddr *const sa) noexcept explicit ZT_INLINE InetAddress(const sockaddr* const sa) noexcept
{ *this = sa; } {
*this = sa;
}
explicit ZT_INLINE InetAddress(const sockaddr_in &sa) noexcept explicit ZT_INLINE InetAddress(const sockaddr_in& sa) noexcept
{ *this = sa; } {
*this = sa;
}
explicit ZT_INLINE InetAddress(const sockaddr_in *const sa) noexcept explicit ZT_INLINE InetAddress(const sockaddr_in* const sa) noexcept
{ *this = sa; } {
*this = sa;
}
explicit ZT_INLINE InetAddress(const sockaddr_in6 &sa) noexcept explicit ZT_INLINE InetAddress(const sockaddr_in6& sa) noexcept
{ *this = sa; } {
*this = sa;
}
explicit ZT_INLINE InetAddress(const sockaddr_in6 *const sa) noexcept explicit ZT_INLINE InetAddress(const sockaddr_in6* const sa) noexcept
{ *this = sa; } {
*this = sa;
}
ZT_INLINE InetAddress(const void *const ipBytes, const unsigned int ipLen, const unsigned int port) noexcept ZT_INLINE InetAddress(const void* const ipBytes, const unsigned int ipLen, const unsigned int port) noexcept
{ this->set(ipBytes, ipLen, port); } {
this->set(ipBytes, ipLen, port);
}
ZT_INLINE InetAddress(const uint32_t ipv4, const unsigned int port) noexcept ZT_INLINE InetAddress(const uint32_t ipv4, const unsigned int port) noexcept
{ this->set(&ipv4, 4, port); } {
this->set(&ipv4, 4, port);
}
explicit ZT_INLINE InetAddress(const char *const ipSlashPort) noexcept explicit ZT_INLINE InetAddress(const char* const ipSlashPort) noexcept
{ this->fromString(ipSlashPort); } {
this->fromString(ipSlashPort);
}
ZT_INLINE InetAddress &operator=(const sockaddr_storage &ss) noexcept ZT_INLINE InetAddress& operator=(const sockaddr_storage& ss) noexcept
{ {
as.ss = ss; as.ss = ss;
return *this; return *this;
} }
ZT_INLINE InetAddress &operator=(const sockaddr_storage *ss) noexcept ZT_INLINE InetAddress& operator=(const sockaddr_storage* ss) noexcept
{ {
if (ss) if (ss)
as.ss = *ss; as.ss = *ss;
else memoryZero(this); else
memoryZero(this);
return *this; return *this;
} }
ZT_INLINE InetAddress &operator=(const sockaddr_in &sa) noexcept ZT_INLINE InetAddress& operator=(const sockaddr_in& sa) noexcept
{ {
memoryZero(this); memoryZero(this);
as.sa_in = sa; as.sa_in = sa;
return *this; return *this;
} }
ZT_INLINE InetAddress &operator=(const sockaddr_in *sa) noexcept ZT_INLINE InetAddress& operator=(const sockaddr_in* sa) noexcept
{ {
memoryZero(this); memoryZero(this);
if (sa) if (sa)
@ -125,14 +149,14 @@ public:
return *this; return *this;
} }
ZT_INLINE InetAddress &operator=(const sockaddr_in6 &sa) noexcept ZT_INLINE InetAddress& operator=(const sockaddr_in6& sa) noexcept
{ {
memoryZero(this); memoryZero(this);
as.sa_in6 = sa; as.sa_in6 = sa;
return *this; return *this;
} }
ZT_INLINE InetAddress &operator=(const sockaddr_in6 *sa) noexcept ZT_INLINE InetAddress& operator=(const sockaddr_in6* sa) noexcept
{ {
memoryZero(this); memoryZero(this);
if (sa) if (sa)
@ -140,30 +164,32 @@ public:
return *this; return *this;
} }
ZT_INLINE InetAddress &operator=(const sockaddr &sa) noexcept ZT_INLINE InetAddress& operator=(const sockaddr& sa) noexcept
{ {
memoryZero(this); memoryZero(this);
if (sa.sa_family == AF_INET) if (sa.sa_family == AF_INET)
as.sa_in = *reinterpret_cast<const sockaddr_in *>(&sa); as.sa_in = *reinterpret_cast<const sockaddr_in*>(&sa);
else if (sa.sa_family == AF_INET6) else if (sa.sa_family == AF_INET6)
as.sa_in6 = *reinterpret_cast<const sockaddr_in6 *>(&sa); as.sa_in6 = *reinterpret_cast<const sockaddr_in6*>(&sa);
return *this; return *this;
} }
ZT_INLINE InetAddress &operator=(const sockaddr *sa) noexcept ZT_INLINE InetAddress& operator=(const sockaddr* sa) noexcept
{ {
memoryZero(this); memoryZero(this);
if (sa) { if (sa) {
if (sa->sa_family == AF_INET) if (sa->sa_family == AF_INET)
as.sa_in = *reinterpret_cast<const sockaddr_in *>(sa); as.sa_in = *reinterpret_cast<const sockaddr_in*>(sa);
else if (sa->sa_family == AF_INET6) else if (sa->sa_family == AF_INET6)
as.sa_in6 = *reinterpret_cast<const sockaddr_in6 *>(sa); as.sa_in6 = *reinterpret_cast<const sockaddr_in6*>(sa);
} }
return *this; return *this;
} }
ZT_INLINE void clear() noexcept ZT_INLINE void clear() noexcept
{ memoryZero(this); } {
memoryZero(this);
}
/** /**
* @return IP scope classification (e.g. loopback, link-local, private, global) * @return IP scope classification (e.g. loopback, link-local, private, global)
@ -177,7 +203,7 @@ public:
* @param ipLen Length of IP address: 4 or 16 * @param ipLen Length of IP address: 4 or 16
* @param port Port number or 0 for none * @param port Port number or 0 for none
*/ */
void set(const void *ipBytes, unsigned int ipLen, unsigned int port) noexcept; void set(const void* ipBytes, unsigned int ipLen, unsigned int port) noexcept;
/** /**
* Set the port component * Set the port component
@ -204,7 +230,7 @@ public:
/** /**
* @return ASCII IP/port format representation * @return ASCII IP/port format representation
*/ */
char *toString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noexcept; char* toString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noexcept;
ZT_INLINE String toString() const ZT_INLINE String toString() const
{ {
@ -216,7 +242,7 @@ public:
/** /**
* @return IP portion only, in ASCII string format * @return IP portion only, in ASCII string format
*/ */
char *toIpString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noexcept; char* toIpString(char buf[ZT_INETADDRESS_STRING_SIZE_MAX]) const noexcept;
ZT_INLINE String toIpString() const ZT_INLINE String toIpString() const
{ {
@ -229,7 +255,7 @@ public:
* @param ipSlashPort IP/port (port is optional, will be 0 if not included) * @param ipSlashPort IP/port (port is optional, will be 0 if not included)
* @return True if address appeared to be valid * @return True if address appeared to be valid
*/ */
bool fromString(const char *ipSlashPort) noexcept; bool fromString(const char* ipSlashPort) noexcept;
/** /**
* @return Port or 0 if no port component defined * @return Port or 0 if no port component defined
@ -256,7 +282,9 @@ public:
* @return Netmask bits * @return Netmask bits
*/ */
ZT_INLINE unsigned int netmaskBits() const noexcept ZT_INLINE unsigned int netmaskBits() const noexcept
{ return port(); } {
return port();
}
/** /**
* @return True if netmask bits is valid for the address type * @return True if netmask bits is valid for the address type
@ -282,7 +310,9 @@ public:
* @return Gateway metric * @return Gateway metric
*/ */
ZT_INLINE unsigned int metric() const noexcept ZT_INLINE unsigned int metric() const noexcept
{ return port(); } {
return port();
}
/** /**
* Construct a full netmask as an InetAddress * Construct a full netmask as an InetAddress
@ -314,7 +344,7 @@ public:
* @param addr Address to check * @param addr Address to check
* @return True if this IPv6 prefix matches the prefix of a given IPv6 address * @return True if this IPv6 prefix matches the prefix of a given IPv6 address
*/ */
bool isEqualPrefix(const InetAddress &addr) const noexcept; bool isEqualPrefix(const InetAddress& addr) const noexcept;
/** /**
* Test whether this IP/netmask contains this address * Test whether this IP/netmask contains this address
@ -322,30 +352,34 @@ public:
* @param addr Address to check * @param addr Address to check
* @return True if this IP/netmask (route) contains this address * @return True if this IP/netmask (route) contains this address
*/ */
bool containsAddress(const InetAddress &addr) const noexcept; bool containsAddress(const InetAddress& addr) const noexcept;
/** /**
* @return True if this is an IPv4 address * @return True if this is an IPv4 address
*/ */
ZT_INLINE bool isV4() const noexcept ZT_INLINE bool isV4() const noexcept
{ return (as.ss.ss_family == AF_INET); } {
return (as.ss.ss_family == AF_INET);
}
/** /**
* @return True if this is an IPv6 address * @return True if this is an IPv6 address
*/ */
ZT_INLINE bool isV6() const noexcept ZT_INLINE bool isV6() const noexcept
{ return (as.ss.ss_family == AF_INET6); } {
return (as.ss.ss_family == AF_INET6);
}
/** /**
* @return pointer to raw address bytes or NULL if not available * @return pointer to raw address bytes or NULL if not available
*/ */
ZT_INLINE const void *rawIpData() const noexcept ZT_INLINE const void* rawIpData() const noexcept
{ {
switch (as.ss.ss_family) { switch (as.ss.ss_family) {
case AF_INET: case AF_INET:
return reinterpret_cast<const void *>(&(as.sa_in.sin_addr.s_addr)); return reinterpret_cast<const void*>(&(as.sa_in.sin_addr.s_addr));
case AF_INET6: case AF_INET6:
return reinterpret_cast<const void *>(as.sa_in6.sin6_addr.s6_addr); return reinterpret_cast<const void*>(as.sa_in6.sin6_addr.s6_addr);
default: default:
return nullptr; return nullptr;
} }
@ -364,7 +398,7 @@ public:
break; break;
case AF_INET6: case AF_INET6:
r.as.sa_in6.sin6_family = AF_INET6; r.as.sa_in6.sin6_family = AF_INET6;
Utils::copy< 16 >(r.as.sa_in6.sin6_addr.s6_addr, as.sa_in6.sin6_addr.s6_addr); Utils::copy<16>(r.as.sa_in6.sin6_addr.s6_addr, as.sa_in6.sin6_addr.s6_addr);
break; break;
} }
return r; return r;
@ -376,7 +410,7 @@ public:
* @param a InetAddress to compare again * @param a InetAddress to compare again
* @return True if only IP portions are equal (false for non-IP or null addresses) * @return True if only IP portions are equal (false for non-IP or null addresses)
*/ */
ZT_INLINE bool ipsEqual(const InetAddress &a) const noexcept ZT_INLINE bool ipsEqual(const InetAddress& a) const noexcept
{ {
const uint8_t f = as.ss.ss_family; const uint8_t f = as.ss.ss_family;
if (f == a.as.ss.ss_family) { if (f == a.as.ss.ss_family) {
@ -397,7 +431,7 @@ public:
* @param a InetAddress to compare again * @param a InetAddress to compare again
* @return True if only IP portions are equal (false for non-IP or null addresses) * @return True if only IP portions are equal (false for non-IP or null addresses)
*/ */
ZT_INLINE bool ipsEqual2(const InetAddress &a) const noexcept ZT_INLINE bool ipsEqual2(const InetAddress& a) const noexcept
{ {
const uint8_t f = as.ss.ss_family; const uint8_t f = as.ss.ss_family;
if (f == a.as.ss.ss_family) { if (f == a.as.ss.ss_family) {
@ -413,13 +447,14 @@ public:
ZT_INLINE unsigned long hashCode() const noexcept ZT_INLINE unsigned long hashCode() const noexcept
{ {
if (as.ss.ss_family == AF_INET) { if (as.ss.ss_family == AF_INET) {
return (unsigned long)Utils::hash32(((uint32_t)as.sa_in.sin_addr.s_addr + (uint32_t)as.sa_in.sin_port) ^ (uint32_t)Utils::s_mapNonce); return (unsigned long)Utils::hash32(
} else if (as.ss.ss_family == AF_INET6) { ((uint32_t)as.sa_in.sin_addr.s_addr + (uint32_t)as.sa_in.sin_port) ^ (uint32_t)Utils::s_mapNonce);
}
else if (as.ss.ss_family == AF_INET6) {
return (unsigned long)Utils::hash64( return (unsigned long)Utils::hash64(
(Utils::loadMachineEndian< uint64_t >(as.sa_in6.sin6_addr.s6_addr) + (Utils::loadMachineEndian<uint64_t>(as.sa_in6.sin6_addr.s6_addr)
Utils::loadMachineEndian< uint64_t >(as.sa_in6.sin6_addr.s6_addr + 8) + + Utils::loadMachineEndian<uint64_t>(as.sa_in6.sin6_addr.s6_addr + 8) + (uint64_t)as.sa_in6.sin6_port)
(uint64_t)as.sa_in6.sin6_port) ^ ^ Utils::s_mapNonce);
Utils::s_mapNonce);
} }
return Utils::fnv1a32(this, sizeof(InetAddress)); return Utils::fnv1a32(this, sizeof(InetAddress));
} }
@ -438,35 +473,44 @@ public:
* @return True if address family is non-zero * @return True if address family is non-zero
*/ */
explicit ZT_INLINE operator bool() const noexcept explicit ZT_INLINE operator bool() const noexcept
{ return (as.ss.ss_family != 0); } {
return (as.ss.ss_family != 0);
}
static constexpr int marshalSizeMax() noexcept static constexpr int marshalSizeMax() noexcept
{ return ZT_INETADDRESS_MARSHAL_SIZE_MAX; } {
return ZT_INETADDRESS_MARSHAL_SIZE_MAX;
}
int marshal(uint8_t data[ZT_INETADDRESS_MARSHAL_SIZE_MAX]) const noexcept; int marshal(uint8_t data[ZT_INETADDRESS_MARSHAL_SIZE_MAX]) const noexcept;
int unmarshal(const uint8_t *restrict data, int len) noexcept; int unmarshal(const uint8_t* restrict data, int len) noexcept;
ZT_INLINE bool operator==(const InetAddress &a) const noexcept ZT_INLINE bool operator==(const InetAddress& a) const noexcept
{ {
if (as.ss.ss_family == a.as.ss.ss_family) { if (as.ss.ss_family == a.as.ss.ss_family) {
if (as.ss.ss_family == AF_INET) if (as.ss.ss_family == AF_INET)
return ((as.sa_in.sin_port == a.as.sa_in.sin_port) && (as.sa_in.sin_addr.s_addr == a.as.sa_in.sin_addr.s_addr)); return (
(as.sa_in.sin_port == a.as.sa_in.sin_port)
&& (as.sa_in.sin_addr.s_addr == a.as.sa_in.sin_addr.s_addr));
if (as.ss.ss_family == AF_INET6) if (as.ss.ss_family == AF_INET6)
return ((as.sa_in6.sin6_port == a.as.sa_in6.sin6_port) && (memcmp(as.sa_in6.sin6_addr.s6_addr, a.as.sa_in6.sin6_addr.s6_addr, 16) == 0)); return (
(as.sa_in6.sin6_port == a.as.sa_in6.sin6_port)
&& (memcmp(as.sa_in6.sin6_addr.s6_addr, a.as.sa_in6.sin6_addr.s6_addr, 16) == 0));
return memcmp(this, &a, sizeof(InetAddress)) == 0; return memcmp(this, &a, sizeof(InetAddress)) == 0;
} }
return false; return false;
} }
ZT_INLINE bool operator<(const InetAddress &a) const noexcept ZT_INLINE bool operator<(const InetAddress& a) const noexcept
{ {
if (as.ss.ss_family == a.as.ss.ss_family) { if (as.ss.ss_family == a.as.ss.ss_family) {
if (as.ss.ss_family == AF_INET) { if (as.ss.ss_family == AF_INET) {
const uint16_t p0 = Utils::ntoh((uint16_t)as.sa_in.sin_port); const uint16_t p0 = Utils::ntoh((uint16_t)as.sa_in.sin_port);
const uint16_t p1 = Utils::ntoh((uint16_t)a.as.sa_in.sin_port); const uint16_t p1 = Utils::ntoh((uint16_t)a.as.sa_in.sin_port);
if (p0 == p1) if (p0 == p1)
return Utils::ntoh((uint32_t)as.sa_in.sin_addr.s_addr) < Utils::ntoh((uint32_t)a.as.sa_in.sin_addr.s_addr); return Utils::ntoh((uint32_t)as.sa_in.sin_addr.s_addr)
< Utils::ntoh((uint32_t)a.as.sa_in.sin_addr.s_addr);
return p0 < p1; return p0 < p1;
} }
if (as.ss.ss_family == AF_INET6) { if (as.ss.ss_family == AF_INET6) {
@ -481,17 +525,25 @@ public:
return as.ss.ss_family < a.as.ss.ss_family; return as.ss.ss_family < a.as.ss.ss_family;
} }
ZT_INLINE bool operator!=(const InetAddress &a) const noexcept ZT_INLINE bool operator!=(const InetAddress& a) const noexcept
{ return !(*this == a); } {
return ! (*this == a);
}
ZT_INLINE bool operator>(const InetAddress &a) const noexcept ZT_INLINE bool operator>(const InetAddress& a) const noexcept
{ return (a < *this); } {
return (a < *this);
}
ZT_INLINE bool operator<=(const InetAddress &a) const noexcept ZT_INLINE bool operator<=(const InetAddress& a) const noexcept
{ return !(a < *this); } {
return ! (a < *this);
}
ZT_INLINE bool operator>=(const InetAddress &a) const noexcept ZT_INLINE bool operator>=(const InetAddress& a) const noexcept
{ return !(*this < a); } {
return ! (*this < a);
}
/** /**
* Compute an IPv6 link-local address * Compute an IPv6 link-local address
@ -499,7 +551,7 @@ public:
* @param mac MAC address seed * @param mac MAC address seed
* @return IPv6 link-local address * @return IPv6 link-local address
*/ */
static InetAddress makeIpv6LinkLocal(const MAC &mac) noexcept; static InetAddress makeIpv6LinkLocal(const MAC& mac) noexcept;
/** /**
* Compute private IPv6 unicast address from network ID and ZeroTier address * Compute private IPv6 unicast address from network ID and ZeroTier address
@ -552,8 +604,7 @@ public:
/** /**
* Union allowing this to be accessed as a sockaddr of any supported type. * Union allowing this to be accessed as a sockaddr of any supported type.
*/ */
union union {
{
sockaddr_storage ss; sockaddr_storage ss;
sockaddr sa; sockaddr sa;
sockaddr_in sa_in; sockaddr_in sa_in;
@ -561,65 +612,105 @@ public:
} as; } as;
}; };
static ZT_INLINE InetAddress *asInetAddress(sockaddr_in *const p) noexcept static ZT_INLINE InetAddress* asInetAddress(sockaddr_in* const p) noexcept
{ return reinterpret_cast<InetAddress *>(p); } {
return reinterpret_cast<InetAddress*>(p);
}
static ZT_INLINE InetAddress *asInetAddress(sockaddr_in6 *const p) noexcept static ZT_INLINE InetAddress* asInetAddress(sockaddr_in6* const p) noexcept
{ return reinterpret_cast<InetAddress *>(p); } {
return reinterpret_cast<InetAddress*>(p);
}
static ZT_INLINE InetAddress *asInetAddress(sockaddr *const p) noexcept static ZT_INLINE InetAddress* asInetAddress(sockaddr* const p) noexcept
{ return reinterpret_cast<InetAddress *>(p); } {
return reinterpret_cast<InetAddress*>(p);
}
static ZT_INLINE InetAddress *asInetAddress(sockaddr_storage *const p) noexcept static ZT_INLINE InetAddress* asInetAddress(sockaddr_storage* const p) noexcept
{ return reinterpret_cast<InetAddress *>(p); } {
return reinterpret_cast<InetAddress*>(p);
}
static ZT_INLINE InetAddress *asInetAddress(ZT_InetAddress *const p) noexcept static ZT_INLINE InetAddress* asInetAddress(ZT_InetAddress* const p) noexcept
{ return reinterpret_cast<InetAddress *>(p); } {
return reinterpret_cast<InetAddress*>(p);
}
static ZT_INLINE const InetAddress *asInetAddress(const sockaddr_in *const p) noexcept static ZT_INLINE const InetAddress* asInetAddress(const sockaddr_in* const p) noexcept
{ return reinterpret_cast<const InetAddress *>(p); } {
return reinterpret_cast<const InetAddress*>(p);
}
static ZT_INLINE const InetAddress *asInetAddress(const sockaddr_in6 *const p) noexcept static ZT_INLINE const InetAddress* asInetAddress(const sockaddr_in6* const p) noexcept
{ return reinterpret_cast<const InetAddress *>(p); } {
return reinterpret_cast<const InetAddress*>(p);
}
static ZT_INLINE const InetAddress *asInetAddress(const sockaddr *const p) noexcept static ZT_INLINE const InetAddress* asInetAddress(const sockaddr* const p) noexcept
{ return reinterpret_cast<const InetAddress *>(p); } {
return reinterpret_cast<const InetAddress*>(p);
}
static ZT_INLINE const InetAddress *asInetAddress(const sockaddr_storage *const p) noexcept static ZT_INLINE const InetAddress* asInetAddress(const sockaddr_storage* const p) noexcept
{ return reinterpret_cast<const InetAddress *>(p); } {
return reinterpret_cast<const InetAddress*>(p);
}
static ZT_INLINE const InetAddress *asInetAddress(const ZT_InetAddress *const p) noexcept static ZT_INLINE const InetAddress* asInetAddress(const ZT_InetAddress* const p) noexcept
{ return reinterpret_cast<const InetAddress *>(p); } {
return reinterpret_cast<const InetAddress*>(p);
}
static ZT_INLINE InetAddress &asInetAddress(sockaddr_in &p) noexcept static ZT_INLINE InetAddress& asInetAddress(sockaddr_in& p) noexcept
{ return *reinterpret_cast<InetAddress *>(&p); } {
return *reinterpret_cast<InetAddress*>(&p);
}
static ZT_INLINE InetAddress &asInetAddress(sockaddr_in6 &p) noexcept static ZT_INLINE InetAddress& asInetAddress(sockaddr_in6& p) noexcept
{ return *reinterpret_cast<InetAddress *>(&p); } {
return *reinterpret_cast<InetAddress*>(&p);
}
static ZT_INLINE InetAddress &asInetAddress(sockaddr &p) noexcept static ZT_INLINE InetAddress& asInetAddress(sockaddr& p) noexcept
{ return *reinterpret_cast<InetAddress *>(&p); } {
return *reinterpret_cast<InetAddress*>(&p);
}
static ZT_INLINE InetAddress &asInetAddress(sockaddr_storage &p) noexcept static ZT_INLINE InetAddress& asInetAddress(sockaddr_storage& p) noexcept
{ return *reinterpret_cast<InetAddress *>(&p); } {
return *reinterpret_cast<InetAddress*>(&p);
}
static ZT_INLINE InetAddress &asInetAddress(ZT_InetAddress &p) noexcept static ZT_INLINE InetAddress& asInetAddress(ZT_InetAddress& p) noexcept
{ return *reinterpret_cast<InetAddress *>(&p); } {
return *reinterpret_cast<InetAddress*>(&p);
}
static ZT_INLINE const InetAddress &asInetAddress(const sockaddr_in &p) noexcept static ZT_INLINE const InetAddress& asInetAddress(const sockaddr_in& p) noexcept
{ return *reinterpret_cast<const InetAddress *>(&p); } {
return *reinterpret_cast<const InetAddress*>(&p);
}
static ZT_INLINE const InetAddress &asInetAddress(const sockaddr_in6 &p) noexcept static ZT_INLINE const InetAddress& asInetAddress(const sockaddr_in6& p) noexcept
{ return *reinterpret_cast<const InetAddress *>(&p); } {
return *reinterpret_cast<const InetAddress*>(&p);
}
static ZT_INLINE const InetAddress &asInetAddress(const sockaddr &p) noexcept static ZT_INLINE const InetAddress& asInetAddress(const sockaddr& p) noexcept
{ return *reinterpret_cast<const InetAddress *>(&p); } {
return *reinterpret_cast<const InetAddress*>(&p);
}
static ZT_INLINE const InetAddress &asInetAddress(const sockaddr_storage &p) noexcept static ZT_INLINE const InetAddress& asInetAddress(const sockaddr_storage& p) noexcept
{ return *reinterpret_cast<const InetAddress *>(&p); } {
return *reinterpret_cast<const InetAddress*>(&p);
}
static ZT_INLINE const InetAddress &asInetAddress(const ZT_InetAddress &p) noexcept static ZT_INLINE const InetAddress& asInetAddress(const ZT_InetAddress& p) noexcept
{ return *reinterpret_cast<const InetAddress *>(&p); } {
return *reinterpret_cast<const InetAddress*>(&p);
}
} // namespace ZeroTier } // namespace ZeroTier

File diff suppressed because it is too large Load diff

View file

@ -19,10 +19,10 @@
namespace ZeroTier { namespace ZeroTier {
#define LZ4_MAX_INPUT_SIZE 0x7E000000 #define LZ4_MAX_INPUT_SIZE 0x7E000000
#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) #define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize) / 255) + 16)
int LZ4_compress_fast(const char *source,char *dest,int inputSize,int maxOutputSize,int acceleration = 1) noexcept; int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration = 1) noexcept;
int LZ4_decompress_safe(const char *source,char *dest,int compressedSize,int maxDecompressedSize) noexcept; int LZ4_decompress_safe(const char* source, char* dest, int compressedSize, int maxDecompressedSize) noexcept;
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -12,18 +12,19 @@
/****/ /****/
#include "Locator.hpp" #include "Locator.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include <algorithm> #include <algorithm>
namespace ZeroTier { namespace ZeroTier {
const SharedPtr< const Locator::EndpointAttributes > Locator::EndpointAttributes::DEFAULT(new Locator::EndpointAttributes()); const SharedPtr<const Locator::EndpointAttributes>
Locator::EndpointAttributes::DEFAULT(new Locator::EndpointAttributes());
Locator::Locator(const char *const str) noexcept : Locator::Locator(const char* const str) noexcept : __refCount(0)
__refCount(0)
{ {
if (!fromString(str)) { if (! fromString(str)) {
m_revision = 0; m_revision = 0;
m_signer.zero(); m_signer.zero();
m_endpoints.clear(); m_endpoints.clear();
@ -31,22 +32,26 @@ Locator::Locator(const char *const str) noexcept :
} }
} }
bool Locator::add(const Endpoint &ep, const SharedPtr< const EndpointAttributes > &a) bool Locator::add(const Endpoint& ep, const SharedPtr<const EndpointAttributes>& a)
{ {
for (Vector< std::pair< Endpoint, SharedPtr< const EndpointAttributes > > >::iterator i(m_endpoints.begin());i!=m_endpoints.end();++i) { for (Vector<std::pair<Endpoint, SharedPtr<const EndpointAttributes> > >::iterator i(m_endpoints.begin());
i != m_endpoints.end();
++i) {
if (i->first == ep) { if (i->first == ep) {
i->second = ((a) && (a->data[0] != 0)) ? a : EndpointAttributes::DEFAULT; i->second = ((a) && (a->data[0] != 0)) ? a : EndpointAttributes::DEFAULT;
return true; return true;
} }
} }
if (m_endpoints.size() < ZT_LOCATOR_MAX_ENDPOINTS) { if (m_endpoints.size() < ZT_LOCATOR_MAX_ENDPOINTS) {
m_endpoints.push_back(std::pair<Endpoint, SharedPtr< const EndpointAttributes > >(ep, ((a) && (a->data[0] != 0)) ? a : EndpointAttributes::DEFAULT)); m_endpoints.push_back(std::pair<Endpoint, SharedPtr<const EndpointAttributes> >(
ep,
((a) && (a->data[0] != 0)) ? a : EndpointAttributes::DEFAULT));
return true; return true;
} }
return false; return false;
} }
bool Locator::sign(const int64_t rev, const Identity &id) noexcept bool Locator::sign(const int64_t rev, const Identity& id) noexcept
{ {
m_revision = rev; m_revision = rev;
m_signer = id.address(); m_signer = id.address();
@ -64,7 +69,7 @@ bool Locator::sign(const int64_t rev, const Identity &id) noexcept
return true; return true;
} }
bool Locator::verify(const Identity &id) const noexcept bool Locator::verify(const Identity& id) const noexcept
{ {
try { try {
if ((m_revision > 0) && (m_signer == id.address())) { if ((m_revision > 0) && (m_signer == id.address())) {
@ -72,23 +77,31 @@ bool Locator::verify(const Identity &id) const noexcept
const unsigned int signlen = marshal(signdata, true); const unsigned int signlen = marshal(signdata, true);
return id.verify(signdata, signlen, m_signature.data(), m_signature.size()); return id.verify(signdata, signlen, m_signature.data(), m_signature.size());
} }
} catch (...) {} // fail verify on any unexpected exception }
catch (...) {
} // fail verify on any unexpected exception
return false; return false;
} }
char *Locator::toString(char s[ZT_LOCATOR_STRING_SIZE_MAX]) const noexcept char* Locator::toString(char s[ZT_LOCATOR_STRING_SIZE_MAX]) const noexcept
{ {
static_assert(ZT_LOCATOR_STRING_SIZE_MAX > ((((ZT_LOCATOR_MARSHAL_SIZE_MAX / 5) + 1) * 8) + ZT_ADDRESS_LENGTH_HEX + 1), "overflow"); static_assert(
ZT_LOCATOR_STRING_SIZE_MAX > ((((ZT_LOCATOR_MARSHAL_SIZE_MAX / 5) + 1) * 8) + ZT_ADDRESS_LENGTH_HEX + 1),
"overflow");
uint8_t bin[ZT_LOCATOR_MARSHAL_SIZE_MAX]; uint8_t bin[ZT_LOCATOR_MARSHAL_SIZE_MAX];
m_signer.toString(s); m_signer.toString(s);
s[ZT_ADDRESS_LENGTH_HEX] = '@'; s[ZT_ADDRESS_LENGTH_HEX] = '@';
Utils::b32e(bin, marshal(bin, false), s + (ZT_ADDRESS_LENGTH_HEX + 1), ZT_LOCATOR_STRING_SIZE_MAX - (ZT_ADDRESS_LENGTH_HEX + 1)); Utils::b32e(
bin,
marshal(bin, false),
s + (ZT_ADDRESS_LENGTH_HEX + 1),
ZT_LOCATOR_STRING_SIZE_MAX - (ZT_ADDRESS_LENGTH_HEX + 1));
return s; return s;
} }
bool Locator::fromString(const char *s) noexcept bool Locator::fromString(const char* s) noexcept
{ {
if (!s) if (! s)
return false; return false;
if (strlen(s) < (ZT_ADDRESS_LENGTH_HEX + 1)) if (strlen(s) < (ZT_ADDRESS_LENGTH_HEX + 1))
return false; return false;
@ -101,13 +114,15 @@ bool Locator::fromString(const char *s) noexcept
int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX], const bool excludeSignature) const noexcept int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX], const bool excludeSignature) const noexcept
{ {
Utils::storeBigEndian<uint64_t>(data, (uint64_t) m_revision); Utils::storeBigEndian<uint64_t>(data, (uint64_t)m_revision);
m_signer.copyTo(data + 8); m_signer.copyTo(data + 8);
int p = 8 + ZT_ADDRESS_LENGTH; int p = 8 + ZT_ADDRESS_LENGTH;
Utils::storeBigEndian<uint16_t>(data + p, (uint16_t)m_endpoints.size()); Utils::storeBigEndian<uint16_t>(data + p, (uint16_t)m_endpoints.size());
p += 2; p += 2;
for (Vector< std::pair< Endpoint, SharedPtr< const EndpointAttributes > > >::const_iterator e(m_endpoints.begin());e != m_endpoints.end();++e) { for (Vector<std::pair<Endpoint, SharedPtr<const EndpointAttributes> > >::const_iterator e(m_endpoints.begin());
e != m_endpoints.end();
++e) {
int l = e->first.marshal(data + p); int l = e->first.marshal(data + p);
if (l <= 0) if (l <= 0)
return -1; return -1;
@ -117,25 +132,26 @@ int Locator::marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX], const bool exclu
if (l > 0) { if (l > 0) {
Utils::copy(data + p, e->second->data, (unsigned int)l); Utils::copy(data + p, e->second->data, (unsigned int)l);
p += l; p += l;
} else { }
else {
data[p++] = 0; data[p++] = 0;
} }
} }
Utils::storeMachineEndian< uint16_t >(data + p, 0); // length of meta-data, currently always 0 Utils::storeMachineEndian<uint16_t>(data + p, 0); // length of meta-data, currently always 0
p += 2; p += 2;
if (!excludeSignature) { if (! excludeSignature) {
Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_signature.size()); Utils::storeBigEndian<uint16_t>(data + p, (uint16_t)m_signature.size());
p += 2; p += 2;
Utils::copy(data + p, m_signature.data(), m_signature.size()); Utils::copy(data + p, m_signature.data(), m_signature.size());
p += (int) m_signature.size(); p += (int)m_signature.size();
} }
return p; return p;
} }
int Locator::unmarshal(const uint8_t *data, const int len) noexcept int Locator::unmarshal(const uint8_t* data, const int len) noexcept
{ {
if (unlikely(len < (8 + ZT_ADDRESS_LENGTH))) if (unlikely(len < (8 + ZT_ADDRESS_LENGTH)))
return -1; return -1;
@ -151,7 +167,7 @@ int Locator::unmarshal(const uint8_t *data, const int len) noexcept
return -1; return -1;
m_endpoints.resize(endpointCount); m_endpoints.resize(endpointCount);
m_endpoints.shrink_to_fit(); m_endpoints.shrink_to_fit();
for (unsigned int i = 0;i < endpointCount;++i) { for (unsigned int i = 0; i < endpointCount; ++i) {
int l = m_endpoints[i].first.unmarshal(data + p, len - p); int l = m_endpoints[i].first.unmarshal(data + p, len - p);
if (l <= 0) if (l <= 0)
return -1; return -1;
@ -163,9 +179,10 @@ int Locator::unmarshal(const uint8_t *data, const int len) noexcept
if (l <= 0) { if (l <= 0) {
m_endpoints[i].second = EndpointAttributes::DEFAULT; m_endpoints[i].second = EndpointAttributes::DEFAULT;
++p; ++p;
} else { }
else {
m_endpoints[i].second.set(new EndpointAttributes()); m_endpoints[i].second.set(new EndpointAttributes());
Utils::copy(const_cast< uint8_t * >(m_endpoints[i].second->data), data + p, (unsigned int)l); Utils::copy(const_cast<uint8_t*>(m_endpoints[i].second->data), data + p, (unsigned int)l);
p += l; p += l;
} }
} }
@ -191,15 +208,20 @@ int Locator::unmarshal(const uint8_t *data, const int len) noexcept
return p; return p;
} }
struct p_SortByEndpoint struct p_SortByEndpoint {
{
// There can't be more than one of the same endpoint, so only need to sort // There can't be more than one of the same endpoint, so only need to sort
// by endpoint. // by endpoint.
ZT_INLINE bool operator()(const std::pair< Endpoint, SharedPtr< const Locator::EndpointAttributes > > &a,const std::pair< Endpoint, SharedPtr< const Locator::EndpointAttributes > > &b) const noexcept ZT_INLINE bool operator()(
{ return a.first < b.first; } const std::pair<Endpoint, SharedPtr<const Locator::EndpointAttributes> >& a,
const std::pair<Endpoint, SharedPtr<const Locator::EndpointAttributes> >& b) const noexcept
{
return a.first < b.first;
}
}; };
void Locator::m_sortEndpoints() noexcept void Locator::m_sortEndpoints() noexcept
{ std::sort(m_endpoints.begin(), m_endpoints.end(), p_SortByEndpoint()); } {
std::sort(m_endpoints.begin(), m_endpoints.end(), p_SortByEndpoint());
}
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -15,13 +15,13 @@
#define ZT_LOCATOR_HPP #define ZT_LOCATOR_HPP
#include "Constants.hpp" #include "Constants.hpp"
#include "Endpoint.hpp"
#include "Identity.hpp"
#include "TriviallyCopyable.hpp"
#include "SharedPtr.hpp"
#include "FCV.hpp"
#include "Containers.hpp" #include "Containers.hpp"
#include "Dictionary.hpp" #include "Dictionary.hpp"
#include "Endpoint.hpp"
#include "FCV.hpp"
#include "Identity.hpp"
#include "SharedPtr.hpp"
#include "TriviallyCopyable.hpp"
/** /**
* Maximum size of endpoint attributes dictionary plus one byte for size. * Maximum size of endpoint attributes dictionary plus one byte for size.
@ -35,7 +35,10 @@
*/ */
#define ZT_LOCATOR_MAX_ENDPOINTS 16 #define ZT_LOCATOR_MAX_ENDPOINTS 16
#define ZT_LOCATOR_MARSHAL_SIZE_MAX (8 + ZT_ADDRESS_LENGTH + 2 + (ZT_LOCATOR_MAX_ENDPOINTS * (ZT_ENDPOINT_MARSHAL_SIZE_MAX + ZT_LOCATOR_MAX_ENDPOINT_ATTRIBUTES_SIZE)) + 2 + 2 + ZT_SIGNATURE_BUFFER_SIZE) #define ZT_LOCATOR_MARSHAL_SIZE_MAX \
(8 + ZT_ADDRESS_LENGTH + 2 \
+ (ZT_LOCATOR_MAX_ENDPOINTS * (ZT_ENDPOINT_MARSHAL_SIZE_MAX + ZT_LOCATOR_MAX_ENDPOINT_ATTRIBUTES_SIZE)) + 2 + 2 \
+ ZT_SIGNATURE_BUFFER_SIZE)
/** /**
* Maximum size of a string format Locator (this is way larger than needed) * Maximum size of a string format Locator (this is way larger than needed)
@ -50,27 +53,25 @@ namespace ZeroTier {
* A locator contains long-lived endpoints for a node such as IP/port pairs, * A locator contains long-lived endpoints for a node such as IP/port pairs,
* URLs, or other nodes, and is signed by the node it describes. * URLs, or other nodes, and is signed by the node it describes.
*/ */
class Locator class Locator {
{ friend class SharedPtr<Locator>;
friend class SharedPtr< Locator >; friend class SharedPtr<const Locator>;
friend class SharedPtr< const Locator >;
public: public:
/** /**
* Attributes of an endpoint in this locator * Attributes of an endpoint in this locator
* *
* This is specified for future use, but there are currently no attributes * This is specified for future use, but there are currently no attributes
* defined. A Dictionary is used for serialization for extensibility. * defined. A Dictionary is used for serialization for extensibility.
*/ */
struct EndpointAttributes struct EndpointAttributes {
{ friend class SharedPtr<Locator::EndpointAttributes>;
friend class SharedPtr< Locator::EndpointAttributes >; friend class SharedPtr<const Locator::EndpointAttributes>;
friend class SharedPtr< const Locator::EndpointAttributes >;
/** /**
* Default endpoint attributes * Default endpoint attributes
*/ */
static const SharedPtr< const Locator::EndpointAttributes > DEFAULT; static const SharedPtr<const Locator::EndpointAttributes> DEFAULT;
/** /**
* Raw attributes data in the form of a dictionary prefixed by its size. * Raw attributes data in the form of a dictionary prefixed by its size.
@ -81,67 +82,90 @@ public:
uint8_t data[ZT_LOCATOR_MAX_ENDPOINT_ATTRIBUTES_SIZE]; uint8_t data[ZT_LOCATOR_MAX_ENDPOINT_ATTRIBUTES_SIZE];
ZT_INLINE EndpointAttributes() noexcept ZT_INLINE EndpointAttributes() noexcept
{ Utils::zero< ZT_LOCATOR_MAX_ENDPOINT_ATTRIBUTES_SIZE >(data); } {
Utils::zero<ZT_LOCATOR_MAX_ENDPOINT_ATTRIBUTES_SIZE>(data);
}
ZT_INLINE bool operator==(const EndpointAttributes &a) const noexcept ZT_INLINE bool operator==(const EndpointAttributes& a) const noexcept
{ return ((data[0] == a.data[0]) && (memcmp(data, a.data, data[0]) == 0)); } {
return ((data[0] == a.data[0]) && (memcmp(data, a.data, data[0]) == 0));
}
ZT_INLINE bool operator<(const EndpointAttributes &a) const noexcept ZT_INLINE bool operator<(const EndpointAttributes& a) const noexcept
{ return ((data[0] < a.data[0]) || ((data[0] == a.data[0]) && (memcmp(data, a.data, data[0]) < 0))); } {
return ((data[0] < a.data[0]) || ((data[0] == a.data[0]) && (memcmp(data, a.data, data[0]) < 0)));
}
ZT_INLINE bool operator!=(const EndpointAttributes &a) const noexcept ZT_INLINE bool operator!=(const EndpointAttributes& a) const noexcept
{ return !(*this == a); } {
return ! (*this == a);
}
ZT_INLINE bool operator>(const EndpointAttributes &a) const noexcept ZT_INLINE bool operator>(const EndpointAttributes& a) const noexcept
{ return (a < *this); } {
return (a < *this);
}
ZT_INLINE bool operator<=(const EndpointAttributes &a) const noexcept ZT_INLINE bool operator<=(const EndpointAttributes& a) const noexcept
{ return !(a < *this); } {
return ! (a < *this);
}
ZT_INLINE bool operator>=(const EndpointAttributes &a) const noexcept ZT_INLINE bool operator>=(const EndpointAttributes& a) const noexcept
{ return !(*this < a); } {
return ! (*this < a);
}
private: private:
std::atomic< int > __refCount; std::atomic<int> __refCount;
}; };
ZT_INLINE Locator() noexcept: ZT_INLINE Locator() noexcept : m_revision(0)
m_revision(0) {
{} }
ZT_INLINE Locator(const Locator &l) noexcept: ZT_INLINE Locator(const Locator& l) noexcept
m_revision(l.m_revision), : m_revision(l.m_revision)
m_signer(l.m_signer), , m_signer(l.m_signer)
m_endpoints(l.m_endpoints), , m_endpoints(l.m_endpoints)
m_signature(l.m_signature), , m_signature(l.m_signature)
__refCount(0) , __refCount(0)
{} {
}
explicit Locator(const char *const str) noexcept; explicit Locator(const char* const str) noexcept;
/** /**
* @return Timestamp (a.k.a. revision number) set by Location signer * @return Timestamp (a.k.a. revision number) set by Location signer
*/ */
ZT_INLINE int64_t revision() const noexcept ZT_INLINE int64_t revision() const noexcept
{ return m_revision; } {
return m_revision;
}
/** /**
* @return ZeroTier address of signer * @return ZeroTier address of signer
*/ */
ZT_INLINE Address signer() const noexcept ZT_INLINE Address signer() const noexcept
{ return m_signer; } {
return m_signer;
}
/** /**
* @return Endpoints specified in locator * @return Endpoints specified in locator
*/ */
ZT_INLINE const Vector <std::pair< Endpoint, SharedPtr< const EndpointAttributes > >> &endpoints() const noexcept ZT_INLINE const Vector<std::pair<Endpoint, SharedPtr<const EndpointAttributes> > >& endpoints() const noexcept
{ return m_endpoints; } {
return m_endpoints;
}
/** /**
* @return Signature data * @return Signature data
*/ */
ZT_INLINE const FCV< uint8_t, ZT_SIGNATURE_BUFFER_SIZE > &signature() const noexcept ZT_INLINE const FCV<uint8_t, ZT_SIGNATURE_BUFFER_SIZE>& signature() const noexcept
{ return m_signature; } {
return m_signature;
}
/** /**
* Add an endpoint to this locator * Add an endpoint to this locator
@ -153,7 +177,7 @@ public:
* @param a Endpoint attributes or NULL to use default * @param a Endpoint attributes or NULL to use default
* @return True if endpoint was added (or already present), false if locator is full * @return True if endpoint was added (or already present), false if locator is full
*/ */
bool add(const Endpoint &ep, const SharedPtr< const EndpointAttributes > &a); bool add(const Endpoint& ep, const SharedPtr<const EndpointAttributes>& a);
/** /**
* Sign this locator * Sign this locator
@ -164,7 +188,7 @@ public:
* @param id Identity that includes private key * @param id Identity that includes private key
* @return True if signature successful * @return True if signature successful
*/ */
bool sign(int64_t rev, const Identity &id) noexcept; bool sign(int64_t rev, const Identity& id) noexcept;
/** /**
* Verify this Locator's validity and signature * Verify this Locator's validity and signature
@ -172,7 +196,7 @@ public:
* @param id Identity corresponding to hash * @param id Identity corresponding to hash
* @return True if valid and signature checks out * @return True if valid and signature checks out
*/ */
bool verify(const Identity &id) const noexcept; bool verify(const Identity& id) const noexcept;
/** /**
* Convert this locator to a string * Convert this locator to a string
@ -180,7 +204,7 @@ public:
* @param s String buffer * @param s String buffer
* @return Pointer to buffer * @return Pointer to buffer
*/ */
char *toString(char s[ZT_LOCATOR_STRING_SIZE_MAX]) const noexcept; char* toString(char s[ZT_LOCATOR_STRING_SIZE_MAX]) const noexcept;
ZT_INLINE String toString() const ZT_INLINE String toString() const
{ {
@ -194,29 +218,35 @@ public:
* @param s Locator from toString() * @param s Locator from toString()
* @return True if format was valid * @return True if format was valid
*/ */
bool fromString(const char *s) noexcept; bool fromString(const char* s) noexcept;
explicit ZT_INLINE operator bool() const noexcept explicit ZT_INLINE operator bool() const noexcept
{ return m_revision > 0; } {
return m_revision > 0;
}
static constexpr int marshalSizeMax() noexcept static constexpr int marshalSizeMax() noexcept
{ return ZT_LOCATOR_MARSHAL_SIZE_MAX; } {
return ZT_LOCATOR_MARSHAL_SIZE_MAX;
}
int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX], bool excludeSignature = false) const noexcept; int marshal(uint8_t data[ZT_LOCATOR_MARSHAL_SIZE_MAX], bool excludeSignature = false) const noexcept;
int unmarshal(const uint8_t *data, int len) noexcept; int unmarshal(const uint8_t* data, int len) noexcept;
ZT_INLINE bool operator==(const Locator &l) const noexcept ZT_INLINE bool operator==(const Locator& l) const noexcept
{ {
const unsigned long es = (unsigned long)m_endpoints.size(); const unsigned long es = (unsigned long)m_endpoints.size();
if ((m_revision == l.m_revision) && (m_signer == l.m_signer) && (es == (unsigned long)l.m_endpoints.size()) && (m_signature == l.m_signature)) { if ((m_revision == l.m_revision) && (m_signer == l.m_signer) && (es == (unsigned long)l.m_endpoints.size())
&& (m_signature == l.m_signature)) {
for (unsigned long i = 0; i < es; ++i) { for (unsigned long i = 0; i < es; ++i) {
if (m_endpoints[i].first != l.m_endpoints[i].first) if (m_endpoints[i].first != l.m_endpoints[i].first)
return false; return false;
if (!m_endpoints[i].second) { if (! m_endpoints[i].second) {
if (l.m_endpoints[i].second) if (l.m_endpoints[i].second)
return false; return false;
} else { }
if ((!l.m_endpoints[i].second) || (*(m_endpoints[i].second) != *(l.m_endpoints[i].second))) else {
if ((! l.m_endpoints[i].second) || (*(m_endpoints[i].second) != *(l.m_endpoints[i].second)))
return false; return false;
} }
} }
@ -225,17 +255,19 @@ public:
return false; return false;
} }
ZT_INLINE bool operator!=(const Locator &l) const noexcept ZT_INLINE bool operator!=(const Locator& l) const noexcept
{ return !(*this == l); } {
return ! (*this == l);
}
private: private:
void m_sortEndpoints() noexcept; void m_sortEndpoints() noexcept;
int64_t m_revision; int64_t m_revision;
Address m_signer; Address m_signer;
Vector <std::pair< Endpoint, SharedPtr< const EndpointAttributes > >> m_endpoints; Vector<std::pair<Endpoint, SharedPtr<const EndpointAttributes> > > m_endpoints;
FCV< uint8_t, ZT_SIGNATURE_BUFFER_SIZE > m_signature; FCV<uint8_t, ZT_SIGNATURE_BUFFER_SIZE> m_signature;
std::atomic< int > __refCount; std::atomic<int> __refCount;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -14,55 +14,70 @@
#ifndef ZT_MAC_HPP #ifndef ZT_MAC_HPP
#define ZT_MAC_HPP #define ZT_MAC_HPP
#include "Constants.hpp"
#include "Utils.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "TriviallyCopyable.hpp" #include "Constants.hpp"
#include "Containers.hpp" #include "Containers.hpp"
#include "TriviallyCopyable.hpp"
#include "Utils.hpp"
namespace ZeroTier { namespace ZeroTier {
/** /**
* 48-byte Ethernet MAC address * 48-byte Ethernet MAC address
*/ */
class MAC : public TriviallyCopyable class MAC : public TriviallyCopyable {
{ public:
public: ZT_INLINE MAC() noexcept : m_mac(0ULL)
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: ZT_INLINE
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)) 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: explicit ZT_INLINE MAC(const uint64_t m) noexcept : m_mac(m)
m_mac(m) {
{} }
explicit ZT_INLINE MAC(const uint8_t b[6]) noexcept explicit ZT_INLINE MAC(const uint8_t b[6]) noexcept
{ setTo(b); } {
setTo(b);
}
ZT_INLINE MAC(const Address &ztaddr, const uint64_t nwid) noexcept ZT_INLINE MAC(const Address& ztaddr, const uint64_t nwid) noexcept
{ fromAddress(ztaddr, nwid); } {
fromAddress(ztaddr, nwid);
}
/** /**
* @return MAC in 64-bit integer * @return MAC in 64-bit integer
*/ */
ZT_INLINE uint64_t toInt() const noexcept ZT_INLINE uint64_t toInt() const noexcept
{ return m_mac; } {
return m_mac;
}
/** /**
* Set MAC to zero * Set MAC to zero
*/ */
ZT_INLINE void zero() noexcept ZT_INLINE void zero() noexcept
{ m_mac = 0ULL; } {
m_mac = 0ULL;
}
/** /**
* @param bits Raw MAC in big-endian byte order * @param bits Raw MAC in big-endian byte order
* @param len Length, must be >= 6 or result is zero * @param len Length, must be >= 6 or result is zero
*/ */
ZT_INLINE void setTo(const uint8_t b[6]) noexcept ZT_INLINE void setTo(const uint8_t b[6]) noexcept
{ 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]; } {
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];
}
/** /**
* @param buf Destination buffer for MAC in big-endian byte order * @param buf Destination buffer for MAC in big-endian byte order
@ -82,13 +97,17 @@ public:
* @return True if this is broadcast (all 0xff) * @return True if this is broadcast (all 0xff)
*/ */
ZT_INLINE bool isBroadcast() const noexcept ZT_INLINE bool isBroadcast() const noexcept
{ return m_mac; } {
return m_mac;
}
/** /**
* @return True if this is a multicast MAC * @return True if this is a multicast MAC
*/ */
ZT_INLINE bool isMulticast() const noexcept ZT_INLINE bool isMulticast() const noexcept
{ return ((m_mac & 0x010000000000ULL) != 0ULL); } {
return ((m_mac & 0x010000000000ULL) != 0ULL);
}
/** /**
* Set this MAC to a MAC derived from an address and a network ID * Set this MAC to a MAC derived from an address and a network ID
@ -96,7 +115,7 @@ public:
* @param ztaddr ZeroTier address * @param ztaddr ZeroTier address
* @param nwid 64-bit network ID * @param nwid 64-bit network ID
*/ */
ZT_INLINE void fromAddress(const Address &ztaddr, uint64_t nwid) noexcept ZT_INLINE void fromAddress(const Address& ztaddr, uint64_t nwid) noexcept
{ {
uint64_t m = ((uint64_t)firstOctetForNetwork(nwid)) << 40U; uint64_t m = ((uint64_t)firstOctetForNetwork(nwid)) << 40U;
m |= ztaddr.toInt(); // a is 40 bits m |= ztaddr.toInt(); // a is 40 bits
@ -118,7 +137,8 @@ public:
ZT_INLINE Address toAddress(uint64_t nwid) const noexcept ZT_INLINE Address toAddress(uint64_t nwid) const noexcept
{ {
uint64_t a = m_mac & 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 >> 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 >> 16U) & 0xffU) << 24U;
a ^= ((nwid >> 24U) & 0xffU) << 16U; a ^= ((nwid >> 24U) & 0xffU) << 16U;
a ^= ((nwid >> 32U) & 0xffU) << 8U; a ^= ((nwid >> 32U) & 0xffU) << 8U;
@ -132,8 +152,10 @@ public:
*/ */
static ZT_INLINE unsigned char firstOctetForNetwork(uint64_t nwid) noexcept static ZT_INLINE unsigned char firstOctetForNetwork(uint64_t nwid) noexcept
{ {
const uint8_t a = ((uint8_t)(nwid & 0xfeU) | 0x02U); // locally administered, not multicast, from LSB of network ID const uint8_t a =
return ((a == 0x52) ? 0x32 : a); // blacklist 0x52 since it's used by KVM, libvirt, and other popular virtualization engines... seems de-facto standard on Linux ((uint8_t)(nwid & 0xfeU) | 0x02U); // locally administered, not multicast, from LSB of network ID
return ((a == 0x52) ? 0x32 : a); // blacklist 0x52 since it's used by KVM, libvirt, and other popular
// virtualization engines... seems de-facto standard on Linux
} }
/** /**
@ -141,22 +163,32 @@ public:
* @return Byte at said position (address interpreted in big-endian order) * @return Byte at said position (address interpreted in big-endian order)
*/ */
ZT_INLINE uint8_t operator[](unsigned int i) const noexcept ZT_INLINE uint8_t operator[](unsigned int i) const noexcept
{ return (uint8_t)(m_mac >> (unsigned int)(40 - (i * 8))); } {
return (uint8_t)(m_mac >> (unsigned int)(40 - (i * 8)));
}
/** /**
* @return 6, which is the number of bytes in a MAC, for container compliance * @return 6, which is the number of bytes in a MAC, for container compliance
*/ */
ZT_INLINE unsigned int size() const noexcept ZT_INLINE unsigned int size() const noexcept
{ return 6; } {
return 6;
}
ZT_INLINE unsigned long hashCode() const noexcept ZT_INLINE unsigned long hashCode() const noexcept
{ return (unsigned long)Utils::hash64(m_mac); } {
return (unsigned long)Utils::hash64(m_mac);
}
ZT_INLINE operator bool() const noexcept ZT_INLINE operator bool() const noexcept
{ return (m_mac != 0ULL); } {
return (m_mac != 0ULL);
}
ZT_INLINE operator uint64_t() const noexcept ZT_INLINE operator uint64_t() const noexcept
{ return m_mac; } {
return m_mac;
}
/** /**
* Convert this MAC to a standard format colon-separated hex string * Convert this MAC to a standard format colon-separated hex string
@ -164,7 +196,7 @@ public:
* @param buf Buffer to store string * @param buf Buffer to store string
* @return Pointer to buf * @return Pointer to buf
*/ */
ZT_INLINE char *toString(char buf[18]) const noexcept ZT_INLINE char* toString(char buf[18]) const noexcept
{ {
buf[0] = Utils::HEXCHARS[(m_mac >> 44U) & 0xfU]; buf[0] = Utils::HEXCHARS[(m_mac >> 44U) & 0xfU];
buf[1] = Utils::HEXCHARS[(m_mac >> 40U) & 0xfU]; buf[1] = Utils::HEXCHARS[(m_mac >> 40U) & 0xfU];
@ -198,7 +230,7 @@ public:
* *
* @param s String to parse * @param s String to parse
*/ */
ZT_INLINE void fromString(const char *s) noexcept ZT_INLINE void fromString(const char* s) noexcept
{ {
m_mac = 0; m_mac = 0;
if (s) { if (s) {
@ -211,56 +243,81 @@ public:
c = (uint64_t)hc - 87; c = (uint64_t)hc - 87;
else if ((hc >= 65) && (hc <= 70)) else if ((hc >= 65) && (hc <= 70))
c = (uint64_t)hc - 55; c = (uint64_t)hc - 55;
else continue; else
continue;
m_mac = (m_mac << 4U) | c; m_mac = (m_mac << 4U) | c;
} }
m_mac &= 0xffffffffffffULL; m_mac &= 0xffffffffffffULL;
} }
} }
ZT_INLINE MAC &operator=(const uint64_t m) noexcept ZT_INLINE MAC& operator=(const uint64_t m) noexcept
{ {
m_mac = m; m_mac = m;
return *this; return *this;
} }
ZT_INLINE bool operator==(const MAC &m) const noexcept ZT_INLINE bool operator==(const MAC& m) const noexcept
{ return (m_mac == m.m_mac); } {
return (m_mac == m.m_mac);
}
ZT_INLINE bool operator!=(const MAC &m) const noexcept ZT_INLINE bool operator!=(const MAC& m) const noexcept
{ return (m_mac != m.m_mac); } {
return (m_mac != m.m_mac);
}
ZT_INLINE bool operator<(const MAC &m) const noexcept ZT_INLINE bool operator<(const MAC& m) const noexcept
{ return (m_mac < m.m_mac); } {
return (m_mac < m.m_mac);
}
ZT_INLINE bool operator<=(const MAC &m) const noexcept ZT_INLINE bool operator<=(const MAC& m) const noexcept
{ return (m_mac <= m.m_mac); } {
return (m_mac <= m.m_mac);
}
ZT_INLINE bool operator>(const MAC &m) const noexcept ZT_INLINE bool operator>(const MAC& m) const noexcept
{ return (m_mac > m.m_mac); } {
return (m_mac > m.m_mac);
}
ZT_INLINE bool operator>=(const MAC &m) const noexcept ZT_INLINE bool operator>=(const MAC& m) const noexcept
{ return (m_mac >= m.m_mac); } {
return (m_mac >= m.m_mac);
}
ZT_INLINE bool operator==(const uint64_t m) const noexcept ZT_INLINE bool operator==(const uint64_t m) const noexcept
{ return (m_mac == m); } {
return (m_mac == m);
}
ZT_INLINE bool operator!=(const uint64_t m) const noexcept ZT_INLINE bool operator!=(const uint64_t m) const noexcept
{ return (m_mac != m); } {
return (m_mac != m);
}
ZT_INLINE bool operator<(const uint64_t m) const noexcept ZT_INLINE bool operator<(const uint64_t m) const noexcept
{ return (m_mac < m); } {
return (m_mac < m);
}
ZT_INLINE bool operator<=(const uint64_t m) const noexcept ZT_INLINE bool operator<=(const uint64_t m) const noexcept
{ return (m_mac <= m); } {
return (m_mac <= m);
}
ZT_INLINE bool operator>(const uint64_t m) const noexcept ZT_INLINE bool operator>(const uint64_t m) const noexcept
{ return (m_mac > m); } {
return (m_mac > m);
}
ZT_INLINE bool operator>=(const uint64_t m) const noexcept ZT_INLINE bool operator>=(const uint64_t m) const noexcept
{ return (m_mac >= m); } {
return (m_mac >= m);
}
private: private:
uint64_t m_mac; uint64_t m_mac;
}; };

View file

@ -11,37 +11,131 @@
*/ */
/****/ /****/
#include "Constants.hpp"
#include "AES.hpp"
#include "MIMC52.hpp" #include "MIMC52.hpp"
#include "AES.hpp"
#include "Constants.hpp"
namespace { namespace {
// Largest 1024 primes of form 6k + 5 and less than 2^52. Only the least significant 32 // Largest 1024 primes of form 6k + 5 and less than 2^52. Only the least significant 32
// bits need to be here, as the most significant bits are all 1. // bits need to be here, as the most significant bits are all 1.
const uint32_t ZT_MIMC52_PRIMES[1024] = {4294895267, 4294895477, 4294895513, 4294895519, 4294895543, 4294895567, 4294895657, 4294895711, 4294895777, 4294895861, 4294895909, 4294895921, 4294895969, 4294896011, 4294896149, 4294896227, 4294896401, 4294896473, 4294896527, 4294896563, 4294896653, 4294896731, 4294896863, 4294896899, 4294896983, 4294897037, 4294897103, 4294897331, 4294897349, 4294897451, 4294897571, 4294897661, 4294897703, 4294897757, 4294897793, 4294897811, 4294897817, 4294897829, 4294897877, 4294897919, 4294897991, 4294898027, 4294898129, 4294898153, 4294898231, 4294898273, const uint32_t ZT_MIMC52_PRIMES[1024] = {
4294898279, 4294898291, 4294898363, 4294898369, 4294898417, 4294898423, 4294898453, 4294898489, 4294898573, 4294898579, 4294898639, 4294898693, 4294898747, 4294898759, 4294898867, 4294898879, 4294898909, 4294898921, 4294898933, 4294899011, 4294899041, 4294899047, 4294899203, 4294899221, 4294899227, 4294899287, 4294899341, 4294899431, 4294899509, 4294899533, 4294899539, 4294899551, 4294899629, 4294899791, 4294899809, 4294899971, 4294900001, 4294900007, 4294900013, 4294900307, 4294900331, 4294900427, 4294900469, 4294900481, 4294900541, 4294900583, 4294895267, 4294895477, 4294895513, 4294895519, 4294895543, 4294895567, 4294895657, 4294895711, 4294895777,
4294900781, 4294900853, 4294900931, 4294900991, 4294901033, 4294901087, 4294901159, 4294901267, 4294901393, 4294901411, 4294901489, 4294901657, 4294902011, 4294902071, 4294902101, 4294902107, 4294902353, 4294902377, 4294902599, 4294902647, 4294902743, 4294902869, 4294902977, 4294903067, 4294903103, 4294903259, 4294903289, 4294903397, 4294903421, 4294903493, 4294903577, 4294903631, 4294903637, 4294903733, 4294903799, 4294903823, 4294904003, 4294904033, 4294904081, 4294904129, 4294904279, 4294904297, 4294904303, 4294904333, 4294904351, 4294904381, 4294895861, 4294895909, 4294895921, 4294895969, 4294896011, 4294896149, 4294896227, 4294896401, 4294896473,
4294904453, 4294904519, 4294904561, 4294904639, 4294904657, 4294904747, 4294904807, 4294904843, 4294905089, 4294905149, 4294905293, 4294905299, 4294905311, 4294905443, 4294905479, 4294905539, 4294905623, 4294905641, 4294905671, 4294905707, 4294905887, 4294905977, 4294906091, 4294906103, 4294906139, 4294906157, 4294906223, 4294906259, 4294906487, 4294906493, 4294906523, 4294906547, 4294906553, 4294906571, 4294906577, 4294906589, 4294906703, 4294906733, 4294906763, 4294906841, 4294906859, 4294906937, 4294907057, 4294907063, 4294907141, 4294907231, 4294896527, 4294896563, 4294896653, 4294896731, 4294896863, 4294896899, 4294896983, 4294897037, 4294897103,
4294907249, 4294907261, 4294907267, 4294907387, 4294907417, 4294907567, 4294907603, 4294907699, 4294907789, 4294907849, 4294907873, 4294907879, 4294908023, 4294908071, 4294908119, 4294908209, 4294908227, 4294908329, 4294908491, 4294908503, 4294908569, 4294908653, 4294908713, 4294908719, 4294908791, 4294908839, 4294908869, 4294908989, 4294909031, 4294909067, 4294909109, 4294909253, 4294909529, 4294909589, 4294909643, 4294909739, 4294909799, 4294909811, 4294909853, 4294910003, 4294910039, 4294910189, 4294910201, 4294910219, 4294910273, 4294910333, 4294897331, 4294897349, 4294897451, 4294897571, 4294897661, 4294897703, 4294897757, 4294897793, 4294897811,
4294910369, 4294910393, 4294910471, 4294910549, 4294910651, 4294910669, 4294910681, 4294910711, 4294910753, 4294910801, 4294910981, 4294911053, 4294911143, 4294911227, 4294911239, 4294911359, 4294911383, 4294911407, 4294911521, 4294911551, 4294911611, 4294911641, 4294911689, 4294911719, 4294911869, 4294912109, 4294912133, 4294912151, 4294912187, 4294912223, 4294912331, 4294912439, 4294912607, 4294912703, 4294912859, 4294912871, 4294912907, 4294912961, 4294913003, 4294913111, 4294913309, 4294913333, 4294913357, 4294913399, 4294913411, 4294913459, 4294897817, 4294897829, 4294897877, 4294897919, 4294897991, 4294898027, 4294898129, 4294898153, 4294898231,
4294913501, 4294913531, 4294913591, 4294913609, 4294913663, 4294913783, 4294913819, 4294913903, 4294914137, 4294914413, 4294914473, 4294914497, 4294914527, 4294914551, 4294914593, 4294914611, 4294914659, 4294914671, 4294914743, 4294914863, 4294914917, 4294915061, 4294915103, 4294915139, 4294915217, 4294915223, 4294915253, 4294915283, 4294915373, 4294915433, 4294915607, 4294916069, 4294916213, 4294916267, 4294916303, 4294916393, 4294916441, 4294916477, 4294916507, 4294916573, 4294916633, 4294916687, 4294916783, 4294916837, 4294916897, 4294916921, 4294898273, 4294898279, 4294898291, 4294898363, 4294898369, 4294898417, 4294898423, 4294898453, 4294898489,
4294917029, 4294917047, 4294917101, 4294917203, 4294917287, 4294917299, 4294917389, 4294917437, 4294917527, 4294917557, 4294917611, 4294917617, 4294917689, 4294917821, 4294917857, 4294917917, 4294917941, 4294918169, 4294918187, 4294918307, 4294918409, 4294918433, 4294918481, 4294918703, 4294918709, 4294918733, 4294918799, 4294918871, 4294919009, 4294919249, 4294919279, 4294919291, 4294919363, 4294919381, 4294919441, 4294919447, 4294919549, 4294919579, 4294919633, 4294919657, 4294919669, 4294919693, 4294919711, 4294920029, 4294920059, 4294920089, 4294898573, 4294898579, 4294898639, 4294898693, 4294898747, 4294898759, 4294898867, 4294898879, 4294898909,
4294920197, 4294920239, 4294920257, 4294920263, 4294920269, 4294920341, 4294920353, 4294920407, 4294920503, 4294920599, 4294920647, 4294920743, 4294920803, 4294920809, 4294920881, 4294920899, 4294920983, 4294921043, 4294921139, 4294921151, 4294921181, 4294921229, 4294921289, 4294921331, 4294921343, 4294921391, 4294921469, 4294921709, 4294921721, 4294921823, 4294921847, 4294921889, 4294922057, 4294922171, 4294922201, 4294922237, 4294922309, 4294922399, 4294922447, 4294922507, 4294922513, 4294922549, 4294922609, 4294922663, 4294922861, 4294922933, 4294898921, 4294898933, 4294899011, 4294899041, 4294899047, 4294899203, 4294899221, 4294899227, 4294899287,
4294923101, 4294923191, 4294923209, 4294923221, 4294923251, 4294923263, 4294923359, 4294923371, 4294923377, 4294923461, 4294923521, 4294923953, 4294924001, 4294924091, 4294924121, 4294924319, 4294924397, 4294924571, 4294924583, 4294924751, 4294924817, 4294924823, 4294924847, 4294924877, 4294925003, 4294925027, 4294925117, 4294925237, 4294925243, 4294925297, 4294925369, 4294925627, 4294925639, 4294925729, 4294925747, 4294925873, 4294925891, 4294925933, 4294926047, 4294926059, 4294926209, 4294926221, 4294926233, 4294926257, 4294926329, 4294926371, 4294899341, 4294899431, 4294899509, 4294899533, 4294899539, 4294899551, 4294899629, 4294899791, 4294899809,
4294926401, 4294926413, 4294926437, 4294926563, 4294926569, 4294926917, 4294926923, 4294926947, 4294926971, 4294927067, 4294927073, 4294927151, 4294927349, 4294927367, 4294927403, 4294927481, 4294927523, 4294927553, 4294927589, 4294927649, 4294927673, 4294927727, 4294927739, 4294927763, 4294927889, 4294928183, 4294928207, 4294928249, 4294928327, 4294928351, 4294928399, 4294928483, 4294928489, 4294928543, 4294928597, 4294928951, 4294928963, 4294928981, 4294929017, 4294929059, 4294929161, 4294929197, 4294929233, 4294929269, 4294929311, 4294929323, 4294899971, 4294900001, 4294900007, 4294900013, 4294900307, 4294900331, 4294900427, 4294900469, 4294900481,
4294929341, 4294929383, 4294929401, 4294929497, 4294929509, 4294929581, 4294929707, 4294929743, 4294930043, 4294930121, 4294930193, 4294930223, 4294930349, 4294930403, 4294930571, 4294930613, 4294930721, 4294930751, 4294930877, 4294930931, 4294930961, 4294930967, 4294930973, 4294931021, 4294931051, 4294931057, 4294931063, 4294931219, 4294931273, 4294931339, 4294931423, 4294931441, 4294931453, 4294931567, 4294931639, 4294931717, 4294931897, 4294931969, 4294932023, 4294932053, 4294932239, 4294932299, 4294932443, 4294932671, 4294932677, 4294932731, 4294900541, 4294900583, 4294900781, 4294900853, 4294900931, 4294900991, 4294901033, 4294901087, 4294901159,
4294932743, 4294932767, 4294932773, 4294932779, 4294932881, 4294932899, 4294932929, 4294933067, 4294933277, 4294933307, 4294933343, 4294933451, 4294933523, 4294933763, 4294933793, 4294933829, 4294933847, 4294933871, 4294933997, 4294934033, 4294934111, 4294934207, 4294934243, 4294934267, 4294934279, 4294934291, 4294934327, 4294934363, 4294934423, 4294934489, 4294934561, 4294934867, 4294934921, 4294934969, 4294935137, 4294935239, 4294935299, 4294935431, 4294935539, 4294935629, 4294935701, 4294935791, 4294935797, 4294935803, 4294935959, 4294936001, 4294901267, 4294901393, 4294901411, 4294901489, 4294901657, 4294902011, 4294902071, 4294902101, 4294902107,
4294936007, 4294936037, 4294936079, 4294936127, 4294936163, 4294936247, 4294936307, 4294936331, 4294936409, 4294936451, 4294936601, 4294936607, 4294936619, 4294936667, 4294936709, 4294936733, 4294936751, 4294936763, 4294936829, 4294936937, 4294936997, 4294937027, 4294937051, 4294937093, 4294937177, 4294937213, 4294937291, 4294937381, 4294937417, 4294937429, 4294937681, 4294937693, 4294937753, 4294937771, 4294937813, 4294937837, 4294937891, 4294937969, 4294938071, 4294938101, 4294938323, 4294938371, 4294938401, 4294938467, 4294938473, 4294938521, 4294902353, 4294902377, 4294902599, 4294902647, 4294902743, 4294902869, 4294902977, 4294903067, 4294903103,
4294938599, 4294938731, 4294938779, 4294938833, 4294938899, 4294938977, 4294938983, 4294939067, 4294939127, 4294939223, 4294939277, 4294939331, 4294939337, 4294939391, 4294939457, 4294939559, 4294939673, 4294939691, 4294939901, 4294939991, 4294940087, 4294940093, 4294940189, 4294940213, 4294940417, 4294940657, 4294940699, 4294940753, 4294940801, 4294940873, 4294940951, 4294941047, 4294941143, 4294941161, 4294941227, 4294941281, 4294941377, 4294941509, 4294941551, 4294941701, 4294941731, 4294941767, 4294941911, 4294941923, 4294942043, 4294942139, 4294903259, 4294903289, 4294903397, 4294903421, 4294903493, 4294903577, 4294903631, 4294903637, 4294903733,
4294942313, 4294942343, 4294942373, 4294942427, 4294942529, 4294942601, 4294942649, 4294942673, 4294942679, 4294942733, 4294942769, 4294942811, 4294942961, 4294943129, 4294943141, 4294943219, 4294943369, 4294943423, 4294943471, 4294943651, 4294943687, 4294943717, 4294943729, 4294943747, 4294943759, 4294943813, 4294943819, 4294943891, 4294944077, 4294944191, 4294944233, 4294944239, 4294944353, 4294944389, 4294944581, 4294944623, 4294944629, 4294944659, 4294944821, 4294945031, 4294945157, 4294945211, 4294945229, 4294945301, 4294945337, 4294945343, 4294903799, 4294903823, 4294904003, 4294904033, 4294904081, 4294904129, 4294904279, 4294904297, 4294904303,
4294945511, 4294945547, 4294945667, 4294945709, 4294945757, 4294945841, 4294945991, 4294946033, 4294946099, 4294946153, 4294946477, 4294946687, 4294946747, 4294946957, 4294946993, 4294947023, 4294947131, 4294947167, 4294947287, 4294947311, 4294947413, 4294947581, 4294947599, 4294947671, 4294947851, 4294947959, 4294948067, 4294948073, 4294948193, 4294948259, 4294948421, 4294948451, 4294948613, 4294948673, 4294948883, 4294949027, 4294949057, 4294949069, 4294949519, 4294949531, 4294949603, 4294949609, 4294949627, 4294949693, 4294949729, 4294949741, 4294904333, 4294904351, 4294904381, 4294904453, 4294904519, 4294904561, 4294904639, 4294904657, 4294904747,
4294949807, 4294949921, 4294949939, 4294949981, 4294949993, 4294950083, 4294950173, 4294950197, 4294950251, 4294950287, 4294950317, 4294950323, 4294950329, 4294950581, 4294950593, 4294950617, 4294950629, 4294950713, 4294950929, 4294951151, 4294951163, 4294951169, 4294951379, 4294951583, 4294951613, 4294951853, 4294951907, 4294951913, 4294951937, 4294951961, 4294952063, 4294952183, 4294952393, 4294952543, 4294952549, 4294952597, 4294952627, 4294952687, 4294952723, 4294952729, 4294952789, 4294952819, 4294952873, 4294952891, 4294952903, 4294952969, 4294904807, 4294904843, 4294905089, 4294905149, 4294905293, 4294905299, 4294905311, 4294905443, 4294905479,
4294952999, 4294953023, 4294953107, 4294953173, 4294953281, 4294953341, 4294953431, 4294953599, 4294953689, 4294953719, 4294953827, 4294953887, 4294953977, 4294954073, 4294954079, 4294954157, 4294954217, 4294954283, 4294954607, 4294954667, 4294954859, 4294954901, 4294954973, 4294955081, 4294955237, 4294955273, 4294955327, 4294955441, 4294955507, 4294955591, 4294955789, 4294955831, 4294955837, 4294955927, 4294955963, 4294955969, 4294955987, 4294956041, 4294956047, 4294956197, 4294956323, 4294956359, 4294956551, 4294956593, 4294956623, 4294956629, 4294905539, 4294905623, 4294905641, 4294905671, 4294905707, 4294905887, 4294905977, 4294906091, 4294906103,
4294956641, 4294956719, 4294956761, 4294956767, 4294956797, 4294956821, 4294956833, 4294957037, 4294957079, 4294957103, 4294957181, 4294957349, 4294957379, 4294957433, 4294957463, 4294957511, 4294957577, 4294957727, 4294957859, 4294957877, 4294958039, 4294958153, 4294958309, 4294958417, 4294958441, 4294958693, 4294958717, 4294958753, 4294958903, 4294958909, 4294959017, 4294959071, 4294959107, 4294959161, 4294959257, 4294959299, 4294959329, 4294959431, 4294959593, 4294959599, 4294959659, 4294959893, 4294959917, 4294959983, 4294960001, 4294960031, 4294906139, 4294906157, 4294906223, 4294906259, 4294906487, 4294906493, 4294906523, 4294906547, 4294906553,
4294960061, 4294960079, 4294960097, 4294960271, 4294960283, 4294960349, 4294960367, 4294960421, 4294960529, 4294960541, 4294960583, 4294960613, 4294960673, 4294960691, 4294960697, 4294960787, 4294960919, 4294961003, 4294961039, 4294961153, 4294961159, 4294961171, 4294961321, 4294961411, 4294961471, 4294961507, 4294961537, 4294961669, 4294961717, 4294961741, 4294961873, 4294962059, 4294962137, 4294962167, 4294962263, 4294962281, 4294962311, 4294962341, 4294962413, 4294962521, 4294962563, 4294962761, 4294962893, 4294963103, 4294963163, 4294963223, 4294906571, 4294906577, 4294906589, 4294906703, 4294906733, 4294906763, 4294906841, 4294906859, 4294906937,
4294963313, 4294963349, 4294963427, 4294963547, 4294963559, 4294963721, 4294963799, 4294963817, 4294963901, 4294963919, 4294964021, 4294964279, 4294964297, 4294964363, 4294964387, 4294964411, 4294964567, 4294964603, 4294964687, 4294964777, 4294965041, 4294965071, 4294965119, 4294965221, 4294965251, 4294965287, 4294965413, 4294965569, 4294965647, 4294965671, 4294965689, 4294965779, 4294965839, 4294965893, 4294966091, 4294966109, 4294966127, 4294966157, 4294966187, 4294966199, 4294966211, 4294966403, 4294966457, 4294966499, 4294966541, 4294966637, 4294907057, 4294907063, 4294907141, 4294907231, 4294907249, 4294907261, 4294907267, 4294907387, 4294907417,
4294966661, 4294966739, 4294966823, 4294966883, 4294966901, 4294966961, 4294967027, 4294967087, 4294967099, 4294967123, 4294967153, 4294967249}; 4294907567, 4294907603, 4294907699, 4294907789, 4294907849, 4294907873, 4294907879, 4294908023, 4294908071,
4294908119, 4294908209, 4294908227, 4294908329, 4294908491, 4294908503, 4294908569, 4294908653, 4294908713,
4294908719, 4294908791, 4294908839, 4294908869, 4294908989, 4294909031, 4294909067, 4294909109, 4294909253,
4294909529, 4294909589, 4294909643, 4294909739, 4294909799, 4294909811, 4294909853, 4294910003, 4294910039,
4294910189, 4294910201, 4294910219, 4294910273, 4294910333, 4294910369, 4294910393, 4294910471, 4294910549,
4294910651, 4294910669, 4294910681, 4294910711, 4294910753, 4294910801, 4294910981, 4294911053, 4294911143,
4294911227, 4294911239, 4294911359, 4294911383, 4294911407, 4294911521, 4294911551, 4294911611, 4294911641,
4294911689, 4294911719, 4294911869, 4294912109, 4294912133, 4294912151, 4294912187, 4294912223, 4294912331,
4294912439, 4294912607, 4294912703, 4294912859, 4294912871, 4294912907, 4294912961, 4294913003, 4294913111,
4294913309, 4294913333, 4294913357, 4294913399, 4294913411, 4294913459, 4294913501, 4294913531, 4294913591,
4294913609, 4294913663, 4294913783, 4294913819, 4294913903, 4294914137, 4294914413, 4294914473, 4294914497,
4294914527, 4294914551, 4294914593, 4294914611, 4294914659, 4294914671, 4294914743, 4294914863, 4294914917,
4294915061, 4294915103, 4294915139, 4294915217, 4294915223, 4294915253, 4294915283, 4294915373, 4294915433,
4294915607, 4294916069, 4294916213, 4294916267, 4294916303, 4294916393, 4294916441, 4294916477, 4294916507,
4294916573, 4294916633, 4294916687, 4294916783, 4294916837, 4294916897, 4294916921, 4294917029, 4294917047,
4294917101, 4294917203, 4294917287, 4294917299, 4294917389, 4294917437, 4294917527, 4294917557, 4294917611,
4294917617, 4294917689, 4294917821, 4294917857, 4294917917, 4294917941, 4294918169, 4294918187, 4294918307,
4294918409, 4294918433, 4294918481, 4294918703, 4294918709, 4294918733, 4294918799, 4294918871, 4294919009,
4294919249, 4294919279, 4294919291, 4294919363, 4294919381, 4294919441, 4294919447, 4294919549, 4294919579,
4294919633, 4294919657, 4294919669, 4294919693, 4294919711, 4294920029, 4294920059, 4294920089, 4294920197,
4294920239, 4294920257, 4294920263, 4294920269, 4294920341, 4294920353, 4294920407, 4294920503, 4294920599,
4294920647, 4294920743, 4294920803, 4294920809, 4294920881, 4294920899, 4294920983, 4294921043, 4294921139,
4294921151, 4294921181, 4294921229, 4294921289, 4294921331, 4294921343, 4294921391, 4294921469, 4294921709,
4294921721, 4294921823, 4294921847, 4294921889, 4294922057, 4294922171, 4294922201, 4294922237, 4294922309,
4294922399, 4294922447, 4294922507, 4294922513, 4294922549, 4294922609, 4294922663, 4294922861, 4294922933,
4294923101, 4294923191, 4294923209, 4294923221, 4294923251, 4294923263, 4294923359, 4294923371, 4294923377,
4294923461, 4294923521, 4294923953, 4294924001, 4294924091, 4294924121, 4294924319, 4294924397, 4294924571,
4294924583, 4294924751, 4294924817, 4294924823, 4294924847, 4294924877, 4294925003, 4294925027, 4294925117,
4294925237, 4294925243, 4294925297, 4294925369, 4294925627, 4294925639, 4294925729, 4294925747, 4294925873,
4294925891, 4294925933, 4294926047, 4294926059, 4294926209, 4294926221, 4294926233, 4294926257, 4294926329,
4294926371, 4294926401, 4294926413, 4294926437, 4294926563, 4294926569, 4294926917, 4294926923, 4294926947,
4294926971, 4294927067, 4294927073, 4294927151, 4294927349, 4294927367, 4294927403, 4294927481, 4294927523,
4294927553, 4294927589, 4294927649, 4294927673, 4294927727, 4294927739, 4294927763, 4294927889, 4294928183,
4294928207, 4294928249, 4294928327, 4294928351, 4294928399, 4294928483, 4294928489, 4294928543, 4294928597,
4294928951, 4294928963, 4294928981, 4294929017, 4294929059, 4294929161, 4294929197, 4294929233, 4294929269,
4294929311, 4294929323, 4294929341, 4294929383, 4294929401, 4294929497, 4294929509, 4294929581, 4294929707,
4294929743, 4294930043, 4294930121, 4294930193, 4294930223, 4294930349, 4294930403, 4294930571, 4294930613,
4294930721, 4294930751, 4294930877, 4294930931, 4294930961, 4294930967, 4294930973, 4294931021, 4294931051,
4294931057, 4294931063, 4294931219, 4294931273, 4294931339, 4294931423, 4294931441, 4294931453, 4294931567,
4294931639, 4294931717, 4294931897, 4294931969, 4294932023, 4294932053, 4294932239, 4294932299, 4294932443,
4294932671, 4294932677, 4294932731, 4294932743, 4294932767, 4294932773, 4294932779, 4294932881, 4294932899,
4294932929, 4294933067, 4294933277, 4294933307, 4294933343, 4294933451, 4294933523, 4294933763, 4294933793,
4294933829, 4294933847, 4294933871, 4294933997, 4294934033, 4294934111, 4294934207, 4294934243, 4294934267,
4294934279, 4294934291, 4294934327, 4294934363, 4294934423, 4294934489, 4294934561, 4294934867, 4294934921,
4294934969, 4294935137, 4294935239, 4294935299, 4294935431, 4294935539, 4294935629, 4294935701, 4294935791,
4294935797, 4294935803, 4294935959, 4294936001, 4294936007, 4294936037, 4294936079, 4294936127, 4294936163,
4294936247, 4294936307, 4294936331, 4294936409, 4294936451, 4294936601, 4294936607, 4294936619, 4294936667,
4294936709, 4294936733, 4294936751, 4294936763, 4294936829, 4294936937, 4294936997, 4294937027, 4294937051,
4294937093, 4294937177, 4294937213, 4294937291, 4294937381, 4294937417, 4294937429, 4294937681, 4294937693,
4294937753, 4294937771, 4294937813, 4294937837, 4294937891, 4294937969, 4294938071, 4294938101, 4294938323,
4294938371, 4294938401, 4294938467, 4294938473, 4294938521, 4294938599, 4294938731, 4294938779, 4294938833,
4294938899, 4294938977, 4294938983, 4294939067, 4294939127, 4294939223, 4294939277, 4294939331, 4294939337,
4294939391, 4294939457, 4294939559, 4294939673, 4294939691, 4294939901, 4294939991, 4294940087, 4294940093,
4294940189, 4294940213, 4294940417, 4294940657, 4294940699, 4294940753, 4294940801, 4294940873, 4294940951,
4294941047, 4294941143, 4294941161, 4294941227, 4294941281, 4294941377, 4294941509, 4294941551, 4294941701,
4294941731, 4294941767, 4294941911, 4294941923, 4294942043, 4294942139, 4294942313, 4294942343, 4294942373,
4294942427, 4294942529, 4294942601, 4294942649, 4294942673, 4294942679, 4294942733, 4294942769, 4294942811,
4294942961, 4294943129, 4294943141, 4294943219, 4294943369, 4294943423, 4294943471, 4294943651, 4294943687,
4294943717, 4294943729, 4294943747, 4294943759, 4294943813, 4294943819, 4294943891, 4294944077, 4294944191,
4294944233, 4294944239, 4294944353, 4294944389, 4294944581, 4294944623, 4294944629, 4294944659, 4294944821,
4294945031, 4294945157, 4294945211, 4294945229, 4294945301, 4294945337, 4294945343, 4294945511, 4294945547,
4294945667, 4294945709, 4294945757, 4294945841, 4294945991, 4294946033, 4294946099, 4294946153, 4294946477,
4294946687, 4294946747, 4294946957, 4294946993, 4294947023, 4294947131, 4294947167, 4294947287, 4294947311,
4294947413, 4294947581, 4294947599, 4294947671, 4294947851, 4294947959, 4294948067, 4294948073, 4294948193,
4294948259, 4294948421, 4294948451, 4294948613, 4294948673, 4294948883, 4294949027, 4294949057, 4294949069,
4294949519, 4294949531, 4294949603, 4294949609, 4294949627, 4294949693, 4294949729, 4294949741, 4294949807,
4294949921, 4294949939, 4294949981, 4294949993, 4294950083, 4294950173, 4294950197, 4294950251, 4294950287,
4294950317, 4294950323, 4294950329, 4294950581, 4294950593, 4294950617, 4294950629, 4294950713, 4294950929,
4294951151, 4294951163, 4294951169, 4294951379, 4294951583, 4294951613, 4294951853, 4294951907, 4294951913,
4294951937, 4294951961, 4294952063, 4294952183, 4294952393, 4294952543, 4294952549, 4294952597, 4294952627,
4294952687, 4294952723, 4294952729, 4294952789, 4294952819, 4294952873, 4294952891, 4294952903, 4294952969,
4294952999, 4294953023, 4294953107, 4294953173, 4294953281, 4294953341, 4294953431, 4294953599, 4294953689,
4294953719, 4294953827, 4294953887, 4294953977, 4294954073, 4294954079, 4294954157, 4294954217, 4294954283,
4294954607, 4294954667, 4294954859, 4294954901, 4294954973, 4294955081, 4294955237, 4294955273, 4294955327,
4294955441, 4294955507, 4294955591, 4294955789, 4294955831, 4294955837, 4294955927, 4294955963, 4294955969,
4294955987, 4294956041, 4294956047, 4294956197, 4294956323, 4294956359, 4294956551, 4294956593, 4294956623,
4294956629, 4294956641, 4294956719, 4294956761, 4294956767, 4294956797, 4294956821, 4294956833, 4294957037,
4294957079, 4294957103, 4294957181, 4294957349, 4294957379, 4294957433, 4294957463, 4294957511, 4294957577,
4294957727, 4294957859, 4294957877, 4294958039, 4294958153, 4294958309, 4294958417, 4294958441, 4294958693,
4294958717, 4294958753, 4294958903, 4294958909, 4294959017, 4294959071, 4294959107, 4294959161, 4294959257,
4294959299, 4294959329, 4294959431, 4294959593, 4294959599, 4294959659, 4294959893, 4294959917, 4294959983,
4294960001, 4294960031, 4294960061, 4294960079, 4294960097, 4294960271, 4294960283, 4294960349, 4294960367,
4294960421, 4294960529, 4294960541, 4294960583, 4294960613, 4294960673, 4294960691, 4294960697, 4294960787,
4294960919, 4294961003, 4294961039, 4294961153, 4294961159, 4294961171, 4294961321, 4294961411, 4294961471,
4294961507, 4294961537, 4294961669, 4294961717, 4294961741, 4294961873, 4294962059, 4294962137, 4294962167,
4294962263, 4294962281, 4294962311, 4294962341, 4294962413, 4294962521, 4294962563, 4294962761, 4294962893,
4294963103, 4294963163, 4294963223, 4294963313, 4294963349, 4294963427, 4294963547, 4294963559, 4294963721,
4294963799, 4294963817, 4294963901, 4294963919, 4294964021, 4294964279, 4294964297, 4294964363, 4294964387,
4294964411, 4294964567, 4294964603, 4294964687, 4294964777, 4294965041, 4294965071, 4294965119, 4294965221,
4294965251, 4294965287, 4294965413, 4294965569, 4294965647, 4294965671, 4294965689, 4294965779, 4294965839,
4294965893, 4294966091, 4294966109, 4294966127, 4294966157, 4294966187, 4294966199, 4294966211, 4294966403,
4294966457, 4294966499, 4294966541, 4294966637, 4294966661, 4294966739, 4294966823, 4294966883, 4294966901,
4294966961, 4294967027, 4294967087, 4294967099, 4294967123, 4294967153, 4294967249
};
#ifdef ZT_NO_IEEE_DOUBLE #ifdef ZT_NO_IEEE_DOUBLE
@ -69,8 +163,8 @@ static uint64_t mulmod64(uint64_t a, uint64_t b, const uint64_t m)
* performs fairly equally across CPUs. */ * performs fairly equally across CPUs. */
ZT_INLINE uint64_t mulmod52(uint64_t a, const uint64_t b, const uint64_t m, const double mf) ZT_INLINE uint64_t mulmod52(uint64_t a, const uint64_t b, const uint64_t m, const double mf)
{ {
a = ( ( a * b ) - ( ((uint64_t)(((double)a * (double)b) / mf) - 1) * m ) ); a = ((a * b) - (((uint64_t)(((double)a * (double)b) / mf) - 1) * m));
//a -= m * (uint64_t)(a > m); // faster on some systems, but slower on newer cores // a -= m * (uint64_t)(a > m); // faster on some systems, but slower on newer cores
a %= m; a %= m;
return a; return a;
} }
@ -87,7 +181,8 @@ ZT_INLINE uint64_t modpow52(uint64_t a, uint64_t e, const uint64_t m, const doub
} }
if (likely((e >>= 1U) != 0)) { if (likely((e >>= 1U) != 0)) {
a = mulmod52(a, a, m, mf); a = mulmod52(a, a, m, mf);
} else { }
else {
break; break;
} }
} }

View file

@ -57,6 +57,6 @@ uint64_t delay(const uint8_t challenge[32], unsigned long rounds);
bool verify(const uint8_t challenge[32], unsigned long rounds, uint64_t proof); bool verify(const uint8_t challenge[32], unsigned long rounds, uint64_t proof);
} // namespace MIMC52 } // namespace MIMC52
} // namespcae ZeroTier } // namespace ZeroTier
#endif #endif

View file

@ -11,26 +11,31 @@
*/ */
/****/ /****/
#include <algorithm>
#include "Member.hpp" #include "Member.hpp"
#include "Context.hpp" #include "Context.hpp"
#include "Peer.hpp" #include "Peer.hpp"
#include "Topology.hpp" #include "Topology.hpp"
#include <algorithm>
namespace ZeroTier { namespace ZeroTier {
Member::Member() : Member::Member()
m_comRevocationThreshold(0), : m_comRevocationThreshold(0)
m_lastPushedCredentials(0), , m_lastPushedCredentials(0)
m_comAgreementLocalTimestamp(0), , m_comAgreementLocalTimestamp(0)
m_comAgreementRemoteTimestamp(0) , m_comAgreementRemoteTimestamp(0)
{ {
} }
void Member::pushCredentials(const Context &ctx, const CallContext &cc, const SharedPtr< Peer > &to, const NetworkConfig &nconf) void Member::pushCredentials(
const Context& ctx,
const CallContext& cc,
const SharedPtr<Peer>& to,
const NetworkConfig& nconf)
{ {
if (!nconf.com) // sanity check if (! nconf.com) // sanity check
return; return;
#if 0 #if 0
@ -115,29 +120,45 @@ void Member::pushCredentials(const Context &ctx, const CallContext &cc, const Sh
m_lastPushedCredentials = cc.ticks; m_lastPushedCredentials = cc.ticks;
} }
void Member::clean(const NetworkConfig &nconf) void Member::clean(const NetworkConfig& nconf)
{ {
m_cleanCredImpl< TagCredential >(nconf, m_remoteTags); m_cleanCredImpl<TagCredential>(nconf, m_remoteTags);
m_cleanCredImpl< CapabilityCredential >(nconf, m_remoteCaps); m_cleanCredImpl<CapabilityCredential>(nconf, m_remoteCaps);
m_cleanCredImpl< OwnershipCredential >(nconf, m_remoteCoos); m_cleanCredImpl<OwnershipCredential>(nconf, m_remoteCoos);
} }
Member::AddCredentialResult Member::addCredential( Member::AddCredentialResult Member::addCredential(
const Context &ctx, const Context& ctx,
const CallContext &cc, const CallContext& cc,
const Identity &sourcePeerIdentity, const Identity& sourcePeerIdentity,
const NetworkConfig &nconf, const NetworkConfig& nconf,
const MembershipCredential &com) const MembershipCredential& com)
{ {
const int64_t newts = com.timestamp(); const int64_t newts = com.timestamp();
if (newts <= m_comRevocationThreshold) { if (newts <= m_comRevocationThreshold) {
ctx.t->credentialRejected(cc, 0xd9992121, com.networkId(), sourcePeerIdentity, com.id(), com.timestamp(), ZT_CREDENTIAL_TYPE_COM, ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED); ctx.t->credentialRejected(
cc,
0xd9992121,
com.networkId(),
sourcePeerIdentity,
com.id(),
com.timestamp(),
ZT_CREDENTIAL_TYPE_COM,
ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED);
return ADD_REJECTED; return ADD_REJECTED;
} }
const int64_t oldts = m_com.timestamp(); const int64_t oldts = m_com.timestamp();
if (newts < oldts) { if (newts < oldts) {
ctx.t->credentialRejected(cc, 0xd9928192, com.networkId(), sourcePeerIdentity, com.id(), com.timestamp(), ZT_CREDENTIAL_TYPE_COM, ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST); ctx.t->credentialRejected(
cc,
0xd9928192,
com.networkId(),
sourcePeerIdentity,
com.id(),
com.timestamp(),
ZT_CREDENTIAL_TYPE_COM,
ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST);
return ADD_REJECTED; return ADD_REJECTED;
} }
if ((newts == oldts) && (m_com == com)) if ((newts == oldts) && (m_com == com))
@ -145,13 +166,29 @@ Member::AddCredentialResult Member::addCredential(
switch (com.verify(ctx, cc)) { switch (com.verify(ctx, cc)) {
default: default:
ctx.t->credentialRejected(cc, 0x0f198241, com.networkId(), sourcePeerIdentity, com.id(), com.timestamp(), ZT_CREDENTIAL_TYPE_COM, ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID); ctx.t->credentialRejected(
cc,
0x0f198241,
com.networkId(),
sourcePeerIdentity,
com.id(),
com.timestamp(),
ZT_CREDENTIAL_TYPE_COM,
ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
return Member::ADD_REJECTED; return Member::ADD_REJECTED;
case Credential::VERIFY_OK: case Credential::VERIFY_OK:
m_com = com; m_com = com;
return ADD_ACCEPTED_NEW; return ADD_ACCEPTED_NEW;
case Credential::VERIFY_BAD_SIGNATURE: case Credential::VERIFY_BAD_SIGNATURE:
ctx.t->credentialRejected(cc, 0xbaf0aaaa, com.networkId(), sourcePeerIdentity, com.id(), com.timestamp(), ZT_CREDENTIAL_TYPE_COM, ZT_TRACE_CREDENTIAL_REJECTION_REASON_SIGNATURE_VERIFICATION_FAILED); ctx.t->credentialRejected(
cc,
0xbaf0aaaa,
com.networkId(),
sourcePeerIdentity,
com.id(),
com.timestamp(),
ZT_CREDENTIAL_TYPE_COM,
ZT_TRACE_CREDENTIAL_REJECTION_REASON_SIGNATURE_VERIFICATION_FAILED);
return ADD_REJECTED; return ADD_REJECTED;
case Credential::VERIFY_NEED_IDENTITY: case Credential::VERIFY_NEED_IDENTITY:
return ADD_DEFERRED_FOR_WHOIS; return ADD_DEFERRED_FOR_WHOIS;
@ -159,35 +196,60 @@ Member::AddCredentialResult Member::addCredential(
} }
// 3/5 of the credential types have identical addCredential() code // 3/5 of the credential types have identical addCredential() code
template< typename C > template <typename C>
static ZT_INLINE Member::AddCredentialResult _addCredImpl( static ZT_INLINE Member::AddCredentialResult _addCredImpl(
Map< uint32_t, C > &remoteCreds, Map<uint32_t, C>& remoteCreds,
const Map< uint64_t, int64_t > &revocations, const Map<uint64_t, int64_t>& revocations,
const Context &ctx, const Context& ctx,
const CallContext &cc, const CallContext& cc,
const Identity &sourcePeerIdentity, const Identity& sourcePeerIdentity,
const NetworkConfig &nconf, const NetworkConfig& nconf,
const C &cred) const C& cred)
{ {
typename Map< uint32_t, C >::const_iterator rc(remoteCreds.find(cred.id())); typename Map<uint32_t, C>::const_iterator rc(remoteCreds.find(cred.id()));
if (rc != remoteCreds.end()) { if (rc != remoteCreds.end()) {
if (rc->second.revision() > cred.revision()) { if (rc->second.revision() > cred.revision()) {
ctx.t->credentialRejected(cc, 0x40000001, nconf.networkId, sourcePeerIdentity, cred.id(), cred.revision(), C::credentialType(), ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST); ctx.t->credentialRejected(
cc,
0x40000001,
nconf.networkId,
sourcePeerIdentity,
cred.id(),
cred.revision(),
C::credentialType(),
ZT_TRACE_CREDENTIAL_REJECTION_REASON_OLDER_THAN_LATEST);
return Member::ADD_REJECTED; return Member::ADD_REJECTED;
} }
if (rc->second == cred) if (rc->second == cred)
return Member::ADD_ACCEPTED_REDUNDANT; return Member::ADD_ACCEPTED_REDUNDANT;
} }
typename Map< uint64_t, int64_t >::const_iterator rt(revocations.find(Member::credentialKey(C::credentialType(), cred.id()))); typename Map<uint64_t, int64_t>::const_iterator rt(
revocations.find(Member::credentialKey(C::credentialType(), cred.id())));
if ((rt != revocations.end()) && (rt->second >= cred.revision())) { if ((rt != revocations.end()) && (rt->second >= cred.revision())) {
ctx.t->credentialRejected(cc, 0x24248124, nconf.networkId, sourcePeerIdentity, cred.id(), cred.revision(), C::credentialType(), ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED); ctx.t->credentialRejected(
cc,
0x24248124,
nconf.networkId,
sourcePeerIdentity,
cred.id(),
cred.revision(),
C::credentialType(),
ZT_TRACE_CREDENTIAL_REJECTION_REASON_REVOKED);
return Member::ADD_REJECTED; return Member::ADD_REJECTED;
} }
switch (cred.verify(ctx, cc)) { switch (cred.verify(ctx, cc)) {
default: default:
ctx.t->credentialRejected(cc, 0x01feba012, nconf.networkId, sourcePeerIdentity, cred.id(), cred.revision(), C::credentialType(), ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID); ctx.t->credentialRejected(
cc,
0x01feba012,
nconf.networkId,
sourcePeerIdentity,
cred.id(),
cred.revision(),
C::credentialType(),
ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
return Member::ADD_REJECTED; return Member::ADD_REJECTED;
case 0: case 0:
if (rc == remoteCreds.end()) if (rc == remoteCreds.end())
@ -198,21 +260,55 @@ static ZT_INLINE Member::AddCredentialResult _addCredImpl(
} }
} }
Member::AddCredentialResult Member::addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const TagCredential &tag) Member::AddCredentialResult Member::addCredential(
{ return _addCredImpl< TagCredential >(m_remoteTags, m_revocations, ctx, cc, sourcePeerIdentity, nconf, tag); } const Context& ctx,
const CallContext& cc,
Member::AddCredentialResult Member::addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const CapabilityCredential &cap) const Identity& sourcePeerIdentity,
{ return _addCredImpl< CapabilityCredential >(m_remoteCaps, m_revocations, ctx, cc, sourcePeerIdentity, nconf, cap); } const NetworkConfig& nconf,
const TagCredential& tag)
Member::AddCredentialResult Member::addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const OwnershipCredential &coo)
{ return _addCredImpl< OwnershipCredential >(m_remoteCoos, m_revocations, ctx, cc, sourcePeerIdentity, nconf, coo); }
Member::AddCredentialResult Member::addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const RevocationCredential &rev)
{ {
int64_t *rt; return _addCredImpl<TagCredential>(m_remoteTags, m_revocations, ctx, cc, sourcePeerIdentity, nconf, tag);
}
Member::AddCredentialResult Member::addCredential(
const Context& ctx,
const CallContext& cc,
const Identity& sourcePeerIdentity,
const NetworkConfig& nconf,
const CapabilityCredential& cap)
{
return _addCredImpl<CapabilityCredential>(m_remoteCaps, m_revocations, ctx, cc, sourcePeerIdentity, nconf, cap);
}
Member::AddCredentialResult Member::addCredential(
const Context& ctx,
const CallContext& cc,
const Identity& sourcePeerIdentity,
const NetworkConfig& nconf,
const OwnershipCredential& coo)
{
return _addCredImpl<OwnershipCredential>(m_remoteCoos, m_revocations, ctx, cc, sourcePeerIdentity, nconf, coo);
}
Member::AddCredentialResult Member::addCredential(
const Context& ctx,
const CallContext& cc,
const Identity& sourcePeerIdentity,
const NetworkConfig& nconf,
const RevocationCredential& rev)
{
int64_t* rt;
switch (rev.verify(ctx, cc)) { switch (rev.verify(ctx, cc)) {
default: default:
ctx.t->credentialRejected(cc, 0x938ff009, nconf.networkId, sourcePeerIdentity, rev.id(), 0, ZT_CREDENTIAL_TYPE_REVOCATION, ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID); ctx.t->credentialRejected(
cc,
0x938ff009,
nconf.networkId,
sourcePeerIdentity,
rev.id(),
0,
ZT_CREDENTIAL_TYPE_REVOCATION,
ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
return ADD_REJECTED; return ADD_REJECTED;
case 0: { case 0: {
const ZT_CredentialType ct = rev.typeBeingRevoked(); const ZT_CredentialType ct = rev.typeBeingRevoked();
@ -234,7 +330,15 @@ Member::AddCredentialResult Member::addCredential(const Context &ctx, const Call
} }
return ADD_ACCEPTED_REDUNDANT; return ADD_ACCEPTED_REDUNDANT;
default: default:
ctx.t->credentialRejected(cc, 0x0bbbb1a4, nconf.networkId, sourcePeerIdentity, rev.id(), 0, ZT_CREDENTIAL_TYPE_REVOCATION, ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID); ctx.t->credentialRejected(
cc,
0x0bbbb1a4,
nconf.networkId,
sourcePeerIdentity,
rev.id(),
0,
ZT_CREDENTIAL_TYPE_REVOCATION,
ZT_TRACE_CREDENTIAL_REJECTION_REASON_INVALID);
return ADD_REJECTED; return ADD_REJECTED;
} }
} }
@ -243,16 +347,12 @@ Member::AddCredentialResult Member::addCredential(const Context &ctx, const Call
} }
} }
bool Member::m_isUnspoofableAddress(const NetworkConfig &nconf, const InetAddress &ip) const noexcept bool Member::m_isUnspoofableAddress(const NetworkConfig& nconf, const InetAddress& ip) const noexcept
{ {
return ( return (
ip.isV6() && ip.isV6() && nconf.ndpEmulation()
nconf.ndpEmulation() && && ((ip == InetAddress::makeIpv66plane(nconf.networkId, m_com.issuedTo().address))
( || (ip == InetAddress::makeIpv6rfc4193(nconf.networkId, m_com.issuedTo().address))));
(ip == InetAddress::makeIpv66plane(nconf.networkId, m_com.issuedTo().address)) ||
(ip == InetAddress::makeIpv6rfc4193(nconf.networkId, m_com.issuedTo().address))
)
);
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -14,14 +14,14 @@
#ifndef ZT_MEMBERSHIP_HPP #ifndef ZT_MEMBERSHIP_HPP
#define ZT_MEMBERSHIP_HPP #define ZT_MEMBERSHIP_HPP
#include "Constants.hpp"
#include "Credential.hpp"
#include "Containers.hpp"
#include "MembershipCredential.hpp"
#include "CapabilityCredential.hpp" #include "CapabilityCredential.hpp"
#include "TagCredential.hpp" #include "Constants.hpp"
#include "RevocationCredential.hpp" #include "Containers.hpp"
#include "Credential.hpp"
#include "MembershipCredential.hpp"
#include "NetworkConfig.hpp" #include "NetworkConfig.hpp"
#include "RevocationCredential.hpp"
#include "TagCredential.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -36,16 +36,9 @@ class Network;
* *
* This class is not thread safe. It must be locked externally. * This class is not thread safe. It must be locked externally.
*/ */
class Member class Member {
{ public:
public: enum AddCredentialResult { ADD_REJECTED, ADD_ACCEPTED_NEW, ADD_ACCEPTED_REDUNDANT, ADD_DEFERRED_FOR_WHOIS };
enum AddCredentialResult
{
ADD_REJECTED,
ADD_ACCEPTED_NEW,
ADD_ACCEPTED_REDUNDANT,
ADD_DEFERRED_FOR_WHOIS
};
Member(); Member();
@ -55,13 +48,16 @@ public:
* @param to Peer identity * @param to Peer identity
* @param nconf My network config * @param nconf My network config
*/ */
void pushCredentials(const Context &ctx, const CallContext &cc, const SharedPtr< Peer > &to, const NetworkConfig &nconf); void
pushCredentials(const Context& ctx, const CallContext& cc, const SharedPtr<Peer>& to, const NetworkConfig& nconf);
/** /**
* @return Time we last pushed credentials to this member * @return Time we last pushed credentials to this member
*/ */
ZT_INLINE int64_t lastPushedCredentials() const noexcept ZT_INLINE int64_t lastPushedCredentials() const noexcept
{ return m_lastPushedCredentials; } {
return m_lastPushedCredentials;
}
/** /**
* Get a remote member's tag (if we have it) * Get a remote member's tag (if we have it)
@ -70,10 +66,12 @@ public:
* @param id Tag ID * @param id Tag ID
* @return Pointer to tag or NULL if not found * @return Pointer to tag or NULL if not found
*/ */
ZT_INLINE const TagCredential *getTag(const NetworkConfig &nconf, const uint32_t id) const noexcept ZT_INLINE const TagCredential* getTag(const NetworkConfig& nconf, const uint32_t id) const noexcept
{ {
Map< uint32_t, TagCredential >::const_iterator t(m_remoteTags.find(id)); Map<uint32_t, TagCredential>::const_iterator t(m_remoteTags.find(id));
return (((t != m_remoteTags.end()) && (m_isCredentialTimestampValid(nconf, t->second))) ? &(t->second) : (TagCredential *)0); return (
((t != m_remoteTags.end()) && (m_isCredentialTimestampValid(nconf, t->second))) ? &(t->second)
: (TagCredential*)0);
} }
/** /**
@ -81,13 +79,15 @@ public:
* *
* @param nconf Current network configuration * @param nconf Current network configuration
*/ */
void clean(const NetworkConfig &nconf); void clean(const NetworkConfig& nconf);
/** /**
* Generates a key for internal use in indexing credentials by type and credential ID * Generates a key for internal use in indexing credentials by type and credential ID
*/ */
static ZT_INLINE uint64_t credentialKey(const ZT_CredentialType &t, const uint32_t i) noexcept static ZT_INLINE uint64_t credentialKey(const ZT_CredentialType& t, const uint32_t i) noexcept
{ return (((uint64_t)t << 32U) | (uint64_t)i); } {
return (((uint64_t)t << 32U) | (uint64_t)i);
}
/** /**
* Check whether the peer represented by this Membership owns a given address * Check whether the peer represented by this Membership owns a given address
@ -97,12 +97,11 @@ public:
* @param r Resource to check * @param r Resource to check
* @return True if this peer has a certificate of ownership for the given resource * @return True if this peer has a certificate of ownership for the given resource
*/ */
template< typename T > template <typename T> ZT_INLINE bool peerOwnsAddress(const NetworkConfig& nconf, const T& r) const noexcept
ZT_INLINE bool peerOwnsAddress(const NetworkConfig &nconf, const T &r) const noexcept
{ {
if (m_isUnspoofableAddress(nconf, r)) if (m_isUnspoofableAddress(nconf, r))
return true; return true;
for (Map< uint32_t, OwnershipCredential >::const_iterator i(m_remoteCoos.begin()); i != m_remoteCoos.end(); ++i) { for (Map<uint32_t, OwnershipCredential>::const_iterator i(m_remoteCoos.begin()); i != m_remoteCoos.end(); ++i) {
if (m_isCredentialTimestampValid(nconf, i->second) && (i->second.owns(r))) if (m_isCredentialTimestampValid(nconf, i->second) && (i->second.owns(r)))
return true; return true;
} }
@ -114,9 +113,10 @@ public:
* *
* @param localCom * @param localCom
*/ */
ZT_INLINE bool certificateOfMembershipAgress(const MembershipCredential &localCom, const Identity &remoteIdentity) ZT_INLINE bool certificateOfMembershipAgress(const MembershipCredential& localCom, const Identity& remoteIdentity)
{ {
if ((m_comAgreementLocalTimestamp == localCom.timestamp()) && (m_comAgreementRemoteTimestamp == m_com.timestamp())) if ((m_comAgreementLocalTimestamp == localCom.timestamp())
&& (m_comAgreementRemoteTimestamp == m_com.timestamp()))
return true; return true;
if (m_com.agreesWith(localCom)) { if (m_com.agreesWith(localCom)) {
// SECURITY: newer network controllers embed the full fingerprint into the COM. If we are // SECURITY: newer network controllers embed the full fingerprint into the COM. If we are
@ -129,7 +129,8 @@ public:
if (localCom.issuedTo().haveHash()) { if (localCom.issuedTo().haveHash()) {
if (localCom.issuedTo() != m_com.issuedTo()) if (localCom.issuedTo() != m_com.issuedTo())
return false; return false;
} else { }
else {
// LEGACY: support networks run by old controllers. // LEGACY: support networks run by old controllers.
if (localCom.issuedTo().address != m_com.issuedTo().address) if (localCom.issuedTo().address != m_com.issuedTo().address)
return false; return false;
@ -145,41 +146,70 @@ public:
return false; return false;
} }
AddCredentialResult addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const MembershipCredential &com); AddCredentialResult addCredential(
AddCredentialResult addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const TagCredential &tag); const Context& ctx,
AddCredentialResult addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const CapabilityCredential &cap); const CallContext& cc,
AddCredentialResult addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const OwnershipCredential &coo); const Identity& sourcePeerIdentity,
AddCredentialResult addCredential(const Context &ctx, const CallContext &cc, const Identity &sourcePeerIdentity, const NetworkConfig &nconf, const RevocationCredential &rev); const NetworkConfig& nconf,
const MembershipCredential& com);
AddCredentialResult addCredential(
const Context& ctx,
const CallContext& cc,
const Identity& sourcePeerIdentity,
const NetworkConfig& nconf,
const TagCredential& tag);
AddCredentialResult addCredential(
const Context& ctx,
const CallContext& cc,
const Identity& sourcePeerIdentity,
const NetworkConfig& nconf,
const CapabilityCredential& cap);
AddCredentialResult addCredential(
const Context& ctx,
const CallContext& cc,
const Identity& sourcePeerIdentity,
const NetworkConfig& nconf,
const OwnershipCredential& coo);
AddCredentialResult addCredential(
const Context& ctx,
const CallContext& cc,
const Identity& sourcePeerIdentity,
const NetworkConfig& nconf,
const RevocationCredential& rev);
private: private:
// This returns true if a resource is an IPv6 NDP-emulated address. These embed the ZT // 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 // address of the peer and therefore cannot be spoofed, causing peerOwnsAddress() to
// always return true for them. A certificate is not required for these. // always return true for them. A certificate is not required for these.
ZT_INLINE bool m_isUnspoofableAddress(const NetworkConfig &nconf, const MAC &m) const noexcept ZT_INLINE bool m_isUnspoofableAddress(const NetworkConfig& nconf, const MAC& m) const noexcept
{ return false; } {
return false;
}
bool m_isUnspoofableAddress(const NetworkConfig &nconf, const InetAddress &ip) const noexcept; 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 // This compares the remote credential's timestamp to the timestamp in our network config
// plus or minus the permitted maximum timestamp delta. // plus or minus the permitted maximum timestamp delta.
template< typename C > template <typename C>
ZT_INLINE bool m_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.revision(); const int64_t ts = remoteCredential.revision();
if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) { if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts))
Map< uint64_t, int64_t >::const_iterator threshold(m_revocations.find(credentialKey(C::credentialType(), remoteCredential.id()))); <= nconf.credentialTimeMaxDelta) {
Map<uint64_t, int64_t>::const_iterator threshold(
m_revocations.find(credentialKey(C::credentialType(), remoteCredential.id())));
return ((threshold == m_revocations.end()) || (ts > threshold->second)); return ((threshold == m_revocations.end()) || (ts > threshold->second));
} }
return false; return false;
} }
template< typename C > template <typename C> ZT_INLINE void m_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();) { for (typename Map<uint32_t, C>::iterator i(remoteCreds.begin()); i != remoteCreds.end();) {
if (!m_isCredentialTimestampValid(nconf, i->second)) if (! m_isCredentialTimestampValid(nconf, i->second))
remoteCreds.erase(i++); remoteCreds.erase(i++);
else ++i; else
++i;
} }
} }
@ -196,27 +226,27 @@ private:
MembershipCredential m_com; MembershipCredential m_com;
// Revocations by credentialKey() // Revocations by credentialKey()
Map< uint64_t, int64_t > m_revocations; Map<uint64_t, int64_t> m_revocations;
// Remote credentials that we have received from this member (and that are valid) // Remote credentials that we have received from this member (and that are valid)
Map< uint32_t, TagCredential > m_remoteTags; Map<uint32_t, TagCredential> m_remoteTags;
Map< uint32_t, CapabilityCredential > m_remoteCaps; Map<uint32_t, CapabilityCredential> m_remoteCaps;
Map< uint32_t, OwnershipCredential > m_remoteCoos; Map<uint32_t, OwnershipCredential> m_remoteCoos;
public:
class CapabilityIterator
{
public: public:
ZT_INLINE CapabilityIterator(Member &m, const NetworkConfig &nconf) noexcept: class CapabilityIterator {
m_hti(m.m_remoteCaps.begin()), public:
m_parent(m), ZT_INLINE CapabilityIterator(Member& m, const NetworkConfig& nconf) noexcept
m_nconf(nconf) : m_hti(m.m_remoteCaps.begin())
{} , m_parent(m)
, m_nconf(nconf)
{
}
ZT_INLINE CapabilityCredential *next() noexcept ZT_INLINE CapabilityCredential* next() noexcept
{ {
while (m_hti != m_parent.m_remoteCaps.end()) { while (m_hti != m_parent.m_remoteCaps.end()) {
Map< uint32_t, CapabilityCredential >::iterator i(m_hti++); Map<uint32_t, CapabilityCredential>::iterator i(m_hti++);
if (m_parent.m_isCredentialTimestampValid(m_nconf, i->second)) if (m_parent.m_isCredentialTimestampValid(m_nconf, i->second))
return &(i->second); return &(i->second);
} }
@ -224,9 +254,9 @@ public:
} }
private: private:
Map< uint32_t, CapabilityCredential >::iterator m_hti; Map<uint32_t, CapabilityCredential>::iterator m_hti;
Member &m_parent; Member& m_parent;
const NetworkConfig &m_nconf; const NetworkConfig& m_nconf;
}; };
}; };

View file

@ -15,15 +15,21 @@
namespace ZeroTier { namespace ZeroTier {
MembershipCredential::MembershipCredential(const int64_t timestamp, const int64_t timestampMaxDelta, const uint64_t nwid, const Identity &issuedTo) noexcept: // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) MembershipCredential::MembershipCredential(
m_timestamp(timestamp), const int64_t timestamp,
m_timestampMaxDelta(timestampMaxDelta), const int64_t timestampMaxDelta,
m_networkId(nwid), const uint64_t nwid,
m_issuedTo(issuedTo.fingerprint()), const Identity& issuedTo) noexcept
m_signatureLength(0) : // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
{} m_timestamp(timestamp)
, m_timestampMaxDelta(timestampMaxDelta)
, m_networkId(nwid)
, m_issuedTo(issuedTo.fingerprint())
, m_signatureLength(0)
{
}
bool MembershipCredential::agreesWith(const MembershipCredential &other) const noexcept bool MembershipCredential::agreesWith(const MembershipCredential& other) const noexcept
{ {
// NOTE: we always do explicit absolute value with an if() since llabs() can have overflow // NOTE: we always do explicit absolute value with an if() since llabs() can have overflow
// conditions that could introduce a vulnerability. // conditions that could introduce a vulnerability.
@ -31,27 +37,35 @@ bool MembershipCredential::agreesWith(const MembershipCredential &other) const n
if (other.m_timestamp > m_timestamp) { if (other.m_timestamp > m_timestamp) {
if ((other.m_timestamp - m_timestamp) > std::min(m_timestampMaxDelta, other.m_timestampMaxDelta)) if ((other.m_timestamp - m_timestamp) > std::min(m_timestampMaxDelta, other.m_timestampMaxDelta))
return false; return false;
} else { }
else {
if ((m_timestamp - other.m_timestamp) > std::min(m_timestampMaxDelta, other.m_timestampMaxDelta)) if ((m_timestamp - other.m_timestamp) > std::min(m_timestampMaxDelta, other.m_timestampMaxDelta))
return false; return false;
} }
// us <> them // us <> them
for (FCV<p_Qualifier, ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS>::const_iterator i(m_additionalQualifiers.begin()); i != m_additionalQualifiers.end(); ++i) { for (FCV<p_Qualifier, ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS>::const_iterator i(
m_additionalQualifiers.begin());
i != m_additionalQualifiers.end();
++i) {
if (i->delta != 0xffffffffffffffffULL) { if (i->delta != 0xffffffffffffffffULL) {
const uint64_t *v2 = nullptr; const uint64_t* v2 = nullptr;
for (FCV<p_Qualifier, ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS>::const_iterator j(other.m_additionalQualifiers.begin()); j != other.m_additionalQualifiers.end(); ++i) { for (FCV<p_Qualifier, ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS>::const_iterator j(
other.m_additionalQualifiers.begin());
j != other.m_additionalQualifiers.end();
++i) {
if (j->id == i->id) { if (j->id == i->id) {
v2 = &(j->value); v2 = &(j->value);
break; break;
} }
} }
if (!v2) if (! v2)
return false; return false;
if (*v2 > i->value) { if (*v2 > i->value) {
if ((*v2 - i->value) > i->delta) if ((*v2 - i->value) > i->delta)
return false; return false;
} else { }
else {
if ((i->value - *v2) > i->delta) if ((i->value - *v2) > i->delta)
return false; return false;
} }
@ -59,21 +73,28 @@ bool MembershipCredential::agreesWith(const MembershipCredential &other) const n
} }
// them <> us (we need a second pass in case they have qualifiers we don't or vice versa) // them <> us (we need a second pass in case they have qualifiers we don't or vice versa)
for (FCV<p_Qualifier, ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS>::const_iterator i(other.m_additionalQualifiers.begin()); i != other.m_additionalQualifiers.end(); ++i) { for (FCV<p_Qualifier, ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS>::const_iterator i(
other.m_additionalQualifiers.begin());
i != other.m_additionalQualifiers.end();
++i) {
if (i->delta != 0xffffffffffffffffULL) { if (i->delta != 0xffffffffffffffffULL) {
const uint64_t *v2 = nullptr; const uint64_t* v2 = nullptr;
for (FCV<p_Qualifier, ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS>::const_iterator j(m_additionalQualifiers.begin()); j != m_additionalQualifiers.end(); ++i) { for (FCV<p_Qualifier, ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS>::const_iterator j(
m_additionalQualifiers.begin());
j != m_additionalQualifiers.end();
++i) {
if (j->id == i->id) { if (j->id == i->id) {
v2 = &(j->value); v2 = &(j->value);
break; break;
} }
} }
if (!v2) if (! v2)
return false; return false;
if (*v2 > i->value) { if (*v2 > i->value) {
if ((*v2 - i->value) > i->delta) if ((*v2 - i->value) > i->delta)
return false; return false;
} else { }
else {
if ((i->value - *v2) > i->delta) if ((i->value - *v2) > i->delta)
return false; return false;
} }
@ -85,7 +106,7 @@ bool MembershipCredential::agreesWith(const MembershipCredential &other) const n
return (other.m_networkId == m_networkId) && (m_networkId != 0) && (other.m_issuedTo.address != m_issuedTo.address); return (other.m_networkId == m_networkId) && (m_networkId != 0) && (other.m_issuedTo.address != m_issuedTo.address);
} }
bool MembershipCredential::sign(const Identity &with) noexcept bool MembershipCredential::sign(const Identity& with) noexcept
{ {
m_signedBy = with.address(); m_signedBy = with.address();
uint64_t buf[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX / 8]; uint64_t buf[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX / 8];
@ -102,14 +123,14 @@ int MembershipCredential::marshal(uint8_t data[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_
// equality compare, and the address of the issued-to node as an informational tuple. // equality compare, and the address of the issued-to node as an informational tuple.
int p = 3; int p = 3;
Utils::storeBigEndian<uint64_t>(data + p, 0); Utils::storeBigEndian<uint64_t>(data + p, 0);
Utils::storeBigEndian<uint64_t>(data + p + 8, (uint64_t) m_timestamp); Utils::storeBigEndian<uint64_t>(data + p + 8, (uint64_t)m_timestamp);
Utils::storeBigEndian<uint64_t>(data + p + 16, (uint64_t) m_timestampMaxDelta); Utils::storeBigEndian<uint64_t>(data + p + 16, (uint64_t)m_timestampMaxDelta);
Utils::storeBigEndian<uint64_t>(data + p + 24, 1); Utils::storeBigEndian<uint64_t>(data + p + 24, 1);
Utils::storeBigEndian<uint64_t>(data + p + 32, m_networkId); Utils::storeBigEndian<uint64_t>(data + p + 32, m_networkId);
Utils::storeBigEndian<uint64_t>(data + p + 40, 0); Utils::storeBigEndian<uint64_t>(data + p + 40, 0);
Utils::storeBigEndian<uint64_t>(data + p + 48, 2); Utils::storeBigEndian<uint64_t>(data + p + 48, 2);
Utils::storeBigEndian<uint64_t>(data + p + 56, m_issuedTo.address); Utils::storeBigEndian<uint64_t>(data + p + 56, m_issuedTo.address);
Utils::storeMachineEndian< uint64_t >(data + p + 64, 0xffffffffffffffffULL); Utils::storeMachineEndian<uint64_t>(data + p + 64, 0xffffffffffffffffULL);
p += 72; p += 72;
if (v2) { if (v2) {
@ -117,13 +138,16 @@ int MembershipCredential::marshal(uint8_t data[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_
Utils::storeBigEndian<uint16_t>(data + 1, 3); Utils::storeBigEndian<uint16_t>(data + 1, 3);
Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(data + p, m_issuedTo.hash); Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(data + p, m_issuedTo.hash);
p += 48; p += 48;
} else { }
else {
// V1 marshal format must shove everything into tuples, resulting in nine. // V1 marshal format must shove everything into tuples, resulting in nine.
Utils::storeBigEndian<uint16_t>(data + 1, 9); Utils::storeBigEndian<uint16_t>(data + 1, 9);
for (int k = 0;k < 6;++k) { for (int k = 0; k < 6; ++k) {
Utils::storeBigEndian<uint64_t>(data + p, (uint64_t) k + 3); Utils::storeBigEndian<uint64_t>(data + p, (uint64_t)k + 3);
Utils::storeMachineEndian< uint64_t >(data + p + 8, Utils::loadMachineEndian< uint64_t >(m_issuedTo.hash + (k * 8))); Utils::storeMachineEndian<uint64_t>(
Utils::storeMachineEndian< uint64_t >(data + p + 16, 0xffffffffffffffffULL); data + p + 8,
Utils::loadMachineEndian<uint64_t>(m_issuedTo.hash + (k * 8)));
Utils::storeMachineEndian<uint64_t>(data + p + 16, 0xffffffffffffffffULL);
p += 24; p += 24;
} }
} }
@ -133,11 +157,12 @@ int MembershipCredential::marshal(uint8_t data[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_
if (v2) { if (v2) {
// V2 marshal format prefixes signatures with a 16-bit length to support future signature types. // V2 marshal format prefixes signatures with a 16-bit length to support future signature types.
Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_signatureLength); Utils::storeBigEndian<uint16_t>(data + p, (uint16_t)m_signatureLength);
p += 2; p += 2;
Utils::copy(data + p, m_signature, m_signatureLength); Utils::copy(data + p, m_signature, m_signatureLength);
p += (int)m_signatureLength; p += (int)m_signatureLength;
} else { }
else {
// V1 only supports 96-byte signature fields. // V1 only supports 96-byte signature fields.
Utils::copy<96>(data + p, m_signature); Utils::copy<96>(data + p, m_signature);
p += 96; p += 96;
@ -146,7 +171,7 @@ int MembershipCredential::marshal(uint8_t data[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_
return p; return p;
} }
int MembershipCredential::unmarshal(const uint8_t *data, int len) noexcept int MembershipCredential::unmarshal(const uint8_t* data, int len) noexcept
{ {
if (len < (1 + 2 + 72)) if (len < (1 + 2 + 72))
return -1; return -1;
@ -157,7 +182,7 @@ int MembershipCredential::unmarshal(const uint8_t *data, int len) noexcept
if ((numq < 3) || (numq > (ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS + 3))) if ((numq < 3) || (numq > (ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS + 3)))
return -1; return -1;
int p = 3; int p = 3;
for (unsigned int q = 0;q < numq;++q) { for (unsigned int q = 0; q < numq; ++q) {
if ((p + 24) > len) if ((p + 24) > len)
return -1; return -1;
const uint64_t id = Utils::loadBigEndian<uint64_t>(data + p); const uint64_t id = Utils::loadBigEndian<uint64_t>(data + p);
@ -168,8 +193,8 @@ int MembershipCredential::unmarshal(const uint8_t *data, int len) noexcept
p += 8; // NOLINT(hicpp-use-auto,modernize-use-auto) p += 8; // NOLINT(hicpp-use-auto,modernize-use-auto)
switch (id) { switch (id) {
case 0: case 0:
m_timestamp = (int64_t) value; m_timestamp = (int64_t)value;
m_timestampMaxDelta = (int64_t) delta; m_timestampMaxDelta = (int64_t)delta;
break; break;
case 1: case 1:
m_networkId = value; m_networkId = value;
@ -214,7 +239,8 @@ int MembershipCredential::unmarshal(const uint8_t *data, int len) noexcept
m_signatureLength = 96; m_signatureLength = 96;
Utils::copy<96>(m_signature, data + p); Utils::copy<96>(m_signature, data + p);
return p + 96; return p + 96;
} else if (data[0] == 2) { }
else if (data[0] == 2) {
if ((p + 48) > len) if ((p + 48) > len)
return -1; return -1;
Utils::copy<48>(m_issuedTo.hash, data + p); Utils::copy<48>(m_issuedTo.hash, data + p);
@ -222,16 +248,16 @@ int MembershipCredential::unmarshal(const uint8_t *data, int len) noexcept
if ((p + 2) > len) if ((p + 2) > len)
return -1; return -1;
m_signatureLength = Utils::loadBigEndian<uint16_t>(data + p); m_signatureLength = Utils::loadBigEndian<uint16_t>(data + p);
if ((m_signatureLength > (unsigned int) sizeof(m_signature)) || ((p + (int) m_signatureLength) > len)) if ((m_signatureLength > (unsigned int)sizeof(m_signature)) || ((p + (int)m_signatureLength) > len))
return -1; return -1;
Utils::copy(m_signature, data + p, m_signatureLength); Utils::copy(m_signature, data + p, m_signatureLength);
return p + (int) m_signatureLength; return p + (int)m_signatureLength;
} }
return -1; return -1;
} }
unsigned int MembershipCredential::m_fillSigningBuf(uint64_t *buf) const noexcept unsigned int MembershipCredential::m_fillSigningBuf(uint64_t* buf) const noexcept
{ {
const uint64_t informational = 0xffffffffffffffffULL; const uint64_t informational = 0xffffffffffffffffULL;
@ -243,8 +269,8 @@ unsigned int MembershipCredential::m_fillSigningBuf(uint64_t *buf) const noexcep
// The standard three tuples that must begin every COM. // The standard three tuples that must begin every COM.
buf[0] = 0; buf[0] = 0;
buf[1] = Utils::hton((uint64_t) m_timestamp); buf[1] = Utils::hton((uint64_t)m_timestamp);
buf[2] = Utils::hton((uint64_t) m_timestampMaxDelta); buf[2] = Utils::hton((uint64_t)m_timestampMaxDelta);
buf[3] = ZT_CONST_TO_BE_UINT64(1); buf[3] = ZT_CONST_TO_BE_UINT64(1);
buf[4] = Utils::hton(m_networkId); buf[4] = Utils::hton(m_networkId);
buf[5] = 0; buf[5] = 0;
@ -258,26 +284,29 @@ unsigned int MembershipCredential::m_fillSigningBuf(uint64_t *buf) const noexcep
// embeded as a series of informational tuples. // embeded as a series of informational tuples.
if (m_issuedTo.haveHash()) { if (m_issuedTo.haveHash()) {
buf[p++] = ZT_CONST_TO_BE_UINT64(3); buf[p++] = ZT_CONST_TO_BE_UINT64(3);
buf[p++] = Utils::loadMachineEndian< uint64_t >(m_issuedTo.hash); buf[p++] = Utils::loadMachineEndian<uint64_t>(m_issuedTo.hash);
buf[p++] = informational; buf[p++] = informational;
buf[p++] = ZT_CONST_TO_BE_UINT64(4); buf[p++] = ZT_CONST_TO_BE_UINT64(4);
buf[p++] = Utils::loadMachineEndian< uint64_t >(m_issuedTo.hash + 8); buf[p++] = Utils::loadMachineEndian<uint64_t>(m_issuedTo.hash + 8);
buf[p++] = informational; buf[p++] = informational;
buf[p++] = ZT_CONST_TO_BE_UINT64(5); buf[p++] = ZT_CONST_TO_BE_UINT64(5);
buf[p++] = Utils::loadMachineEndian< uint64_t >(m_issuedTo.hash + 16); buf[p++] = Utils::loadMachineEndian<uint64_t>(m_issuedTo.hash + 16);
buf[p++] = informational; buf[p++] = informational;
buf[p++] = ZT_CONST_TO_BE_UINT64(6); buf[p++] = ZT_CONST_TO_BE_UINT64(6);
buf[p++] = Utils::loadMachineEndian< uint64_t >(m_issuedTo.hash + 24); buf[p++] = Utils::loadMachineEndian<uint64_t>(m_issuedTo.hash + 24);
buf[p++] = informational; buf[p++] = informational;
buf[p++] = ZT_CONST_TO_BE_UINT64(7); buf[p++] = ZT_CONST_TO_BE_UINT64(7);
buf[p++] = Utils::loadMachineEndian< uint64_t >(m_issuedTo.hash + 32); buf[p++] = Utils::loadMachineEndian<uint64_t>(m_issuedTo.hash + 32);
buf[p++] = informational; buf[p++] = informational;
buf[p++] = ZT_CONST_TO_BE_UINT64(8); buf[p++] = ZT_CONST_TO_BE_UINT64(8);
buf[p++] = Utils::loadMachineEndian< uint64_t >(m_issuedTo.hash + 40); buf[p++] = Utils::loadMachineEndian<uint64_t>(m_issuedTo.hash + 40);
buf[p++] = informational; buf[p++] = informational;
} }
for (FCV<p_Qualifier, ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS>::const_iterator i(m_additionalQualifiers.begin()); i != m_additionalQualifiers.end(); ++i) { // NOLINT(modernize-loop-convert) for (FCV<p_Qualifier, ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS>::const_iterator i(
m_additionalQualifiers.begin());
i != m_additionalQualifiers.end();
++i) { // NOLINT(modernize-loop-convert)
buf[p++] = Utils::hton(i->id); buf[p++] = Utils::hton(i->id);
buf[p++] = Utils::hton(i->value); buf[p++] = Utils::hton(i->value);
buf[p++] = Utils::hton(i->delta); buf[p++] = Utils::hton(i->delta);

View file

@ -14,23 +14,24 @@
#ifndef ZT_CERTIFICATEOFMEMBERSHIP_HPP #ifndef ZT_CERTIFICATEOFMEMBERSHIP_HPP
#define ZT_CERTIFICATEOFMEMBERSHIP_HPP #define ZT_CERTIFICATEOFMEMBERSHIP_HPP
#include <string>
#include <stdexcept>
#include <algorithm>
#include "Constants.hpp"
#include "Credential.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "C25519.hpp" #include "C25519.hpp"
#include "Constants.hpp"
#include "Credential.hpp"
#include "FCV.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include "FCV.hpp"
#include <algorithm>
#include <stdexcept>
#include <string>
// Maximum number of additional tuples beyond the standard always-present three. // Maximum number of additional tuples beyond the standard always-present three.
#define ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS 8 #define ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS 8
// version + qualifier count + three required qualifiers + additional qualifiers + // version + qualifier count + three required qualifiers + additional qualifiers +
#define ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX (1 + 2 + (3 * 3 * 8) + (ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS * 3 * 8) + 144 + 5 + 2 + 96) #define ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX \
(1 + 2 + (3 * 3 * 8) + (ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS * 3 * 8) + 144 + 5 + 2 + 96)
namespace ZeroTier { namespace ZeroTier {
@ -96,19 +97,22 @@ class Context;
* order with the fingerprint hash being packed into tuple IDs 3-8 and this buffer is * order with the fingerprint hash being packed into tuple IDs 3-8 and this buffer is
* then signed. * then signed.
*/ */
class MembershipCredential : public Credential class MembershipCredential : public Credential {
{
friend class Credential; friend class Credential;
public: public:
static constexpr ZT_CredentialType credentialType() noexcept static constexpr ZT_CredentialType credentialType() noexcept
{ return ZT_CREDENTIAL_TYPE_COM; } {
return ZT_CREDENTIAL_TYPE_COM;
}
/** /**
* Create an empty certificate of membership * Create an empty certificate of membership
*/ */
ZT_INLINE MembershipCredential() noexcept ZT_INLINE MembershipCredential() noexcept
{ memoryZero(this); } {
memoryZero(this);
}
/** /**
* Create from required fields common to all networks * Create from required fields common to all networks
@ -118,46 +122,61 @@ public:
* @param nwid Network ID * @param nwid Network ID
* @param issuedTo Certificate recipient * @param issuedTo Certificate recipient
*/ */
MembershipCredential(int64_t timestamp, int64_t timestampMaxDelta, uint64_t nwid, const Identity &issuedTo) noexcept; MembershipCredential(int64_t timestamp, int64_t timestampMaxDelta, uint64_t nwid, const Identity& issuedTo)
noexcept;
/** /**
* @return True if there's something here * @return True if there's something here
*/ */
ZT_INLINE operator bool() const noexcept ZT_INLINE operator bool() const noexcept
{ return (m_networkId != 0); } {
return (m_networkId != 0);
}
/** /**
* @return Credential ID, always 0 for COMs * @return Credential ID, always 0 for COMs
*/ */
ZT_INLINE uint32_t id() const noexcept ZT_INLINE uint32_t id() const noexcept
{ return 0; } {
return 0;
}
/** /**
* @return Timestamp for this cert and maximum delta for timestamp * @return Timestamp for this cert and maximum delta for timestamp
*/ */
ZT_INLINE int64_t timestamp() const noexcept ZT_INLINE int64_t timestamp() const noexcept
{ return m_timestamp; } {
return m_timestamp;
}
ZT_INLINE int64_t revision() const noexcept ZT_INLINE int64_t revision() const noexcept
{ return m_timestamp; } {
return m_timestamp;
}
/** /**
* @return Maximum allowed difference between timestamps * @return Maximum allowed difference between timestamps
*/ */
ZT_INLINE int64_t timestampMaxDelta() const noexcept ZT_INLINE int64_t timestampMaxDelta() const noexcept
{ return m_timestampMaxDelta; } {
return m_timestampMaxDelta;
}
/** /**
* @return Fingerprint of identity to which this cert was issued * @return Fingerprint of identity to which this cert was issued
*/ */
ZT_INLINE const Fingerprint &issuedTo() const noexcept ZT_INLINE const Fingerprint& issuedTo() const noexcept
{ return m_issuedTo; } {
return m_issuedTo;
}
/** /**
* @return Network ID for which this cert was issued * @return Network ID for which this cert was issued
*/ */
ZT_INLINE uint64_t networkId() const noexcept ZT_INLINE uint64_t networkId() const noexcept
{ return m_networkId; } {
return m_networkId;
}
/** /**
* Compare two certificates for parameter agreement * Compare two certificates for parameter agreement
@ -172,7 +191,7 @@ public:
* @param other Cert to compare with * @param other Cert to compare with
* @return True if certs agree and 'other' may be communicated with * @return True if certs agree and 'other' may be communicated with
*/ */
bool agreesWith(const MembershipCredential &other) const noexcept; bool agreesWith(const MembershipCredential& other) const noexcept;
/** /**
* Sign this certificate * Sign this certificate
@ -180,7 +199,7 @@ public:
* @param with Identity to sign with, must include private key * @param with Identity to sign with, must include private key
* @return True if signature was successful * @return True if signature was successful
*/ */
bool sign(const Identity &with) noexcept; bool sign(const Identity& with) noexcept;
/** /**
* Verify this COM and its signature * Verify this COM and its signature
@ -188,34 +207,47 @@ public:
* @param RR Runtime environment for looking up peers * @param RR Runtime environment for looking up peers
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
*/ */
ZT_INLINE Credential::VerifyResult verify(const Context &ctx, const CallContext &cc) const ZT_INLINE Credential::VerifyResult verify(const Context& ctx, const CallContext& cc) const
{ return s_verify(ctx, cc, *this); } {
return s_verify(ctx, cc, *this);
}
static constexpr int marshalSizeMax() noexcept static constexpr int marshalSizeMax() noexcept
{ return ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX; } {
return ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX;
}
int marshal(uint8_t data[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX], bool v2 = false) const noexcept; int marshal(uint8_t data[ZT_MEMBERSHIP_CREDENTIAL_MARSHAL_SIZE_MAX], bool v2 = false) const noexcept;
int unmarshal(const uint8_t *data, int len) noexcept; int unmarshal(const uint8_t* data, int len) noexcept;
private: private:
unsigned int m_fillSigningBuf(uint64_t *buf) const noexcept; unsigned int m_fillSigningBuf(uint64_t* buf) const noexcept;
struct p_Qualifier struct p_Qualifier {
ZT_INLINE p_Qualifier() noexcept
: id(0)
, value(0)
, delta(0)
{ {
ZT_INLINE p_Qualifier() noexcept: id(0), value(0), delta(0) }
{}
ZT_INLINE p_Qualifier(const uint64_t id_, const uint64_t value_, const uint64_t delta_) noexcept: id(id_), value(value_), delta(delta_) ZT_INLINE p_Qualifier(const uint64_t id_, const uint64_t value_, const uint64_t delta_) noexcept
{} : id(id_)
, value(value_)
, delta(delta_)
{
}
uint64_t id; uint64_t id;
uint64_t value; uint64_t value;
uint64_t delta; uint64_t delta;
ZT_INLINE bool operator<(const p_Qualifier &q) const noexcept ZT_INLINE bool operator<(const p_Qualifier& q) const noexcept
{ return (id < q.id); } // sort order {
return (id < q.id);
} // sort order
}; };
FCV< p_Qualifier, ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS > m_additionalQualifiers; FCV<p_Qualifier, ZT_MEMBERSHIP_CREDENTIAL_MAX_ADDITIONAL_QUALIFIERS> m_additionalQualifiers;
int64_t m_timestamp; int64_t m_timestamp;
int64_t m_timestampMaxDelta; int64_t m_timestampMaxDelta;
uint64_t m_networkId; uint64_t m_networkId;

View file

@ -34,17 +34,16 @@ namespace ZeroTier {
* @tparam TUNIT Unit of time in milliseconds (default: 1000 for one second) * @tparam TUNIT Unit of time in milliseconds (default: 1000 for one second)
* @tparam LSIZE Log size in units of time (default: 10 for 10s worth of data) * @tparam LSIZE Log size in units of time (default: 10 for 10s worth of data)
*/ */
template<int64_t TUNIT = 1000, unsigned long LSIZE = 10> template <int64_t TUNIT = 1000, unsigned long LSIZE = 10> class Meter {
class Meter public:
{
public:
/** /**
* Create and initialize a new meter * Create and initialize a new meter
* *
* @param now Start time * @param now Start time
*/ */
ZT_INLINE Meter() noexcept ZT_INLINE Meter() noexcept
{} {
}
/** /**
* Add a measurement * Add a measurement
@ -59,8 +58,11 @@ public:
// to it. // to it.
const unsigned long bucket = ((unsigned long)(ts / TUNIT)) % LSIZE; const unsigned long bucket = ((unsigned long)(ts / TUNIT)) % LSIZE;
if (unlikely(m_bucket.exchange(bucket, std::memory_order_relaxed) != bucket)) { if (unlikely(m_bucket.exchange(bucket, std::memory_order_relaxed) != bucket)) {
m_totalExclCounts.fetch_add(m_counts[bucket].exchange(count, std::memory_order_relaxed), std::memory_order_relaxed); m_totalExclCounts.fetch_add(
} else { m_counts[bucket].exchange(count, std::memory_order_relaxed),
std::memory_order_relaxed);
}
else {
m_counts[bucket].fetch_add(count, std::memory_order_relaxed); m_counts[bucket].fetch_add(count, std::memory_order_relaxed);
} }
} }
@ -72,16 +74,16 @@ public:
* @param rate Result parameter: rate in count/TUNIT * @param rate Result parameter: rate in count/TUNIT
* @param total Total count for life of object * @param total Total count for life of object
*/ */
ZT_INLINE void rate(double &rate, uint64_t &total) const noexcept ZT_INLINE void rate(double& rate, uint64_t& total) const noexcept
{ {
total = 0; total = 0;
for (unsigned long i = 0;i < LSIZE;++i) for (unsigned long i = 0; i < LSIZE; ++i)
total += m_counts[i].load(std::memory_order_relaxed); total += m_counts[i].load(std::memory_order_relaxed);
rate = (double) total / (double) LSIZE; rate = (double)total / (double)LSIZE;
total += m_totalExclCounts.load(std::memory_order_relaxed); total += m_totalExclCounts.load(std::memory_order_relaxed);
} }
private: private:
std::atomic<uint64_t> m_counts[LSIZE]; std::atomic<uint64_t> m_counts[LSIZE];
std::atomic<uint64_t> m_totalExclCounts; std::atomic<uint64_t> m_totalExclCounts;
std::atomic<unsigned long> m_bucket; std::atomic<unsigned long> m_bucket;

View file

@ -15,10 +15,10 @@
#define ZT_MULTICASTGROUP_HPP #define ZT_MULTICASTGROUP_HPP
#include "Constants.hpp" #include "Constants.hpp"
#include "MAC.hpp"
#include "InetAddress.hpp" #include "InetAddress.hpp"
#include "Utils.hpp" #include "MAC.hpp"
#include "TriviallyCopyable.hpp" #include "TriviallyCopyable.hpp"
#include "Utils.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -37,14 +37,19 @@ namespace ZeroTier {
* *
* MulticastGroup behaves as an immutable value object. * MulticastGroup behaves as an immutable value object.
*/ */
class MulticastGroup : public TriviallyCopyable class MulticastGroup : public TriviallyCopyable {
{ public:
public: ZT_INLINE MulticastGroup() noexcept
ZT_INLINE MulticastGroup() noexcept: m_mac(), m_adi(0) : m_mac()
{} , m_adi(0)
{
}
ZT_INLINE MulticastGroup(const MAC &m, uint32_t a) noexcept: m_mac(m), m_adi(a) 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 * Derive the multicast group used for address resolution (ARP/NDP) for an IP
@ -52,20 +57,22 @@ public:
* @param ip IP address (port field is ignored) * @param ip IP address (port field is ignored)
* @return Multicast group for ARP/NDP * @return Multicast group for ARP/NDP
*/ */
static ZT_INLINE MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress &ip) noexcept static ZT_INLINE MulticastGroup deriveMulticastGroupForAddressResolution(const InetAddress& ip) noexcept
{ {
if (ip.isV4()) { if (ip.isV4()) {
// IPv4 wants broadcast MACs, so we shove the V4 address itself into // IPv4 wants broadcast MACs, so we shove the V4 address itself into
// the Multicast Group ADI field. Making V4 ARP work is basically why // the Multicast Group ADI field. Making V4 ARP work is basically why
// ADI was added, as well as handling other things that want mindless // ADI was added, as well as handling other things that want mindless
// Ethernet broadcast to all. // Ethernet broadcast to all.
return MulticastGroup(MAC(0xffffffffffffULL), Utils::ntoh(*((const uint32_t *)ip.rawIpData()))); return MulticastGroup(MAC(0xffffffffffffULL), Utils::ntoh(*((const uint32_t*)ip.rawIpData())));
} else if (ip.isV6()) { }
else if (ip.isV6()) {
// IPv6 is better designed in this respect. We can compute the IPv6 // IPv6 is better designed in this respect. We can compute the IPv6
// multicast address directly from the IP address, and it gives us // multicast address directly from the IP address, and it gives us
// 24 bits of uniqueness. Collisions aren't likely to be common enough // 24 bits of uniqueness. Collisions aren't likely to be common enough
// to care about. // to care about.
const uint8_t *const a = reinterpret_cast<const uint8_t *>(ip.rawIpData()); // NOLINT(hicpp-use-auto,modernize-use-auto) const uint8_t* const a =
reinterpret_cast<const uint8_t*>(ip.rawIpData()); // NOLINT(hicpp-use-auto,modernize-use-auto)
return MulticastGroup(MAC(0x33, 0x33, 0xff, a[13], a[14], a[15]), 0); return MulticastGroup(MAC(0x33, 0x33, 0xff, a[13], a[14], a[15]), 0);
} }
return MulticastGroup(); // NOLINT(modernize-return-braced-init-list) return MulticastGroup(); // NOLINT(modernize-return-braced-init-list)
@ -74,22 +81,31 @@ public:
/** /**
* @return Ethernet MAC portion of multicast group * @return Ethernet MAC portion of multicast group
*/ */
ZT_INLINE const MAC &mac() const noexcept ZT_INLINE const MAC& mac() const noexcept
{ return m_mac; } {
return m_mac;
}
/** /**
* @return Additional distinguishing information, which is normally zero except for IPv4 ARP where it's the IPv4 address * @return Additional distinguishing information, which is normally zero except for IPv4 ARP where it's the IPv4
* address
*/ */
ZT_INLINE uint32_t adi() const ZT_INLINE uint32_t adi() const
{ return m_adi; } {
return m_adi;
}
ZT_INLINE bool operator==(const MulticastGroup &g) const noexcept ZT_INLINE bool operator==(const MulticastGroup& g) const noexcept
{ return ((m_mac == g.m_mac) && (m_adi == g.m_adi)); } {
return ((m_mac == g.m_mac) && (m_adi == g.m_adi));
}
ZT_INLINE bool operator!=(const MulticastGroup &g) const noexcept ZT_INLINE bool operator!=(const MulticastGroup& g) const noexcept
{ return ((m_mac != g.m_mac) || (m_adi != g.m_adi)); } {
return ((m_mac != g.m_mac) || (m_adi != g.m_adi));
}
ZT_INLINE bool operator<(const MulticastGroup &g) const noexcept ZT_INLINE bool operator<(const MulticastGroup& g) const noexcept
{ {
if (m_mac < g.m_mac) if (m_mac < g.m_mac)
return true; return true;
@ -98,19 +114,27 @@ public:
return false; return false;
} }
ZT_INLINE bool operator>(const MulticastGroup &g) const noexcept ZT_INLINE bool operator>(const MulticastGroup& g) const noexcept
{ return (g < *this); } {
return (g < *this);
}
ZT_INLINE bool operator<=(const MulticastGroup &g) const noexcept ZT_INLINE bool operator<=(const MulticastGroup& g) const noexcept
{ return !(g < *this); } {
return ! (g < *this);
}
ZT_INLINE bool operator>=(const MulticastGroup &g) const noexcept ZT_INLINE bool operator>=(const MulticastGroup& g) const noexcept
{ return !(*this < g); } {
return ! (*this < g);
}
ZT_INLINE unsigned long hashCode() const noexcept ZT_INLINE unsigned long hashCode() const noexcept
{ return (m_mac.hashCode() + (unsigned long)m_adi); } {
return (m_mac.hashCode() + (unsigned long)m_adi);
}
private: private:
MAC m_mac; MAC m_mac;
uint32_t m_adi; uint32_t m_adi;
}; };

View file

@ -36,33 +36,66 @@ namespace ZeroTier {
/** /**
* A simple mutual exclusion lock. * A simple mutual exclusion lock.
*/ */
class Mutex class Mutex {
{ public:
public:
#ifdef ZT_USE_PTHREADS #ifdef ZT_USE_PTHREADS
ZT_INLINE Mutex() noexcept { pthread_mutex_init(&_mh,nullptr); } ZT_INLINE Mutex() noexcept
ZT_INLINE ~Mutex() noexcept { pthread_mutex_destroy(&_mh); } {
ZT_INLINE void lock() const noexcept { pthread_mutex_lock(&((const_cast <Mutex *> (this))->_mh)); } pthread_mutex_init(&_mh, nullptr);
ZT_INLINE void unlock() const noexcept { pthread_mutex_unlock(&((const_cast <Mutex *> (this))->_mh)); } }
ZT_INLINE ~Mutex() noexcept
{
pthread_mutex_destroy(&_mh);
}
ZT_INLINE void lock() const noexcept
{
pthread_mutex_lock(&((const_cast<Mutex*>(this))->_mh));
}
ZT_INLINE void unlock() const noexcept
{
pthread_mutex_unlock(&((const_cast<Mutex*>(this))->_mh));
}
#else #else
ZT_INLINE Mutex() noexcept : _m() {} ZT_INLINE Mutex() noexcept : _m()
ZT_INLINE void lock() const noexcept { const_cast<Mutex *>(this)->_m.lock(); } {
ZT_INLINE void unlock() const noexcept { const_cast<Mutex *>(this)->_m.unlock(); } }
ZT_INLINE void lock() const noexcept
{
const_cast<Mutex*>(this)->_m.lock();
}
ZT_INLINE void unlock() const noexcept
{
const_cast<Mutex*>(this)->_m.unlock();
}
#endif #endif
class Lock class Lock {
{
public: public:
explicit ZT_INLINE Lock(Mutex &m) noexcept : _m(&m) { m.lock(); } explicit ZT_INLINE Lock(Mutex& m) noexcept : _m(&m)
explicit ZT_INLINE Lock(const Mutex &m) noexcept : _m(const_cast<Mutex *>(&m)) { _m->lock(); } {
ZT_INLINE ~Lock() { _m->unlock(); } m.lock();
}
explicit ZT_INLINE Lock(const Mutex& m) noexcept : _m(const_cast<Mutex*>(&m))
{
_m->lock();
}
ZT_INLINE ~Lock()
{
_m->unlock();
}
private: private:
Mutex *const _m; Mutex* const _m;
}; };
private: private:
ZT_INLINE Mutex(const Mutex &) noexcept {} ZT_INLINE Mutex(const Mutex&) noexcept
ZT_INLINE const Mutex &operator=(const Mutex &) noexcept { return *this; } {
}
ZT_INLINE const Mutex& operator=(const Mutex&) noexcept
{
return *this;
}
#ifdef ZT_USE_PTHREADS #ifdef ZT_USE_PTHREADS
pthread_mutex_t _mh; pthread_mutex_t _mh;
@ -74,48 +107,97 @@ private:
/** /**
* A lock allowing multiple threads to read but making all wait on any writing thread. * A lock allowing multiple threads to read but making all wait on any writing thread.
*/ */
class RWMutex class RWMutex {
{ public:
public:
#ifdef ZT_USE_PTHREADS #ifdef ZT_USE_PTHREADS
ZT_INLINE RWMutex() noexcept { pthread_rwlock_init(&_mh,nullptr); } ZT_INLINE RWMutex() noexcept
ZT_INLINE ~RWMutex() noexcept { pthread_rwlock_destroy(&_mh); } {
ZT_INLINE void lock() const noexcept { pthread_rwlock_wrlock(&((const_cast <RWMutex *> (this))->_mh)); } pthread_rwlock_init(&_mh, nullptr);
ZT_INLINE void rlock() const noexcept { pthread_rwlock_rdlock(&((const_cast <RWMutex *> (this))->_mh)); } }
ZT_INLINE void unlock() const noexcept { pthread_rwlock_unlock(&((const_cast <RWMutex *> (this))->_mh)); } ZT_INLINE ~RWMutex() noexcept
ZT_INLINE void runlock() const noexcept { pthread_rwlock_unlock(&((const_cast <RWMutex *> (this))->_mh)); } {
pthread_rwlock_destroy(&_mh);
}
ZT_INLINE void lock() const noexcept
{
pthread_rwlock_wrlock(&((const_cast<RWMutex*>(this))->_mh));
}
ZT_INLINE void rlock() const noexcept
{
pthread_rwlock_rdlock(&((const_cast<RWMutex*>(this))->_mh));
}
ZT_INLINE void unlock() const noexcept
{
pthread_rwlock_unlock(&((const_cast<RWMutex*>(this))->_mh));
}
ZT_INLINE void runlock() const noexcept
{
pthread_rwlock_unlock(&((const_cast<RWMutex*>(this))->_mh));
}
#else #else
ZT_INLINE RWMutex() noexcept : _m() {} ZT_INLINE RWMutex() noexcept : _m()
ZT_INLINE void lock() const noexcept { const_cast<RWMutex *>(this)->_m.lock(); } {
ZT_INLINE void rlock() const noexcept { const_cast<RWMutex *>(this)->_m.lock_shared(); } }
ZT_INLINE void unlock() const noexcept { const_cast<RWMutex *>(this)->_m.unlock(); } ZT_INLINE void lock() const noexcept
ZT_INLINE void runlock() const noexcept { const_cast<RWMutex *>(this)->_m.unlock_shared(); } {
const_cast<RWMutex*>(this)->_m.lock();
}
ZT_INLINE void rlock() const noexcept
{
const_cast<RWMutex*>(this)->_m.lock_shared();
}
ZT_INLINE void unlock() const noexcept
{
const_cast<RWMutex*>(this)->_m.unlock();
}
ZT_INLINE void runlock() const noexcept
{
const_cast<RWMutex*>(this)->_m.unlock_shared();
}
#endif #endif
/** /**
* RAAI locker that acquires only the read lock (shared read) * RAAI locker that acquires only the read lock (shared read)
*/ */
class RLock class RLock {
{
public: public:
explicit ZT_INLINE RLock(RWMutex &m) noexcept : _m(&m) { m.rlock(); } explicit ZT_INLINE RLock(RWMutex& m) noexcept : _m(&m)
explicit ZT_INLINE RLock(const RWMutex &m) noexcept : _m(const_cast<RWMutex *>(&m)) { _m->rlock(); } {
ZT_INLINE ~RLock() { _m->runlock(); } m.rlock();
}
explicit ZT_INLINE RLock(const RWMutex& m) noexcept : _m(const_cast<RWMutex*>(&m))
{
_m->rlock();
}
ZT_INLINE ~RLock()
{
_m->runlock();
}
private: private:
RWMutex *const _m; RWMutex* const _m;
}; };
/** /**
* RAAI locker that acquires the write lock (exclusive write, no readers) * RAAI locker that acquires the write lock (exclusive write, no readers)
*/ */
class Lock class Lock {
{
public: public:
explicit ZT_INLINE Lock(RWMutex &m) noexcept : _m(&m) { m.lock(); } explicit ZT_INLINE Lock(RWMutex& m) noexcept : _m(&m)
explicit ZT_INLINE Lock(const RWMutex &m) noexcept : _m(const_cast<RWMutex *>(&m)) { _m->lock(); } {
ZT_INLINE ~Lock() { _m->unlock(); } m.lock();
}
explicit ZT_INLINE Lock(const RWMutex& m) noexcept : _m(const_cast<RWMutex*>(&m))
{
_m->lock();
}
ZT_INLINE ~Lock()
{
_m->unlock();
}
private: private:
RWMutex *const _m; RWMutex* const _m;
}; };
/** /**
@ -127,23 +209,61 @@ public:
* transition, meaning protected variable states can change. Code must not assume * transition, meaning protected variable states can change. Code must not assume
* that the lock is held constantly if writing() is used to change mode. * that the lock is held constantly if writing() is used to change mode.
*/ */
class RMaybeWLock class RMaybeWLock {
{
public: public:
explicit ZT_INLINE RMaybeWLock(RWMutex &m) noexcept : _m(&m),_w(false) { m.rlock(); } explicit ZT_INLINE RMaybeWLock(RWMutex& m) noexcept
explicit ZT_INLINE RMaybeWLock(const RWMutex &m) noexcept : _m(const_cast<RWMutex *>(&m)),_w(false) { _m->rlock(); } : _m(&m)
ZT_INLINE void writing() noexcept { if (!_w) { _w = true; _m->runlock(); _m->lock(); } } , _w(false)
ZT_INLINE void reading() noexcept { if (_w) { _w = false; _m->unlock(); _m->rlock(); } } {
ZT_INLINE bool isWriting() const noexcept { return _w; } m.rlock();
ZT_INLINE ~RMaybeWLock() { if (_w) _m->unlock(); else _m->runlock(); } }
explicit ZT_INLINE RMaybeWLock(const RWMutex& m) noexcept
: _m(const_cast<RWMutex*>(&m))
, _w(false)
{
_m->rlock();
}
ZT_INLINE void writing() noexcept
{
if (! _w) {
_w = true;
_m->runlock();
_m->lock();
}
}
ZT_INLINE void reading() noexcept
{
if (_w) {
_w = false;
_m->unlock();
_m->rlock();
}
}
ZT_INLINE bool isWriting() const noexcept
{
return _w;
}
ZT_INLINE ~RMaybeWLock()
{
if (_w)
_m->unlock();
else
_m->runlock();
}
private: private:
RWMutex *const _m; RWMutex* const _m;
bool _w; bool _w;
}; };
private: private:
ZT_INLINE RWMutex(const RWMutex &) noexcept {} ZT_INLINE RWMutex(const RWMutex&) noexcept
ZT_INLINE const RWMutex &operator=(const RWMutex &) noexcept { return *this; } {
}
ZT_INLINE const RWMutex& operator=(const RWMutex&) noexcept
{
return *this;
}
#ifdef ZT_USE_PTHREADS #ifdef ZT_USE_PTHREADS
pthread_rwlock_t _mh; pthread_rwlock_t _mh;

File diff suppressed because it is too large Load diff

View file

@ -14,19 +14,19 @@
#ifndef ZT_NETWORK_HPP #ifndef ZT_NETWORK_HPP
#define ZT_NETWORK_HPP #define ZT_NETWORK_HPP
#include "Constants.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Mutex.hpp"
#include "SharedPtr.hpp"
#include "MulticastGroup.hpp"
#include "MAC.hpp"
#include "Buf.hpp" #include "Buf.hpp"
#include "Dictionary.hpp"
#include "Member.hpp"
#include "NetworkConfig.hpp"
#include "MembershipCredential.hpp"
#include "Containers.hpp"
#include "CallContext.hpp" #include "CallContext.hpp"
#include "Constants.hpp"
#include "Containers.hpp"
#include "Dictionary.hpp"
#include "MAC.hpp"
#include "Member.hpp"
#include "MembershipCredential.hpp"
#include "MulticastGroup.hpp"
#include "Mutex.hpp"
#include "NetworkConfig.hpp"
#include "SharedPtr.hpp"
#define ZT_NETWORK_MAX_INCOMING_UPDATES 3 #define ZT_NETWORK_MAX_INCOMING_UPDATES 3
@ -39,11 +39,10 @@ class Peer;
/** /**
* A virtual LAN * A virtual LAN
*/ */
class Network class Network {
{ friend class SharedPtr<Network>;
friend class SharedPtr< Network >;
public: public:
/** /**
* Broadcast multicast group: ff:ff:ff:ff:ff:ff / 0 * Broadcast multicast group: ff:ff:ff:ff:ff:ff / 0
*/ */
@ -53,7 +52,9 @@ public:
* Compute primary controller device ID from network ID * Compute primary controller device ID from network ID
*/ */
static ZT_INLINE Address controllerFor(uint64_t nwid) noexcept static ZT_INLINE Address controllerFor(uint64_t nwid) noexcept
{ return Address(nwid >> 24U); } {
return Address(nwid >> 24U);
}
/** /**
* Construct a new network * Construct a new network
@ -67,38 +68,54 @@ public:
* @param nconf Network config, if known * @param nconf Network config, if known
*/ */
Network( Network(
const Context &ctx, const Context& ctx,
const CallContext &cc, const CallContext& cc,
uint64_t nwid, uint64_t nwid,
const Fingerprint &controllerFingerprint, const Fingerprint& controllerFingerprint,
void *uptr, void* uptr,
const NetworkConfig *nconf); const NetworkConfig* nconf);
~Network(); ~Network();
ZT_INLINE uint64_t id() const noexcept ZT_INLINE uint64_t id() const noexcept
{ return m_id; } {
return m_id;
}
ZT_INLINE Address controller() const noexcept ZT_INLINE Address controller() const noexcept
{ return Address(m_id >> 24U); } {
return Address(m_id >> 24U);
}
ZT_INLINE bool multicastEnabled() const noexcept ZT_INLINE bool multicastEnabled() const noexcept
{ return (m_config.multicastLimit > 0); } {
return (m_config.multicastLimit > 0);
}
ZT_INLINE bool hasConfig() const noexcept ZT_INLINE bool hasConfig() const noexcept
{ return (m_config); } {
return (m_config);
}
ZT_INLINE uint64_t lastConfigUpdate() const noexcept ZT_INLINE uint64_t lastConfigUpdate() const noexcept
{ return m_lastConfigUpdate; } {
return m_lastConfigUpdate;
}
ZT_INLINE ZT_VirtualNetworkStatus status() const noexcept ZT_INLINE ZT_VirtualNetworkStatus status() const noexcept
{ return m_status(); } {
return m_status();
}
ZT_INLINE const NetworkConfig &config() const noexcept ZT_INLINE const NetworkConfig& config() const noexcept
{ return m_config; } {
return m_config;
}
ZT_INLINE const MAC &mac() const noexcept ZT_INLINE const MAC& mac() const noexcept
{ return m_mac; } {
return m_mac;
}
/** /**
* Apply filters to an outgoing packet * Apply filters to an outgoing packet
@ -120,17 +137,17 @@ public:
* @return True if packet should be sent, false if dropped or redirected * @return True if packet should be sent, false if dropped or redirected
*/ */
bool filterOutgoingPacket( bool filterOutgoingPacket(
const CallContext &cc, const CallContext& cc,
bool noTee, bool noTee,
const Address &ztSource, const Address& ztSource,
const Address &ztDest, const Address& ztDest,
const MAC &macSource, const MAC& macSource,
const MAC &macDest, const MAC& macDest,
const uint8_t *frameData, const uint8_t* frameData,
unsigned int frameLen, unsigned int frameLen,
unsigned int etherType, unsigned int etherType,
unsigned int vlanId, unsigned int vlanId,
uint8_t &qosBucket); uint8_t& qosBucket);
/** /**
* Apply filters to an incoming packet * Apply filters to an incoming packet
@ -151,12 +168,12 @@ public:
* @return 0 == drop, 1 == accept, 2 == accept even if bridged * @return 0 == drop, 1 == accept, 2 == accept even if bridged
*/ */
int filterIncomingPacket( int filterIncomingPacket(
const CallContext &cc, const CallContext& cc,
const SharedPtr< Peer > &sourcePeer, const SharedPtr<Peer>& sourcePeer,
const Address &ztDest, const Address& ztDest,
const MAC &macSource, const MAC& macSource,
const MAC &macDest, const MAC& macDest,
const uint8_t *frameData, const uint8_t* frameData,
unsigned int frameLen, unsigned int frameLen,
unsigned int etherType, unsigned int etherType,
unsigned int vlanId); unsigned int vlanId);
@ -166,14 +183,14 @@ public:
* *
* @param mg New multicast group * @param mg New multicast group
*/ */
void multicastSubscribe(const CallContext &cc, const MulticastGroup &mg); void multicastSubscribe(const CallContext& cc, const MulticastGroup& mg);
/** /**
* Unsubscribe from a multicast group * Unsubscribe from a multicast group
* *
* @param mg Multicast group * @param mg Multicast group
*/ */
void multicastUnsubscribe(const MulticastGroup &mg); void multicastUnsubscribe(const MulticastGroup& mg);
/** /**
* Parse, verify, and handle an inbound network config chunk * Parse, verify, and handle an inbound network config chunk
@ -191,10 +208,10 @@ public:
* @return Update ID if update was fully assembled and accepted or 0 otherwise * @return Update ID if update was fully assembled and accepted or 0 otherwise
*/ */
uint64_t handleConfigChunk( uint64_t handleConfigChunk(
const CallContext &cc, const CallContext& cc,
uint64_t packetId, uint64_t packetId,
const SharedPtr< Peer > &source, const SharedPtr<Peer>& source,
const Buf &chunk, const Buf& chunk,
int ptr, int ptr,
int size); int size);
@ -209,22 +226,23 @@ public:
* @param saveToDisk Save to disk? Used during loading, should usually be true otherwise. * @param saveToDisk Save to disk? Used during loading, should usually be true otherwise.
* @return 0 == bad, 1 == accepted but duplicate/unchanged, 2 == accepted and new * @return 0 == bad, 1 == accepted but duplicate/unchanged, 2 == accepted and new
*/ */
int setConfiguration( int setConfiguration(const CallContext& cc, const NetworkConfig& nconf, bool saveToDisk);
const CallContext &cc,
const NetworkConfig &nconf,
bool saveToDisk);
/** /**
* Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this * Set netconf failure to 'access denied' -- called in IncomingPacket when controller reports this
*/ */
ZT_INLINE void setAccessDenied() noexcept ZT_INLINE void setAccessDenied() noexcept
{ _netconfFailure = NETCONF_FAILURE_ACCESS_DENIED; } {
_netconfFailure = NETCONF_FAILURE_ACCESS_DENIED;
}
/** /**
* Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this * Set netconf failure to 'not found' -- called by IncomingPacket when controller reports this
*/ */
ZT_INLINE void setNotFound() noexcept ZT_INLINE void setNotFound() noexcept
{ _netconfFailure = NETCONF_FAILURE_NOT_FOUND; } {
_netconfFailure = NETCONF_FAILURE_NOT_FOUND;
}
/** /**
* Determine whether this peer is permitted to communicate on this network * Determine whether this peer is permitted to communicate on this network
@ -232,12 +250,12 @@ public:
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param peer Peer to check * @param peer Peer to check
*/ */
bool gate(void *tPtr, const SharedPtr< Peer > &peer) noexcept; bool gate(void* tPtr, const SharedPtr<Peer>& peer) noexcept;
/** /**
* Do periodic cleanup and housekeeping tasks * Do periodic cleanup and housekeeping tasks
*/ */
void doPeriodicTasks(const CallContext &cc); void doPeriodicTasks(const CallContext& cc);
/** /**
* Find the node on this network that has this MAC behind it (if any) * Find the node on this network that has this MAC behind it (if any)
@ -245,10 +263,10 @@ public:
* @param mac MAC address * @param mac MAC address
* @return ZeroTier address of bridge to this MAC * @return ZeroTier address of bridge to this MAC
*/ */
ZT_INLINE Address findBridgeTo(const MAC &mac) const ZT_INLINE Address findBridgeTo(const MAC& mac) const
{ {
Mutex::Lock _l(m_remoteBridgeRoutes_l); Mutex::Lock _l(m_remoteBridgeRoutes_l);
Map< MAC, Address >::const_iterator br(m_remoteBridgeRoutes.find(mac)); Map<MAC, Address>::const_iterator br(m_remoteBridgeRoutes.find(mac));
return ((br == m_remoteBridgeRoutes.end()) ? Address() : br->second); return ((br == m_remoteBridgeRoutes.end()) ? Address() : br->second);
} }
@ -258,7 +276,7 @@ public:
* @param mac MAC address of destination * @param mac MAC address of destination
* @param addr Bridge this MAC is reachable behind * @param addr Bridge this MAC is reachable behind
*/ */
void learnBridgeRoute(const MAC &mac, const Address &addr); void learnBridgeRoute(const MAC& mac, const Address& addr);
/** /**
* Learn a multicast group that is bridged to our tap device * Learn a multicast group that is bridged to our tap device
@ -267,7 +285,7 @@ public:
* @param mg Multicast group * @param mg Multicast group
* @param now Current time * @param now Current time
*/ */
ZT_INLINE void learnBridgedMulticastGroup(const MulticastGroup &mg, int64_t now) ZT_INLINE void learnBridgedMulticastGroup(const MulticastGroup& mg, int64_t now)
{ {
Mutex::Lock l(m_myMulticastGroups_l); Mutex::Lock l(m_myMulticastGroups_l);
m_multicastGroupsBehindMe[mg] = now; m_multicastGroupsBehindMe[mg] = now;
@ -276,34 +294,39 @@ public:
/** /**
* Validate a credential and learn it if it passes certificate and other checks * Validate a credential and learn it if it passes certificate and other checks
*/ */
Member::AddCredentialResult addCredential(const CallContext &cc, const Identity &sourcePeerIdentity, const MembershipCredential &com); Member::AddCredentialResult
addCredential(const CallContext& cc, const Identity& sourcePeerIdentity, const MembershipCredential& com);
/** /**
* Validate a credential and learn it if it passes certificate and other checks * Validate a credential and learn it if it passes certificate and other checks
*/ */
Member::AddCredentialResult addCredential(const CallContext &cc, const Identity &sourcePeerIdentity, const CapabilityCredential &cap); Member::AddCredentialResult
addCredential(const CallContext& cc, const Identity& sourcePeerIdentity, const CapabilityCredential& cap);
/** /**
* Validate a credential and learn it if it passes certificate and other checks * Validate a credential and learn it if it passes certificate and other checks
*/ */
Member::AddCredentialResult addCredential(const CallContext &cc, const Identity &sourcePeerIdentity, const TagCredential &tag); Member::AddCredentialResult
addCredential(const CallContext& cc, const Identity& sourcePeerIdentity, const TagCredential& tag);
/** /**
* Validate a credential and learn it if it passes certificate and other checks * Validate a credential and learn it if it passes certificate and other checks
*/ */
Member::AddCredentialResult addCredential(const CallContext &cc, const Identity &sourcePeerIdentity, const RevocationCredential &rev); Member::AddCredentialResult
addCredential(const CallContext& cc, const Identity& sourcePeerIdentity, const RevocationCredential& rev);
/** /**
* Validate a credential and learn it if it passes certificate and other checks * Validate a credential and learn it if it passes certificate and other checks
*/ */
Member::AddCredentialResult addCredential(const CallContext &cc, const Identity &sourcePeerIdentity, const OwnershipCredential &coo); Member::AddCredentialResult
addCredential(const CallContext& cc, const Identity& sourcePeerIdentity, const OwnershipCredential& coo);
/** /**
* Push credentials to a peer if timeouts indicate that we should do so * Push credentials to a peer if timeouts indicate that we should do so
* *
* @param to Destination peer * @param to Destination peer
*/ */
void pushCredentials(const CallContext &cc, const SharedPtr< Peer > &to); void pushCredentials(const CallContext& cc, const SharedPtr<Peer>& to);
/** /**
* Destroy this network * Destroy this network
@ -318,19 +341,19 @@ public:
* *
* @param ec Buffer to fill with externally-visible network configuration * @param ec Buffer to fill with externally-visible network configuration
*/ */
void externalConfig(ZT_VirtualNetworkConfig *ec) const; void externalConfig(ZT_VirtualNetworkConfig* ec) const;
/** /**
* Iterate through memberships * Iterate through memberships
* *
* @param f Function of (const Address,const Membership) * @param f Function of (const Address,const Membership)
*/ */
template< typename F > template <typename F> ZT_INLINE void eachMember(F f)
ZT_INLINE void eachMember(F f)
{ {
Mutex::Lock ml(m_memberships_l); Mutex::Lock ml(m_memberships_l);
for (Map< Address, Member >::iterator i(m_memberships.begin()); i != m_memberships.end(); ++i) { // NOLINT(modernize-loop-convert,hicpp-use-auto,modernize-use-auto) for (Map<Address, Member>::iterator i(m_memberships.begin()); i != m_memberships.end();
if (!f(i->first, i->second)) ++i) { // NOLINT(modernize-loop-convert,hicpp-use-auto,modernize-use-auto)
if (! f(i->first, i->second))
break; break;
} }
} }
@ -338,48 +361,51 @@ public:
/** /**
* @return Externally usable pointer-to-pointer exported via the core API * @return Externally usable pointer-to-pointer exported via the core API
*/ */
ZT_INLINE void **userPtr() noexcept ZT_INLINE void** userPtr() noexcept
{ return &m_uPtr; } {
return &m_uPtr;
}
private: private:
void m_requestConfiguration(const CallContext &cc); void m_requestConfiguration(const CallContext& cc);
ZT_VirtualNetworkStatus m_status() const; ZT_VirtualNetworkStatus m_status() const;
void m_externalConfig(ZT_VirtualNetworkConfig *ec) const; // assumes _lock is locked void m_externalConfig(ZT_VirtualNetworkConfig* ec) const; // assumes _lock is locked
void m_announceMulticastGroups(void *tPtr, bool force); void m_announceMulticastGroups(void* tPtr, bool force);
void m_announceMulticastGroupsTo(void *tPtr, const Address &peer, const Vector< MulticastGroup > &allMulticastGroups); void m_announceMulticastGroupsTo(void* tPtr, const Address& peer, const Vector<MulticastGroup>& allMulticastGroups);
Vector< MulticastGroup > m_allMulticastGroups() const; Vector<MulticastGroup> m_allMulticastGroups() const;
const Context &m_ctx; const Context& m_ctx;
void *m_uPtr; void* m_uPtr;
const uint64_t m_id; const uint64_t m_id;
Fingerprint m_controllerFingerprint; Fingerprint m_controllerFingerprint;
MAC m_mac; // local MAC address MAC m_mac; // local MAC address
bool m_portInitialized; bool m_portInitialized;
std::atomic< bool > m_destroyed; std::atomic<bool> m_destroyed;
Vector< MulticastGroup > m_myMulticastGroups; // multicast groups that we belong to (according to tap) 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<MulticastGroup, int64_t> m_multicastGroupsBehindMe; // multicast groups that seem to be behind us and when we
Map< MAC, Address > m_remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges) // 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 m_config; NetworkConfig m_config;
std::atomic< int64_t > m_lastConfigUpdate; std::atomic<int64_t> m_lastConfigUpdate;
volatile enum volatile enum {
{
NETCONF_FAILURE_NONE, NETCONF_FAILURE_NONE,
NETCONF_FAILURE_ACCESS_DENIED, NETCONF_FAILURE_ACCESS_DENIED,
NETCONF_FAILURE_NOT_FOUND, NETCONF_FAILURE_NOT_FOUND,
NETCONF_FAILURE_INIT_FAILED NETCONF_FAILURE_INIT_FAILED
} _netconfFailure; } _netconfFailure;
Map< Address, Member > m_memberships; Map<Address, Member> m_memberships;
Mutex m_myMulticastGroups_l; Mutex m_myMulticastGroups_l;
Mutex m_remoteBridgeRoutes_l; Mutex m_remoteBridgeRoutes_l;
Mutex m_config_l; Mutex m_config_l;
Mutex m_memberships_l; Mutex m_memberships_l;
std::atomic< int > __refCount; std::atomic<int> __refCount;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -11,44 +11,47 @@
*/ */
/****/ /****/
#include <cstdint> #include "NetworkConfig.hpp"
#include "Buf.hpp"
#include "ScopedPtr.hpp"
#include <algorithm> #include <algorithm>
#include <cstdint>
#include "NetworkConfig.hpp"
#include "ScopedPtr.hpp"
#include "Buf.hpp"
namespace ZeroTier { namespace ZeroTier {
bool NetworkConfig::toDictionary(Dictionary &d) const bool NetworkConfig::toDictionary(Dictionary& d) const
{ {
uint8_t tmp[ZT_BUF_MEM_SIZE]; uint8_t tmp[ZT_BUF_MEM_SIZE];
try { try {
d.clear(); d.clear();
d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,this->networkId); d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID, this->networkId);
d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,this->timestamp); d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP, this->timestamp);
d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,this->credentialTimeMaxDelta); d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA, this->credentialTimeMaxDelta);
d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision); d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION, this->revision);
d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo.toString((char *)tmp)); d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO, this->issuedTo.toString((char*)tmp));
d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO_IDENTITY_HASH,this->issuedToFingerprintHash,ZT_FINGERPRINT_HASH_SIZE); d.add(
d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags); ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO_IDENTITY_HASH,
d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit); this->issuedToFingerprintHash,
d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type); ZT_FINGERPRINT_HASH_SIZE);
d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name); d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS, this->flags);
d.add(ZT_NETWORKCONFIG_DICT_KEY_MTU,(uint64_t)this->mtu); d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT, (uint64_t)this->multicastLimit);
d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE, (uint64_t)this->type);
d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME, this->name);
d.add(ZT_NETWORKCONFIG_DICT_KEY_MTU, (uint64_t)this->mtu);
if (this->com) { if (this->com) {
d.add(ZT_NETWORKCONFIG_DICT_KEY_COM,tmp,this->com.marshal(tmp)); d.add(ZT_NETWORKCONFIG_DICT_KEY_COM, tmp, this->com.marshal(tmp));
} }
Vector<uint8_t> *blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES]); Vector<uint8_t>* blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES]);
for (unsigned int i = 0; i < this->capabilityCount; ++i) { for (unsigned int i = 0; i < this->capabilityCount; ++i) {
int l = this->capabilities[i].marshal(tmp); int l = this->capabilities[i].marshal(tmp);
if (l < 0) if (l < 0)
return false; return false;
blob->insert(blob->end(),tmp,tmp + l); blob->insert(blob->end(), tmp, tmp + l);
} }
blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_TAGS]); blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_TAGS]);
@ -56,7 +59,7 @@ bool NetworkConfig::toDictionary(Dictionary &d) const
int l = this->tags[i].marshal(tmp); int l = this->tags[i].marshal(tmp);
if (l < 0) if (l < 0)
return false; return false;
blob->insert(blob->end(),tmp,tmp + l); blob->insert(blob->end(), tmp, tmp + l);
} }
blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP]); blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP]);
@ -64,13 +67,13 @@ bool NetworkConfig::toDictionary(Dictionary &d) const
int l = this->certificatesOfOwnership[i].marshal(tmp); int l = this->certificatesOfOwnership[i].marshal(tmp);
if (l < 0) if (l < 0)
return false; return false;
blob->insert(blob->end(),tmp,tmp + l); blob->insert(blob->end(), tmp, tmp + l);
} }
blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS]); blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS]);
for (unsigned int i = 0; i < this->specialistCount; ++i) { for (unsigned int i = 0; i < this->specialistCount; ++i) {
Utils::storeBigEndian<uint64_t>(tmp,this->specialists[i]); Utils::storeBigEndian<uint64_t>(tmp, this->specialists[i]);
blob->insert(blob->end(),tmp,tmp + 8); blob->insert(blob->end(), tmp, tmp + 8);
} }
blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_ROUTES]); blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_ROUTES]);
@ -78,11 +81,11 @@ bool NetworkConfig::toDictionary(Dictionary &d) const
int l = asInetAddress(this->routes[i].target).marshal(tmp); int l = asInetAddress(this->routes[i].target).marshal(tmp);
if (l < 0) if (l < 0)
return false; return false;
blob->insert(blob->end(),tmp,tmp + l); blob->insert(blob->end(), tmp, tmp + l);
l = asInetAddress(this->routes[i].via).marshal(tmp); l = asInetAddress(this->routes[i].via).marshal(tmp);
if (l < 0) if (l < 0)
return false; return false;
blob->insert(blob->end(),tmp,tmp + l); blob->insert(blob->end(), tmp, tmp + l);
} }
blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS]); blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS]);
@ -90,7 +93,7 @@ bool NetworkConfig::toDictionary(Dictionary &d) const
int l = this->staticIps[i].marshal(tmp); int l = this->staticIps[i].marshal(tmp);
if (l < 0) if (l < 0)
return false; return false;
blob->insert(blob->end(),tmp,tmp + l); blob->insert(blob->end(), tmp, tmp + l);
} }
blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_RULES]); blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_RULES]);
@ -102,140 +105,157 @@ bool NetworkConfig::toDictionary(Dictionary &d) const
} }
return true; return true;
} catch ( ... ) {} }
catch (...) {
}
return false; return false;
} }
bool NetworkConfig::fromDictionary(const Dictionary &d) bool NetworkConfig::fromDictionary(const Dictionary& d)
{ {
static const NetworkConfig NIL_NC; static const NetworkConfig NIL_NC;
try { try {
*this = NIL_NC; *this = NIL_NC;
this->networkId = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,0); this->networkId = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID, 0);
if (!this->networkId) if (! this->networkId)
return false; return false;
this->timestamp = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,0); this->timestamp = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP, 0);
if (this->timestamp <= 0) if (this->timestamp <= 0)
return false; return false;
this->credentialTimeMaxDelta = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,0); this->credentialTimeMaxDelta = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA, 0);
this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION,0); this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION, 0);
this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,0); this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO, 0);
const Vector<uint8_t> *blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO_IDENTITY_HASH]); const Vector<uint8_t>* blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO_IDENTITY_HASH]);
if (blob->size() == ZT_FINGERPRINT_HASH_SIZE) { if (blob->size() == ZT_FINGERPRINT_HASH_SIZE) {
Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(this->issuedToFingerprintHash,blob->data()); Utils::copy<ZT_FINGERPRINT_HASH_SIZE>(this->issuedToFingerprintHash, blob->data());
} else { }
else {
Utils::zero<ZT_FINGERPRINT_HASH_SIZE>(this->issuedToFingerprintHash); Utils::zero<ZT_FINGERPRINT_HASH_SIZE>(this->issuedToFingerprintHash);
} }
if (!this->issuedTo) if (! this->issuedTo)
return false; return false;
this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,0); this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT, 0);
d.getS(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name,sizeof(this->name)); d.getS(ZT_NETWORKCONFIG_DICT_KEY_NAME, this->name, sizeof(this->name));
this->mtu = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MTU,ZT_DEFAULT_MTU); this->mtu = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MTU, ZT_DEFAULT_MTU);
if (this->mtu < 1280) if (this->mtu < 1280)
this->mtu = 1280; // minimum MTU allowed by IPv6 standard and others this->mtu = 1280; // minimum MTU allowed by IPv6 standard and others
else if (this->mtu > ZT_MAX_MTU) else if (this->mtu > ZT_MAX_MTU)
this->mtu = ZT_MAX_MTU; this->mtu = ZT_MAX_MTU;
if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION,0) < 6) { if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION, 0) < 6) {
return false; return false;
} else { }
this->flags = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,0); else {
this->type = (ZT_VirtualNetworkType)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)ZT_NETWORK_TYPE_PRIVATE); this->flags = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_FLAGS, 0);
this->type =
(ZT_VirtualNetworkType)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TYPE, (uint64_t)ZT_NETWORK_TYPE_PRIVATE);
blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_COM]); blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_COM]);
if (!blob->empty()) { if (! blob->empty()) {
if (this->com.unmarshal(blob->data(),(int)(blob->size()) < 0)) if (this->com.unmarshal(blob->data(), (int)(blob->size()) < 0))
return false; return false;
} }
blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES]); blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CAPABILITIES]);
if (!blob->empty()) { if (! blob->empty()) {
try { try {
unsigned int p = 0; unsigned int p = 0;
while (p < blob->size()) { while (p < blob->size()) {
CapabilityCredential cap; CapabilityCredential cap;
int l = cap.unmarshal(blob->data() + p,(int)(blob->size() - p)); int l = cap.unmarshal(blob->data() + p, (int)(blob->size() - p));
if (l < 0) if (l < 0)
return false; return false;
p += l; p += l;
if (this->capabilityCount < ZT_MAX_NETWORK_CAPABILITIES) if (this->capabilityCount < ZT_MAX_NETWORK_CAPABILITIES)
this->capabilities[this->capabilityCount++] = cap; this->capabilities[this->capabilityCount++] = cap;
} }
} catch ( ... ) {} }
std::sort(&(this->capabilities[0]),&(this->capabilities[this->capabilityCount])); catch (...) {
}
std::sort(&(this->capabilities[0]), &(this->capabilities[this->capabilityCount]));
} }
blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_TAGS]); blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_TAGS]);
if (!blob->empty()) { if (! blob->empty()) {
try { try {
unsigned int p = 0; unsigned int p = 0;
while (p < blob->size()) { while (p < blob->size()) {
TagCredential tag; TagCredential tag;
int l = tag.unmarshal(blob->data() + p,(int)(blob->size() - p)); int l = tag.unmarshal(blob->data() + p, (int)(blob->size() - p));
if (l < 0) if (l < 0)
return false; return false;
p += l; p += l;
if (this->tagCount < ZT_MAX_NETWORK_TAGS) if (this->tagCount < ZT_MAX_NETWORK_TAGS)
this->tags[this->tagCount++] = tag; this->tags[this->tagCount++] = tag;
} }
} catch ( ... ) {} }
std::sort(&(this->tags[0]),&(this->tags[this->tagCount])); catch (...) {
}
std::sort(&(this->tags[0]), &(this->tags[this->tagCount]));
} }
blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP]); blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATES_OF_OWNERSHIP]);
if (!blob->empty()) { if (! blob->empty()) {
try { try {
unsigned int p = 0; unsigned int p = 0;
while (p < blob->size()) { while (p < blob->size()) {
OwnershipCredential coo; OwnershipCredential coo;
int l = coo.unmarshal(blob->data() + p,(int)(blob->size() - p)); int l = coo.unmarshal(blob->data() + p, (int)(blob->size() - p));
if (l < 0) if (l < 0)
return false; return false;
p += l; p += l;
if (this->certificateOfOwnershipCount < ZT_MAX_CERTIFICATES_OF_OWNERSHIP) if (this->certificateOfOwnershipCount < ZT_MAX_CERTIFICATES_OF_OWNERSHIP)
this->certificatesOfOwnership[certificateOfOwnershipCount++] = coo; this->certificatesOfOwnership[certificateOfOwnershipCount++] = coo;
} }
} catch ( ... ) {} }
std::sort(&(this->certificatesOfOwnership[0]),&(this->certificatesOfOwnership[this->certificateOfOwnershipCount])); catch (...) {
}
std::sort(
&(this->certificatesOfOwnership[0]),
&(this->certificatesOfOwnership[this->certificateOfOwnershipCount]));
} }
blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS]); blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_SPECIALISTS]);
if (!blob->empty()) { if (! blob->empty()) {
unsigned int p = 0; unsigned int p = 0;
while (((p + 8) <= blob->size())&&(specialistCount < ZT_MAX_NETWORK_SPECIALISTS)) { while (((p + 8) <= blob->size()) && (specialistCount < ZT_MAX_NETWORK_SPECIALISTS)) {
this->specialists[this->specialistCount++] = Utils::loadBigEndian<uint64_t>(blob->data() + p); this->specialists[this->specialistCount++] = Utils::loadBigEndian<uint64_t>(blob->data() + p);
p += 8; p += 8;
} }
} }
blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_ROUTES]); blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_ROUTES]);
if (!blob->empty()) { if (! blob->empty()) {
unsigned int p = 0; unsigned int p = 0;
while ((p < blob->size())&&(routeCount < ZT_MAX_NETWORK_ROUTES)) { while ((p < blob->size()) && (routeCount < ZT_MAX_NETWORK_ROUTES)) {
int l = asInetAddress(this->routes[this->routeCount].target).unmarshal(blob->data(),(int)(blob->size() - p)); int l = asInetAddress(this->routes[this->routeCount].target)
.unmarshal(blob->data(), (int)(blob->size() - p));
if (l < 0) if (l < 0)
return false; return false;
p += l; p += l;
if (p >= blob->size()) if (p >= blob->size())
return false; return false;
l = asInetAddress(this->routes[this->routeCount].via).unmarshal(blob->data(),(int)(blob->size() - p)); l = asInetAddress(this->routes[this->routeCount].via)
.unmarshal(blob->data(), (int)(blob->size() - p));
if (l < 0) if (l < 0)
return false; return false;
p += l; p += l;
if ((p + 4) > blob->size()) if ((p + 4) > blob->size())
return false; return false;
this->routes[this->routeCount].flags = Utils::loadBigEndian<uint16_t>(blob->data() + p); p += 2; this->routes[this->routeCount].flags = Utils::loadBigEndian<uint16_t>(blob->data() + p);
this->routes[this->routeCount].metric = Utils::loadBigEndian<uint16_t>(blob->data() + p); p += 2; p += 2;
this->routes[this->routeCount].metric = Utils::loadBigEndian<uint16_t>(blob->data() + p);
p += 2;
++this->routeCount; ++this->routeCount;
} }
} }
blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS]); blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_STATIC_IPS]);
if (!blob->empty()) { if (! blob->empty()) {
unsigned int p = 0; unsigned int p = 0;
while ((p < blob->size())&&(staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) { while ((p < blob->size()) && (staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) {
int l = this->staticIps[this->staticIpCount].unmarshal(blob->data() + p,(int)(blob->size() - p)); int l = this->staticIps[this->staticIpCount].unmarshal(blob->data() + p, (int)(blob->size() - p));
if (l < 0) if (l < 0)
return false; return false;
p += l; p += l;
@ -244,22 +264,30 @@ bool NetworkConfig::fromDictionary(const Dictionary &d)
} }
blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_RULES]); blob = &(d[ZT_NETWORKCONFIG_DICT_KEY_RULES]);
if (!blob->empty()) { if (! blob->empty()) {
this->ruleCount = 0; this->ruleCount = 0;
if (CapabilityCredential::unmarshalVirtualNetworkRules(blob->data(), (int)blob->size(), this->rules, this->ruleCount, ZT_MAX_NETWORK_RULES) < 0) if (CapabilityCredential::unmarshalVirtualNetworkRules(
blob->data(),
(int)blob->size(),
this->rules,
this->ruleCount,
ZT_MAX_NETWORK_RULES)
< 0)
return false; return false;
} }
} }
return true; return true;
} catch ( ... ) {} }
catch (...) {
}
return false; return false;
} }
bool NetworkConfig::addSpecialist(const Address &a,const uint64_t f) noexcept bool NetworkConfig::addSpecialist(const Address& a, const uint64_t f) noexcept
{ {
const uint64_t aint = a.toInt(); const uint64_t aint = a.toInt();
for(unsigned int i=0;i<specialistCount;++i) { for (unsigned int i = 0; i < specialistCount; ++i) {
if ((specialists[i] & 0xffffffffffULL) == aint) { if ((specialists[i] & 0xffffffffffULL) == aint) {
specialists[i] |= f; specialists[i] |= f;
return true; return true;

View file

@ -14,23 +14,23 @@
#ifndef ZT_NETWORKCONFIG_HPP #ifndef ZT_NETWORKCONFIG_HPP
#define ZT_NETWORKCONFIG_HPP #define ZT_NETWORKCONFIG_HPP
#include "Constants.hpp"
#include "InetAddress.hpp"
#include "MulticastGroup.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "MembershipCredential.hpp"
#include "OwnershipCredential.hpp"
#include "CapabilityCredential.hpp" #include "CapabilityCredential.hpp"
#include "TagCredential.hpp" #include "Constants.hpp"
#include "Containers.hpp"
#include "Dictionary.hpp" #include "Dictionary.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "Utils.hpp" #include "InetAddress.hpp"
#include "MembershipCredential.hpp"
#include "MulticastGroup.hpp"
#include "OwnershipCredential.hpp"
#include "TagCredential.hpp"
#include "Trace.hpp" #include "Trace.hpp"
#include "TriviallyCopyable.hpp" #include "TriviallyCopyable.hpp"
#include "Containers.hpp" #include "Utils.hpp"
#include <stdexcept>
#include <algorithm> #include <algorithm>
#include <stdexcept>
namespace ZeroTier { namespace ZeroTier {
@ -144,10 +144,11 @@ namespace ZeroTier {
/** /**
* Network configuration received from network controller nodes * Network configuration received from network controller nodes
*/ */
struct NetworkConfig : TriviallyCopyable struct NetworkConfig : TriviallyCopyable {
{
ZT_INLINE NetworkConfig() noexcept ZT_INLINE NetworkConfig() noexcept
{ memoryZero(this); } // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) {
memoryZero(this);
} // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
/** /**
* Write this network config to a dictionary for transport * Write this network config to a dictionary for transport
@ -155,7 +156,7 @@ struct NetworkConfig : TriviallyCopyable
* @param d Dictionary * @param d Dictionary
* @return True if dictionary was successfully created, false if e.g. overflow * @return True if dictionary was successfully created, false if e.g. overflow
*/ */
bool toDictionary(Dictionary &d) const; bool toDictionary(Dictionary& d) const;
/** /**
* Read this network config from a dictionary * Read this network config from a dictionary
@ -163,52 +164,67 @@ struct NetworkConfig : TriviallyCopyable
* @param d Dictionary (non-const since it might be modified during parse, should not be used after call) * @param d Dictionary (non-const since it might be modified during parse, should not be used after call)
* @return True if dictionary was valid and network config successfully initialized * @return True if dictionary was valid and network config successfully initialized
*/ */
bool fromDictionary(const Dictionary &d); bool fromDictionary(const Dictionary& d);
/** /**
* @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network * @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network
*/ */
ZT_INLINE bool enableBroadcast() const noexcept ZT_INLINE bool enableBroadcast() const noexcept
{ return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); } {
return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0);
}
/** /**
* @return True if IPv6 NDP emulation should be allowed for certain "magic" IPv6 address patterns * @return True if IPv6 NDP emulation should be allowed for certain "magic" IPv6 address patterns
*/ */
ZT_INLINE bool ndpEmulation() const noexcept ZT_INLINE bool ndpEmulation() const noexcept
{ return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); } {
return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0);
}
/** /**
* @return Network type is public (no access control) * @return Network type is public (no access control)
*/ */
ZT_INLINE bool isPublic() const noexcept ZT_INLINE bool isPublic() const noexcept
{ return (this->type == ZT_NETWORK_TYPE_PUBLIC); } {
return (this->type == ZT_NETWORK_TYPE_PUBLIC);
}
/** /**
* @return Network type is private (certificate access control) * @return Network type is private (certificate access control)
*/ */
ZT_INLINE bool isPrivate() const noexcept ZT_INLINE bool isPrivate() const noexcept
{ return (this->type == ZT_NETWORK_TYPE_PRIVATE); } {
return (this->type == ZT_NETWORK_TYPE_PRIVATE);
}
/** /**
* @param fromPeer Peer attempting to bridge other Ethernet peers onto network * @param fromPeer Peer attempting to bridge other Ethernet peers onto network
* @return True if this network allows bridging * @return True if this network allows bridging
*/ */
ZT_INLINE bool permitsBridging(const Address &fromPeer) const noexcept ZT_INLINE bool permitsBridging(const Address& fromPeer) const noexcept
{ {
for (unsigned int i = 0;i < specialistCount;++i) { for (unsigned int i = 0; i < specialistCount; ++i) {
if ((fromPeer.toInt() == (specialists[i] & ZT_ADDRESS_MASK)) && ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0)) if ((fromPeer.toInt() == (specialists[i] & ZT_ADDRESS_MASK))
&& ((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0))
return true; return true;
} }
return false; return false;
} }
ZT_INLINE operator bool() const noexcept ZT_INLINE operator bool() const noexcept
{ return (networkId != 0); } // NOLINT(google-explicit-constructor,hicpp-explicit-conversions) {
ZT_INLINE bool operator==(const NetworkConfig &nc) const noexcept return (networkId != 0);
{ return (memcmp(this, &nc, sizeof(NetworkConfig)) == 0); } } // NOLINT(google-explicit-constructor,hicpp-explicit-conversions)
ZT_INLINE bool operator==(const NetworkConfig& nc) const noexcept
{
return (memcmp(this, &nc, sizeof(NetworkConfig)) == 0);
}
ZT_INLINE bool operator!=(const NetworkConfig &nc) const noexcept ZT_INLINE bool operator!=(const NetworkConfig& nc) const noexcept
{ return (!(*this == nc)); } {
return (! (*this == nc));
}
/** /**
* Add a specialist or mask flags if already present * Add a specialist or mask flags if already present
@ -220,20 +236,20 @@ struct NetworkConfig : TriviallyCopyable
* @param f Flags (OR of specialist role/type flags) * @param f Flags (OR of specialist role/type flags)
* @return True if successfully masked or added * @return True if successfully masked or added
*/ */
bool addSpecialist(const Address &a, uint64_t f) noexcept; bool addSpecialist(const Address& a, uint64_t f) noexcept;
ZT_INLINE const CapabilityCredential *capability(const uint32_t id) const ZT_INLINE const CapabilityCredential* capability(const uint32_t id) const
{ {
for (unsigned int i = 0;i < capabilityCount;++i) { for (unsigned int i = 0; i < capabilityCount; ++i) {
if (capabilities[i].id() == id) if (capabilities[i].id() == id)
return &(capabilities[i]); return &(capabilities[i]);
} }
return nullptr; return nullptr;
} }
ZT_INLINE const TagCredential *tag(const uint32_t id) const ZT_INLINE const TagCredential* tag(const uint32_t id) const
{ {
for (unsigned int i = 0;i < tagCount;++i) { for (unsigned int i = 0; i < tagCount; ++i) {
if (tags[i].id() == id) if (tags[i].id() == id)
return &(tags[i]); return &(tags[i]);
} }

View file

@ -14,11 +14,11 @@
#ifndef ZT_NETWORKCONFIGMASTER_HPP #ifndef ZT_NETWORKCONFIGMASTER_HPP
#define ZT_NETWORKCONFIGMASTER_HPP #define ZT_NETWORKCONFIGMASTER_HPP
#include "Address.hpp"
#include "Constants.hpp" #include "Constants.hpp"
#include "Dictionary.hpp" #include "Dictionary.hpp"
#include "NetworkConfig.hpp" #include "NetworkConfig.hpp"
#include "RevocationCredential.hpp" #include "RevocationCredential.hpp"
#include "Address.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -28,11 +28,9 @@ struct InetAddress;
/** /**
* Interface for network controller implementations * Interface for network controller implementations
*/ */
class NetworkController class NetworkController {
{ public:
public: enum ErrorCode {
enum ErrorCode
{
NC_ERROR_NONE = 0, NC_ERROR_NONE = 0,
NC_ERROR_OBJECT_NOT_FOUND = 1, NC_ERROR_OBJECT_NOT_FOUND = 1,
NC_ERROR_ACCESS_DENIED = 2, NC_ERROR_ACCESS_DENIED = 2,
@ -42,19 +40,27 @@ public:
/** /**
* Interface for sender used to send pushes and replies * Interface for sender used to send pushes and replies
*/ */
class Sender class Sender {
{
public: public:
/** /**
* Send a configuration to a remote peer * Send a configuration to a remote peer
* *
* @param nwid Network ID * @param nwid Network ID
* @param requestPacketId Request packet ID to send OK(NETWORK_CONFIG_REQUEST) or 0 to send NETWORK_CONFIG (push) * @param requestPacketId Request packet ID to send OK(NETWORK_CONFIG_REQUEST) or 0 to send NETWORK_CONFIG
* (push)
* @param destination Destination peer Address * @param destination Destination peer Address
* @param nc Network configuration to send * @param nc Network configuration to send
* @param sendLegacyFormatConfig If true, send an old-format network config * @param sendLegacyFormatConfig If true, send an old-format network config
*/ */
virtual void ncSendConfig(void *tPtr, int64_t clock, int64_t ticks, uint64_t nwid, uint64_t requestPacketId, const Address &destination, const NetworkConfig &nc, bool sendLegacyFormatConfig) = 0; virtual void ncSendConfig(
void* tPtr,
int64_t clock,
int64_t ticks,
uint64_t nwid,
uint64_t requestPacketId,
const Address& destination,
const NetworkConfig& nc,
bool sendLegacyFormatConfig) = 0;
/** /**
* Send revocation to a node * Send revocation to a node
@ -62,7 +68,12 @@ public:
* @param destination Destination node address * @param destination Destination node address
* @param rev Revocation to send * @param rev Revocation to send
*/ */
virtual void ncSendRevocation(void *tPtr, int64_t clock, int64_t ticks, const Address &destination, const RevocationCredential &rev) = 0; virtual void ncSendRevocation(
void* tPtr,
int64_t clock,
int64_t ticks,
const Address& destination,
const RevocationCredential& rev) = 0;
/** /**
* Send a network configuration request error * Send a network configuration request error
@ -72,11 +83,22 @@ public:
* @param destination Destination peer Address * @param destination Destination peer Address
* @param errorCode Error code * @param errorCode Error code
*/ */
virtual void ncSendError(void *tPtr, int64_t clock, int64_t ticks, uint64_t nwid, uint64_t requestPacketId, const Address &destination, NetworkController::ErrorCode errorCode) = 0; virtual void ncSendError(
void* tPtr,
int64_t clock,
int64_t ticks,
uint64_t nwid,
uint64_t requestPacketId,
const Address& destination,
NetworkController::ErrorCode errorCode) = 0;
}; };
NetworkController() {} NetworkController()
virtual ~NetworkController() {} {
}
virtual ~NetworkController()
{
}
/** /**
* Called when this is added to a Node to initialize and supply info * Called when this is added to a Node to initialize and supply info
@ -84,7 +106,7 @@ public:
* @param signingId Identity for signing of network configurations, certs, etc. * @param signingId Identity for signing of network configurations, certs, etc.
* @param sender Sender implementation for sending replies or config pushes * @param sender Sender implementation for sending replies or config pushes
*/ */
virtual void init(const Identity &signingId, Sender *sender) = 0; virtual void init(const Identity& signingId, Sender* sender) = 0;
/** /**
* Handle a network configuration request * Handle a network configuration request
@ -98,10 +120,10 @@ public:
*/ */
virtual void request( virtual void request(
uint64_t nwid, uint64_t nwid,
const InetAddress &fromAddr, const InetAddress& fromAddr,
uint64_t requestPacketId, uint64_t requestPacketId,
const Identity &identity, const Identity& identity,
const Dictionary &metaData) = 0; const Dictionary& metaData) = 0;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -11,39 +11,39 @@
*/ */
/****/ /****/
#include "Constants.hpp"
#include "SharedPtr.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "NetworkController.hpp"
#include "Topology.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Identity.hpp" #include "Buf.hpp"
#include "SelfAwareness.hpp" #include "Constants.hpp"
#include "Network.hpp"
#include "Trace.hpp"
#include "Locator.hpp"
#include "Expect.hpp" #include "Expect.hpp"
#include "Identity.hpp"
#include "Locator.hpp"
#include "Network.hpp"
#include "NetworkController.hpp"
#include "SelfAwareness.hpp"
#include "SharedPtr.hpp"
#include "Store.hpp"
#include "Topology.hpp"
#include "Trace.hpp"
#include "TrustStore.hpp"
#include "VL1.hpp" #include "VL1.hpp"
#include "VL2.hpp" #include "VL2.hpp"
#include "Buf.hpp"
#include "TrustStore.hpp"
#include "Store.hpp"
namespace ZeroTier { namespace ZeroTier {
namespace { namespace {
struct _NodeObjects struct _NodeObjects {
{ ZT_INLINE _NodeObjects(Context& ctx, const CallContext& cc)
ZT_INLINE _NodeObjects(Context &ctx, const CallContext &cc) : : networks()
networks(), , t(ctx)
t(ctx), , expect()
expect(), , vl2(ctx)
vl2(ctx), , vl1(ctx)
vl1(ctx), , topology(ctx, cc)
topology(ctx, cc), , sa(ctx)
sa(ctx), , ts()
ts()
{ {
ctx.networks = &networks; ctx.networks = &networks;
ctx.t = &t; ctx.t = &t;
@ -55,7 +55,7 @@ struct _NodeObjects
ctx.ts = &ts; ctx.ts = &ts;
} }
TinyMap< SharedPtr< Network > > networks; TinyMap<SharedPtr<Network> > networks;
Trace t; Trace t;
Expect expect; Expect expect;
VL2 vl2; VL2 vl2;
@ -67,27 +67,27 @@ struct _NodeObjects
} // anonymous namespace } // anonymous namespace
Node::Node(void *uPtr, const struct ZT_Node_Callbacks *callbacks, const CallContext &cc) : Node::Node(void* uPtr, const struct ZT_Node_Callbacks* callbacks, const CallContext& cc)
m_ctx(this), : m_ctx(this)
m_store(m_ctx), , m_store(m_ctx)
m_objects(nullptr), , m_objects(nullptr)
m_lastPeerPulse(0), , m_lastPeerPulse(0)
m_lastHousekeepingRun(0), , m_lastHousekeepingRun(0)
m_lastNetworkHousekeepingRun(0), , m_lastNetworkHousekeepingRun(0)
m_lastTrustStoreUpdate(0), , m_lastTrustStoreUpdate(0)
m_online(false) , m_online(false)
{ {
ZT_SPEW("Node starting up!"); ZT_SPEW("Node starting up!");
Utils::copy< sizeof(ZT_Node_Callbacks) >(&m_ctx.cb, callbacks); Utils::copy<sizeof(ZT_Node_Callbacks)>(&m_ctx.cb, callbacks);
m_ctx.uPtr = uPtr; m_ctx.uPtr = uPtr;
m_ctx.store = &m_store; m_ctx.store = &m_store;
Vector< uint8_t > data(m_store.get(cc, ZT_STATE_OBJECT_IDENTITY_SECRET, Utils::ZERO256, 0)); Vector<uint8_t> data(m_store.get(cc, ZT_STATE_OBJECT_IDENTITY_SECRET, Utils::ZERO256, 0));
bool haveIdentity = false; bool haveIdentity = false;
if (!data.empty()) { if (! data.empty()) {
data.push_back(0); // zero-terminate string data.push_back(0); // zero-terminate string
if (m_ctx.identity.fromString((const char *)data.data())) { if (m_ctx.identity.fromString((const char*)data.data())) {
m_ctx.identity.toString(false, m_ctx.publicIdentityStr); m_ctx.identity.toString(false, m_ctx.publicIdentityStr);
m_ctx.identity.toString(true, m_ctx.secretIdentityStr); m_ctx.identity.toString(true, m_ctx.secretIdentityStr);
haveIdentity = true; haveIdentity = true;
@ -95,17 +95,36 @@ Node::Node(void *uPtr, const struct ZT_Node_Callbacks *callbacks, const CallCont
} }
} }
if (!haveIdentity) { if (! haveIdentity) {
m_ctx.identity.generate(Identity::C25519); m_ctx.identity.generate(Identity::C25519);
m_ctx.identity.toString(false, m_ctx.publicIdentityStr); m_ctx.identity.toString(false, m_ctx.publicIdentityStr);
m_ctx.identity.toString(true, m_ctx.secretIdentityStr); m_ctx.identity.toString(true, m_ctx.secretIdentityStr);
m_store.put(cc, ZT_STATE_OBJECT_IDENTITY_SECRET, Utils::ZERO256, 0, m_ctx.secretIdentityStr, (unsigned int)strlen(m_ctx.secretIdentityStr)); m_store.put(
m_store.put(cc, ZT_STATE_OBJECT_IDENTITY_PUBLIC, Utils::ZERO256, 0, m_ctx.publicIdentityStr, (unsigned int)strlen(m_ctx.publicIdentityStr)); cc,
ZT_STATE_OBJECT_IDENTITY_SECRET,
Utils::ZERO256,
0,
m_ctx.secretIdentityStr,
(unsigned int)strlen(m_ctx.secretIdentityStr));
m_store.put(
cc,
ZT_STATE_OBJECT_IDENTITY_PUBLIC,
Utils::ZERO256,
0,
m_ctx.publicIdentityStr,
(unsigned int)strlen(m_ctx.publicIdentityStr));
ZT_SPEW("no pre-existing identity found, created %s", m_ctx.identity.toString().c_str()); ZT_SPEW("no pre-existing identity found, created %s", m_ctx.identity.toString().c_str());
} else { }
else {
data = m_store.get(cc, ZT_STATE_OBJECT_IDENTITY_PUBLIC, Utils::ZERO256, 0); data = m_store.get(cc, ZT_STATE_OBJECT_IDENTITY_PUBLIC, Utils::ZERO256, 0);
if ((data.empty()) || (memcmp(data.data(), m_ctx.publicIdentityStr, strlen(m_ctx.publicIdentityStr)) != 0)) if ((data.empty()) || (memcmp(data.data(), m_ctx.publicIdentityStr, strlen(m_ctx.publicIdentityStr)) != 0))
m_store.put(cc, ZT_STATE_OBJECT_IDENTITY_PUBLIC, Utils::ZERO256, 0, m_ctx.publicIdentityStr, (unsigned int)strlen(m_ctx.publicIdentityStr)); m_store.put(
cc,
ZT_STATE_OBJECT_IDENTITY_PUBLIC,
Utils::ZERO256,
0,
m_ctx.publicIdentityStr,
(unsigned int)strlen(m_ctx.publicIdentityStr));
} }
uint8_t localSecretCipherKey[ZT_FINGERPRINT_HASH_SIZE]; uint8_t localSecretCipherKey[ZT_FINGERPRINT_HASH_SIZE];
@ -142,7 +161,7 @@ Node::~Node()
m_allNetworks.clear(); m_allNetworks.clear();
m_allNetworks_l.unlock(); m_allNetworks_l.unlock();
delete reinterpret_cast<_NodeObjects *>(m_objects); delete reinterpret_cast<_NodeObjects*>(m_objects);
// Let go of cached Buf objects. If other nodes happen to be running in this // Let go of cached Buf objects. If other nodes happen to be running in this
// same process space new Bufs will be allocated as needed, but this is almost // same process space new Bufs will be allocated as needed, but this is almost
@ -151,7 +170,7 @@ Node::~Node()
Buf::freePool(); Buf::freePool();
} }
void Node::shutdown(const CallContext &cc) void Node::shutdown(const CallContext& cc)
{ {
m_allNetworks_l.lock(); m_allNetworks_l.lock();
m_ctx.networks->clear(); m_ctx.networks->clear();
@ -164,7 +183,7 @@ void Node::shutdown(const CallContext &cc)
m_ctx.topology->saveAll(cc); m_ctx.topology->saveAll(cc);
} }
ZT_ResultCode Node::processBackgroundTasks(const CallContext &cc, volatile int64_t *nextBackgroundTaskDeadline) ZT_ResultCode Node::processBackgroundTasks(const CallContext& cc, volatile int64_t* nextBackgroundTaskDeadline)
{ {
Mutex::Lock bl(m_backgroundTasksLock); Mutex::Lock bl(m_backgroundTasksLock);
@ -183,7 +202,7 @@ ZT_ResultCode Node::processBackgroundTasks(const CallContext &cc, volatile int64
m_lastNetworkHousekeepingRun = cc.ticks; m_lastNetworkHousekeepingRun = cc.ticks;
ZT_SPEW("running networking housekeeping..."); ZT_SPEW("running networking housekeeping...");
Mutex::Lock l(m_allNetworks_l); Mutex::Lock l(m_allNetworks_l);
for (Vector< SharedPtr< Network > >::const_iterator n(m_allNetworks.begin()); n != m_allNetworks.end(); ++n) for (Vector<SharedPtr<Network> >::const_iterator n(m_allNetworks.begin()); n != m_allNetworks.end(); ++n)
(*n)->doPeriodicTasks(cc); (*n)->doPeriodicTasks(cc);
} }
@ -203,15 +222,17 @@ ZT_ResultCode Node::processBackgroundTasks(const CallContext &cc, volatile int64
m_lastPeerPulse = cc.ticks; m_lastPeerPulse = cc.ticks;
ZT_SPEW("running pulse() on each peer..."); ZT_SPEW("running pulse() on each peer...");
try { try {
Vector< SharedPtr< Peer > > allPeers, rootPeers; Vector<SharedPtr<Peer> > allPeers, rootPeers;
m_ctx.topology->allPeers(allPeers, rootPeers); m_ctx.topology->allPeers(allPeers, rootPeers);
std::sort(rootPeers.begin(), rootPeers.end()); std::sort(rootPeers.begin(), rootPeers.end());
bool online = false; bool online = false;
for (Vector< SharedPtr< Peer > >::iterator p(allPeers.begin()); p != allPeers.end(); ++p) { for (Vector<SharedPtr<Peer> >::iterator p(allPeers.begin()); p != allPeers.end(); ++p) {
(*p)->pulse(m_ctx, cc); (*p)->pulse(m_ctx, cc);
if (!online) { if (! online) {
online = ((std::binary_search(rootPeers.begin(), rootPeers.end(), *p) || rootPeers.empty()) && (*p)->directlyConnected()); online =
((std::binary_search(rootPeers.begin(), rootPeers.end(), *p) || rootPeers.empty())
&& (*p)->directlyConnected());
} }
} }
@ -220,20 +241,22 @@ ZT_ResultCode Node::processBackgroundTasks(const CallContext &cc, volatile int64
ZT_SPEW("ranking roots..."); ZT_SPEW("ranking roots...");
m_ctx.topology->rankRoots(cc); m_ctx.topology->rankRoots(cc);
} catch (...) { }
catch (...) {
return ZT_RESULT_FATAL_ERROR_INTERNAL; return ZT_RESULT_FATAL_ERROR_INTERNAL;
} }
} }
*nextBackgroundTaskDeadline = cc.ticks + ZT_TIMER_TASK_INTERVAL; *nextBackgroundTaskDeadline = cc.ticks + ZT_TIMER_TASK_INTERVAL;
} catch (...) { }
catch (...) {
return ZT_RESULT_FATAL_ERROR_INTERNAL; return ZT_RESULT_FATAL_ERROR_INTERNAL;
} }
return ZT_RESULT_OK; return ZT_RESULT_OK;
} }
ZT_ResultCode Node::join(uint64_t nwid, const ZT_Fingerprint *controllerFingerprint, void *uptr, const CallContext &cc) ZT_ResultCode Node::join(uint64_t nwid, const ZT_Fingerprint* controllerFingerprint, void* uptr, const CallContext& cc)
{ {
Mutex::Lock l(m_allNetworks_l); Mutex::Lock l(m_allNetworks_l);
@ -241,31 +264,32 @@ ZT_ResultCode Node::join(uint64_t nwid, const ZT_Fingerprint *controllerFingerpr
if (controllerFingerprint) { if (controllerFingerprint) {
fp = *controllerFingerprint; fp = *controllerFingerprint;
ZT_SPEW("joining network %.16llx with controller fingerprint %s", nwid, fp.toString().c_str()); ZT_SPEW("joining network %.16llx with controller fingerprint %s", nwid, fp.toString().c_str());
} else { }
else {
ZT_SPEW("joining network %.16llx", nwid); ZT_SPEW("joining network %.16llx", nwid);
} }
for (Vector< SharedPtr< Network > >::iterator n(m_allNetworks.begin()); n != m_allNetworks.end(); ++n) { for (Vector<SharedPtr<Network> >::iterator n(m_allNetworks.begin()); n != m_allNetworks.end(); ++n) {
if ((*n)->id() == nwid) if ((*n)->id() == nwid)
return ZT_RESULT_OK; return ZT_RESULT_OK;
} }
SharedPtr< Network > network(new Network(m_ctx, cc, nwid, fp, uptr, nullptr)); SharedPtr<Network> network(new Network(m_ctx, cc, nwid, fp, uptr, nullptr));
m_allNetworks.push_back(network); m_allNetworks.push_back(network);
m_ctx.networks->set(nwid, network); m_ctx.networks->set(nwid, network);
return ZT_RESULT_OK; return ZT_RESULT_OK;
} }
ZT_ResultCode Node::leave(uint64_t nwid, void **uptr, const CallContext &cc) ZT_ResultCode Node::leave(uint64_t nwid, void** uptr, const CallContext& cc)
{ {
Mutex::Lock l(m_allNetworks_l); Mutex::Lock l(m_allNetworks_l);
ZT_SPEW("leaving network %.16llx", nwid); ZT_SPEW("leaving network %.16llx", nwid);
ZT_VirtualNetworkConfig ctmp; ZT_VirtualNetworkConfig ctmp;
SharedPtr< Network > network; SharedPtr<Network> network;
m_ctx.networks->erase(nwid); m_ctx.networks->erase(nwid);
for (Vector< SharedPtr< Network > >::iterator n(m_allNetworks.begin()); n != m_allNetworks.end(); ++n) { for (Vector<SharedPtr<Network> >::iterator n(m_allNetworks.begin()); n != m_allNetworks.end(); ++n) {
if ((*n)->id() == nwid) { if ((*n)->id() == nwid) {
network.move(*n); network.move(*n);
m_allNetworks.erase(n); m_allNetworks.erase(n);
@ -282,88 +306,100 @@ ZT_ResultCode Node::leave(uint64_t nwid, void **uptr, const CallContext &cc)
if (uptr) if (uptr)
*uptr = *network->userPtr(); *uptr = *network->userPtr();
network->externalConfig(&ctmp); network->externalConfig(&ctmp);
m_ctx.cb.virtualNetworkConfigFunction(reinterpret_cast<ZT_Node *>(this), m_ctx.uPtr, cc.tPtr, nwid, network->userPtr(), ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY, &ctmp); m_ctx.cb.virtualNetworkConfigFunction(
reinterpret_cast<ZT_Node*>(this),
m_ctx.uPtr,
cc.tPtr,
nwid,
network->userPtr(),
ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,
&ctmp);
network->destroy(); network->destroy();
return ZT_RESULT_OK; return ZT_RESULT_OK;
} else { }
else {
return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
} }
} }
ZT_ResultCode Node::multicastSubscribe(const CallContext &cc, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi) ZT_ResultCode
Node::multicastSubscribe(const CallContext& cc, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi)
{ {
ZT_SPEW("multicast subscribe to %s:%lu", MAC(multicastGroup).toString().c_str(), multicastAdi); ZT_SPEW("multicast subscribe to %s:%lu", MAC(multicastGroup).toString().c_str(), multicastAdi);
const SharedPtr< Network > nw(m_ctx.networks->get(nwid)); const SharedPtr<Network> nw(m_ctx.networks->get(nwid));
if (nw) { if (nw) {
nw->multicastSubscribe(cc, MulticastGroup(MAC(multicastGroup), (uint32_t)(multicastAdi & 0xffffffff))); nw->multicastSubscribe(cc, MulticastGroup(MAC(multicastGroup), (uint32_t)(multicastAdi & 0xffffffff)));
return ZT_RESULT_OK; return ZT_RESULT_OK;
} else { }
else {
return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
} }
} }
ZT_ResultCode Node::multicastUnsubscribe(const CallContext &cc, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi) ZT_ResultCode
Node::multicastUnsubscribe(const CallContext& cc, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi)
{ {
ZT_SPEW("multicast unsubscribe from %s:%lu", MAC(multicastGroup).toString().c_str(), multicastAdi); ZT_SPEW("multicast unsubscribe from %s:%lu", MAC(multicastGroup).toString().c_str(), multicastAdi);
const SharedPtr< Network > nw(m_ctx.networks->get(nwid)); const SharedPtr<Network> nw(m_ctx.networks->get(nwid));
if (nw) { if (nw) {
nw->multicastUnsubscribe(MulticastGroup(MAC(multicastGroup), (uint32_t)(multicastAdi & 0xffffffff))); nw->multicastUnsubscribe(MulticastGroup(MAC(multicastGroup), (uint32_t)(multicastAdi & 0xffffffff)));
return ZT_RESULT_OK; return ZT_RESULT_OK;
} else { }
else {
return ZT_RESULT_ERROR_NETWORK_NOT_FOUND; return ZT_RESULT_ERROR_NETWORK_NOT_FOUND;
} }
} }
void Node::status(ZT_NodeStatus *status) const void Node::status(ZT_NodeStatus* status) const
{ {
status->address = m_ctx.identity.address().toInt(); status->address = m_ctx.identity.address().toInt();
status->identity = reinterpret_cast<const ZT_Identity *>(&m_ctx.identity); status->identity = reinterpret_cast<const ZT_Identity*>(&m_ctx.identity);
status->publicIdentity = m_ctx.publicIdentityStr; status->publicIdentity = m_ctx.publicIdentityStr;
status->secretIdentity = m_ctx.secretIdentityStr; status->secretIdentity = m_ctx.secretIdentityStr;
status->online = m_online ? 1 : 0; status->online = m_online ? 1 : 0;
} }
struct p_ZT_PeerListPrivate : public ZT_PeerList struct p_ZT_PeerListPrivate : public ZT_PeerList {
{
// Actual containers for the memory, hidden from external users. // Actual containers for the memory, hidden from external users.
Vector< ZT_Peer > p_peers; Vector<ZT_Peer> p_peers;
ForwardList< Vector< ZT_Path > > p_paths; ForwardList<Vector<ZT_Path> > p_paths;
ForwardList< Identity > p_identities; ForwardList<Identity> p_identities;
ForwardList< Blob< ZT_LOCATOR_MARSHAL_SIZE_MAX > > p_locators; ForwardList<Blob<ZT_LOCATOR_MARSHAL_SIZE_MAX> > p_locators;
}; };
static void p_peerListFreeFunction(const void *pl) static void p_peerListFreeFunction(const void* pl)
{ {
if (pl) if (pl)
delete reinterpret_cast<p_ZT_PeerListPrivate *>(const_cast<void *>(pl)); delete reinterpret_cast<p_ZT_PeerListPrivate*>(const_cast<void*>(pl));
} }
struct p_sortPeerPtrsByAddress struct p_sortPeerPtrsByAddress {
{ ZT_INLINE bool operator()(const SharedPtr<Peer>& a, const SharedPtr<Peer>& b) const noexcept
ZT_INLINE bool operator()(const SharedPtr< Peer > &a, const SharedPtr< Peer > &b) const noexcept {
{ return (a->address() < b->address()); } return (a->address() < b->address());
}
}; };
ZT_PeerList *Node::peers(const CallContext &cc) const ZT_PeerList* Node::peers(const CallContext& cc) const
{ {
p_ZT_PeerListPrivate *pl = nullptr; p_ZT_PeerListPrivate* pl = nullptr;
try { try {
pl = new p_ZT_PeerListPrivate; pl = new p_ZT_PeerListPrivate;
pl->freeFunction = p_peerListFreeFunction; pl->freeFunction = p_peerListFreeFunction;
Vector< SharedPtr< Peer > > peers, rootPeers; Vector<SharedPtr<Peer> > peers, rootPeers;
m_ctx.topology->allPeers(peers, rootPeers); m_ctx.topology->allPeers(peers, rootPeers);
std::sort(peers.begin(), peers.end(), p_sortPeerPtrsByAddress()); std::sort(peers.begin(), peers.end(), p_sortPeerPtrsByAddress());
std::sort(rootPeers.begin(), rootPeers.end()); std::sort(rootPeers.begin(), rootPeers.end());
for (Vector< SharedPtr< Peer > >::iterator pi(peers.begin()); pi != peers.end(); ++pi) { for (Vector<SharedPtr<Peer> >::iterator pi(peers.begin()); pi != peers.end(); ++pi) {
pl->p_peers.push_back(ZT_Peer()); pl->p_peers.push_back(ZT_Peer());
ZT_Peer &p = pl->p_peers.back(); ZT_Peer& p = pl->p_peers.back();
Peer &pp = **pi; Peer& pp = **pi;
p.address = pp.address(); p.address = pp.address();
pl->p_identities.push_front(pp.identity()); pl->p_identities.push_front(pp.identity());
p.identity = reinterpret_cast<const ZT_Identity *>(&(pl->p_identities.front())); p.identity = reinterpret_cast<const ZT_Identity*>(&(pl->p_identities.front()));
p.fingerprint = &(pl->p_identities.front().fingerprint()); p.fingerprint = &(pl->p_identities.front().fingerprint());
uint16_t vProto, vMajor, vMinor, vRevision; uint16_t vProto, vMajor, vMinor, vRevision;
if (pp.remoteVersion(vProto, vMajor, vMinor, vRevision)) { if (pp.remoteVersion(vProto, vMajor, vMinor, vRevision)) {
@ -371,7 +407,8 @@ ZT_PeerList *Node::peers(const CallContext &cc) const
p.versionMinor = (int)vMinor; p.versionMinor = (int)vMinor;
p.versionRev = (int)vRevision; p.versionRev = (int)vRevision;
p.versionProto = (int)vProto; p.versionProto = (int)vProto;
} else { }
else {
p.versionMajor = -1; p.versionMajor = -1;
p.versionMinor = -1; p.versionMinor = -1;
p.versionRev = -1; p.versionRev = -1;
@ -383,17 +420,17 @@ ZT_PeerList *Node::peers(const CallContext &cc) const
p.networks = nullptr; p.networks = nullptr;
p.networkCount = 0; // TODO: networks this peer belongs to p.networkCount = 0; // TODO: networks this peer belongs to
Vector< SharedPtr< Path > > ztPaths; Vector<SharedPtr<Path> > ztPaths;
pp.getAllPaths(ztPaths); pp.getAllPaths(ztPaths);
if (ztPaths.empty()) { if (ztPaths.empty()) {
pl->p_paths.push_front(Vector< ZT_Path >()); pl->p_paths.push_front(Vector<ZT_Path>());
std::vector< ZT_Path > &apiPaths = pl->p_paths.front(); std::vector<ZT_Path>& apiPaths = pl->p_paths.front();
apiPaths.resize(ztPaths.size()); apiPaths.resize(ztPaths.size());
for (unsigned long i = 0; i < (unsigned long)ztPaths.size(); ++i) { for (unsigned long i = 0; i < (unsigned long)ztPaths.size(); ++i) {
SharedPtr< Path > &ztp = ztPaths[i]; SharedPtr<Path>& ztp = ztPaths[i];
ZT_Path &apip = apiPaths[i]; ZT_Path& apip = apiPaths[i];
apip.endpoint.type = ZT_ENDPOINT_TYPE_IP_UDP; apip.endpoint.type = ZT_ENDPOINT_TYPE_IP_UDP;
Utils::copy< sizeof(struct sockaddr_storage) >(&(apip.endpoint.value.ss), &(ztp->address().as.ss)); Utils::copy<sizeof(struct sockaddr_storage)>(&(apip.endpoint.value.ss), &(ztp->address().as.ss));
apip.lastSend = ztp->lastOut(); apip.lastSend = ztp->lastOut();
apip.lastReceive = ztp->lastIn(); apip.lastReceive = ztp->lastIn();
apip.alive = ztp->alive(cc) ? 1 : 0; apip.alive = ztp->alive(cc) ? 1 : 0;
@ -401,16 +438,17 @@ ZT_PeerList *Node::peers(const CallContext &cc) const
} }
p.paths = apiPaths.data(); p.paths = apiPaths.data();
p.pathCount = (unsigned int)apiPaths.size(); p.pathCount = (unsigned int)apiPaths.size();
} else { }
else {
p.paths = nullptr; p.paths = nullptr;
p.pathCount = 0; p.pathCount = 0;
} }
const SharedPtr< const Locator > loc(pp.locator()); const SharedPtr<const Locator> loc(pp.locator());
if (loc) { if (loc) {
pl->p_locators.push_front(Blob< ZT_LOCATOR_MARSHAL_SIZE_MAX >()); pl->p_locators.push_front(Blob<ZT_LOCATOR_MARSHAL_SIZE_MAX>());
Blob< ZT_LOCATOR_MARSHAL_SIZE_MAX > &lb = pl->p_locators.front(); Blob<ZT_LOCATOR_MARSHAL_SIZE_MAX>& lb = pl->p_locators.front();
Utils::zero< ZT_LOCATOR_MARSHAL_SIZE_MAX >(lb.data); Utils::zero<ZT_LOCATOR_MARSHAL_SIZE_MAX>(lb.data);
const int ls = loc->marshal(lb.data); const int ls = loc->marshal(lb.data);
if (ls > 0) { if (ls > 0) {
p.locatorSize = (unsigned int)ls; p.locatorSize = (unsigned int)ls;
@ -423,47 +461,48 @@ ZT_PeerList *Node::peers(const CallContext &cc) const
pl->peerCount = (unsigned long)pl->p_peers.size(); pl->peerCount = (unsigned long)pl->p_peers.size();
return pl; return pl;
} catch (...) { }
catch (...) {
delete pl; delete pl;
return nullptr; return nullptr;
} }
} }
ZT_VirtualNetworkConfig *Node::networkConfig(uint64_t nwid) const ZT_VirtualNetworkConfig* Node::networkConfig(uint64_t nwid) const
{ {
const SharedPtr< Network > nw(m_ctx.networks->get(nwid)); const SharedPtr<Network> nw(m_ctx.networks->get(nwid));
if (nw) { if (nw) {
ZT_VirtualNetworkConfig *const nc = (ZT_VirtualNetworkConfig *)::malloc(sizeof(ZT_VirtualNetworkConfig)); ZT_VirtualNetworkConfig* const nc = (ZT_VirtualNetworkConfig*)::malloc(sizeof(ZT_VirtualNetworkConfig));
nw->externalConfig(nc); nw->externalConfig(nc);
return nc; return nc;
} else { }
else {
return nullptr; return nullptr;
} }
} }
ZT_VirtualNetworkList *Node::networks() const ZT_VirtualNetworkList* Node::networks() const
{ {
Mutex::Lock l(m_allNetworks_l); Mutex::Lock l(m_allNetworks_l);
char *const buf = (char *)::malloc(sizeof(ZT_VirtualNetworkList) + (sizeof(ZT_VirtualNetworkConfig) * m_allNetworks.size())); char* const buf =
if (!buf) (char*)::malloc(sizeof(ZT_VirtualNetworkList) + (sizeof(ZT_VirtualNetworkConfig) * m_allNetworks.size()));
if (! buf)
return nullptr; return nullptr;
ZT_VirtualNetworkList *nl = (ZT_VirtualNetworkList *)buf; ZT_VirtualNetworkList* nl = (ZT_VirtualNetworkList*)buf;
nl->freeFunction = reinterpret_cast<void (*)(const void *)>(free); nl->freeFunction = reinterpret_cast<void (*)(const void*)>(free);
nl->networks = (ZT_VirtualNetworkConfig *)(buf + sizeof(ZT_VirtualNetworkList)); nl->networks = (ZT_VirtualNetworkConfig*)(buf + sizeof(ZT_VirtualNetworkList));
nl->networkCount = 0; nl->networkCount = 0;
for (Vector< SharedPtr< Network > >::const_iterator i(m_allNetworks.begin()); i != m_allNetworks.end(); ++i) for (Vector<SharedPtr<Network> >::const_iterator i(m_allNetworks.begin()); i != m_allNetworks.end(); ++i)
(*i)->externalConfig(&(nl->networks[nl->networkCount++])); (*i)->externalConfig(&(nl->networks[nl->networkCount++]));
return nl; return nl;
} }
void Node::setNetworkUserPtr( void Node::setNetworkUserPtr(uint64_t nwid, void* ptr)
uint64_t nwid,
void *ptr)
{ {
SharedPtr< Network > nw(m_ctx.networks->get(nwid)); SharedPtr<Network> nw(m_ctx.networks->get(nwid));
if (nw) { if (nw) {
m_allNetworks_l.lock(); // ensure no concurrent modification of user PTR in network m_allNetworks_l.lock(); // ensure no concurrent modification of user PTR in network
*(nw->userPtr()) = ptr; *(nw->userPtr()) = ptr;
@ -471,86 +510,89 @@ void Node::setNetworkUserPtr(
} }
} }
void Node::setInterfaceAddresses( void Node::setInterfaceAddresses(const ZT_InterfaceAddress* addrs, unsigned int addrCount)
const ZT_InterfaceAddress *addrs,
unsigned int addrCount)
{ {
Mutex::Lock _l(m_localInterfaceAddresses_m); Mutex::Lock _l(m_localInterfaceAddresses_m);
m_localInterfaceAddresses.clear(); m_localInterfaceAddresses.clear();
for (unsigned int i = 0; i < addrCount; ++i) { for (unsigned int i = 0; i < addrCount; ++i) {
bool dupe = false; bool dupe = false;
for (unsigned int j = 0; j < i; ++j) { for (unsigned int j = 0; j < i; ++j) {
if (*(reinterpret_cast<const InetAddress *>(&addrs[j].address)) == *(reinterpret_cast<const InetAddress *>(&addrs[i].address))) { if (*(reinterpret_cast<const InetAddress*>(&addrs[j].address))
== *(reinterpret_cast<const InetAddress*>(&addrs[i].address))) {
dupe = true; dupe = true;
break; break;
} }
} }
if (!dupe) if (! dupe)
m_localInterfaceAddresses.push_back(addrs[i]); m_localInterfaceAddresses.push_back(addrs[i]);
} }
} }
ZT_CertificateError Node::addCertificate( ZT_CertificateError Node::addCertificate(
const CallContext &cc, const CallContext& cc,
unsigned int localTrust, unsigned int localTrust,
const ZT_Certificate *cert, const ZT_Certificate* cert,
const void *certData, const void* certData,
unsigned int certSize) unsigned int certSize)
{ {
Certificate c; Certificate c;
if (cert) { if (cert) {
c = *cert; c = *cert;
} else { }
if ((!certData) || (!certSize)) else {
if ((! certData) || (! certSize))
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
if (!c.decode(certData, certSize)) if (! c.decode(certData, certSize))
return ZT_CERTIFICATE_ERROR_INVALID_FORMAT; return ZT_CERTIFICATE_ERROR_INVALID_FORMAT;
} }
m_ctx.ts->add(c, localTrust); m_ctx.ts->add(c, localTrust);
m_ctx.ts->update(cc.clock, nullptr); m_ctx.ts->update(cc.clock, nullptr);
SharedPtr< TrustStore::Entry > ent(m_ctx.ts->get(c.getSerialNo())); SharedPtr<TrustStore::Entry> ent(m_ctx.ts->get(c.getSerialNo()));
return (ent) ? ent->error() : ZT_CERTIFICATE_ERROR_INVALID_FORMAT; // should never be null, but if so it means invalid return (ent) ? ent->error()
: ZT_CERTIFICATE_ERROR_INVALID_FORMAT; // should never be null, but if so it means invalid
} }
ZT_ResultCode Node::deleteCertificate( ZT_ResultCode Node::deleteCertificate(const CallContext& cc, const void* serialNo)
const CallContext &cc,
const void *serialNo)
{ {
if (!serialNo) if (! serialNo)
return ZT_RESULT_ERROR_BAD_PARAMETER; return ZT_RESULT_ERROR_BAD_PARAMETER;
m_ctx.ts->erase(H384(serialNo)); m_ctx.ts->erase(H384(serialNo));
m_ctx.ts->update(-1, nullptr); m_ctx.ts->update(-1, nullptr);
return ZT_RESULT_OK; return ZT_RESULT_OK;
} }
struct p_certificateListInternal struct p_certificateListInternal {
{ Vector<SharedPtr<TrustStore::Entry> > entries;
Vector< SharedPtr< TrustStore::Entry > > entries; Vector<const ZT_Certificate*> c;
Vector< const ZT_Certificate * > c; Vector<unsigned int> t;
Vector< unsigned int > t;
}; };
static void p_freeCertificateList(const void *cl) static void p_freeCertificateList(const void* cl)
{ {
if (cl) { if (cl) {
reinterpret_cast<const p_certificateListInternal *>(reinterpret_cast<const uint8_t *>(cl) + sizeof(ZT_CertificateList))->~p_certificateListInternal(); reinterpret_cast<const p_certificateListInternal*>(
free(const_cast<void *>(cl)); reinterpret_cast<const uint8_t*>(cl) + sizeof(ZT_CertificateList))
->~p_certificateListInternal();
free(const_cast<void*>(cl));
} }
} }
ZT_CertificateList *Node::listCertificates() ZT_CertificateList* Node::listCertificates()
{ {
ZT_CertificateList *const cl = (ZT_CertificateList *)malloc(sizeof(ZT_CertificateList) + sizeof(p_certificateListInternal)); ZT_CertificateList* const cl =
if (!cl) (ZT_CertificateList*)malloc(sizeof(ZT_CertificateList) + sizeof(p_certificateListInternal));
if (! cl)
return nullptr; return nullptr;
p_certificateListInternal *const clint = reinterpret_cast<p_certificateListInternal *>(reinterpret_cast<uint8_t *>(cl) + sizeof(ZT_CertificateList)); p_certificateListInternal* const clint =
new(clint) p_certificateListInternal; reinterpret_cast<p_certificateListInternal*>(reinterpret_cast<uint8_t*>(cl) + sizeof(ZT_CertificateList));
new (clint) p_certificateListInternal;
clint->entries = m_ctx.ts->all(false); clint->entries = m_ctx.ts->all(false);
clint->c.reserve(clint->entries.size()); clint->c.reserve(clint->entries.size());
clint->t.reserve(clint->entries.size()); clint->t.reserve(clint->entries.size());
for (Vector< SharedPtr< TrustStore::Entry > >::const_iterator i(clint->entries.begin()); i != clint->entries.end(); ++i) { for (Vector<SharedPtr<TrustStore::Entry> >::const_iterator i(clint->entries.begin()); i != clint->entries.end();
++i) {
clint->c.push_back(&((*i)->certificate())); clint->c.push_back(&((*i)->certificate()));
clint->t.push_back((*i)->localTrust()); clint->t.push_back((*i)->localTrust());
} }
@ -564,10 +606,10 @@ ZT_CertificateList *Node::listCertificates()
} }
int Node::sendUserMessage( int Node::sendUserMessage(
const CallContext &cc, const CallContext& cc,
uint64_t dest, uint64_t dest,
uint64_t /*typeId*/, uint64_t /*typeId*/,
const void */*data*/, const void* /*data*/,
unsigned int /*len*/) unsigned int /*len*/)
{ {
try { try {
@ -582,22 +624,24 @@ int Node::sendUserMessage(
*/ */
return 1; return 1;
} }
} catch (...) {} }
catch (...) {
}
return 0; return 0;
} }
void Node::setController(void *networkControllerInstance) void Node::setController(void* networkControllerInstance)
{ {
m_ctx.localNetworkController = reinterpret_cast<NetworkController *>(networkControllerInstance); m_ctx.localNetworkController = reinterpret_cast<NetworkController*>(networkControllerInstance);
if (networkControllerInstance) if (networkControllerInstance)
m_ctx.localNetworkController->init(m_ctx.identity, this); m_ctx.localNetworkController->init(m_ctx.identity, this);
} }
bool Node::filterPotentialPath(void *tPtr, const Identity &id, int64_t localSocket, const InetAddress &remoteAddress) bool Node::filterPotentialPath(void* tPtr, const Identity& id, int64_t localSocket, const InetAddress& remoteAddress)
{ {
{ {
Mutex::Lock l(m_allNetworks_l); Mutex::Lock l(m_allNetworks_l);
for (Vector< SharedPtr< Network > >::iterator i(m_allNetworks.begin()); i != m_allNetworks.end(); ++i) { for (Vector<SharedPtr<Network> >::iterator i(m_allNetworks.begin()); i != m_allNetworks.end(); ++i) {
for (unsigned int k = 0, j = (*i)->config().staticIpCount; k < j; ++k) { for (unsigned int k = 0, j = (*i)->config().staticIpCount; k < j; ++k) {
if ((*i)->config().staticIps[k].containsAddress(remoteAddress)) if ((*i)->config().staticIps[k].containsAddress(remoteAddress))
return false; return false;
@ -606,62 +650,74 @@ bool Node::filterPotentialPath(void *tPtr, const Identity &id, int64_t localSock
} }
if (m_ctx.cb.pathCheckFunction) { if (m_ctx.cb.pathCheckFunction) {
return (m_ctx.cb.pathCheckFunction( return (
reinterpret_cast<ZT_Node *>(this), m_ctx.cb.pathCheckFunction(
reinterpret_cast<ZT_Node*>(this),
m_ctx.uPtr, m_ctx.uPtr,
tPtr, tPtr,
id.address().toInt(), id.address().toInt(),
(const ZT_Identity *)&id, (const ZT_Identity*)&id,
localSocket, localSocket,
reinterpret_cast<const ZT_InetAddress *>(&remoteAddress)) != 0); reinterpret_cast<const ZT_InetAddress*>(&remoteAddress))
!= 0);
} }
return true; return true;
} }
bool Node::externalPathLookup(void *tPtr, const Identity &id, int family, InetAddress &addr) bool Node::externalPathLookup(void* tPtr, const Identity& id, int family, InetAddress& addr)
{ {
if (m_ctx.cb.pathLookupFunction) { if (m_ctx.cb.pathLookupFunction) {
return (m_ctx.cb.pathLookupFunction( return (
reinterpret_cast<ZT_Node *>(this), m_ctx.cb.pathLookupFunction(
reinterpret_cast<ZT_Node*>(this),
m_ctx.uPtr, m_ctx.uPtr,
tPtr, tPtr,
id.address().toInt(), id.address().toInt(),
reinterpret_cast<const ZT_Identity *>(&id), reinterpret_cast<const ZT_Identity*>(&id),
family, family,
reinterpret_cast<ZT_InetAddress *>(&addr)) == ZT_RESULT_OK); reinterpret_cast<ZT_InetAddress*>(&addr))
== ZT_RESULT_OK);
} }
return false; return false;
} }
// Implementation of NetworkController::Sender ------------------------------------------------------------------------ // Implementation of NetworkController::Sender ------------------------------------------------------------------------
void Node::ncSendConfig(void *tPtr, int64_t clock, int64_t ticks, uint64_t nwid, uint64_t requestPacketId, const Address &destination, const NetworkConfig &nc, bool sendLegacyFormatConfig) void Node::ncSendConfig(
void* tPtr,
int64_t clock,
int64_t ticks,
uint64_t nwid,
uint64_t requestPacketId,
const Address& destination,
const NetworkConfig& nc,
bool sendLegacyFormatConfig)
{ {
if (destination == m_ctx.identity.address()) { if (destination == m_ctx.identity.address()) {
SharedPtr< Network > n(m_ctx.networks->get(nwid)); SharedPtr<Network> n(m_ctx.networks->get(nwid));
if (!n) if (! n)
return; return;
CallContext cc(clock, ticks, tPtr); CallContext cc(clock, ticks, tPtr);
n->setConfiguration(cc, nc, true); n->setConfiguration(cc, nc, true);
} else { }
else {
Dictionary dconf; Dictionary dconf;
if (nc.toDictionary(dconf)) { if (nc.toDictionary(dconf)) {
uint64_t configUpdateId = Utils::random(); uint64_t configUpdateId = Utils::random();
if (!configUpdateId) if (! configUpdateId)
++configUpdateId; ++configUpdateId;
Vector< uint8_t > ddata; Vector<uint8_t> ddata;
dconf.encode(ddata); dconf.encode(ddata);
// TODO // TODO
/* /*
unsigned int chunkIndex = 0; unsigned int chunkIndex = 0;
while (chunkIndex < totalSize) { while (chunkIndex < totalSize) {
const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_PROTO_MAX_PACKET_LENGTH - (ZT_PACKET_IDX_PAYLOAD + 256))); const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_PROTO_MAX_PACKET_LENGTH
Packet outp(destination,m_ctx.identity.address(),(requestPacketId) ? Packet::VERB_OK : Packet::VERB_NETWORK_CONFIG); - (ZT_PACKET_IDX_PAYLOAD + 256))); Packet outp(destination,m_ctx.identity.address(),(requestPacketId) ?
if (requestPacketId) { Packet::VERB_OK : Packet::VERB_NETWORK_CONFIG); if (requestPacketId) { outp.append((unsigned
outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); char)Packet::VERB_NETWORK_CONFIG_REQUEST); outp.append(requestPacketId);
outp.append(requestPacketId);
} }
const unsigned int sigStart = outp.size(); const unsigned int sigStart = outp.size();
@ -675,9 +731,8 @@ void Node::ncSendConfig(void *tPtr, int64_t clock, int64_t ticks, uint64_t nwid,
outp.append((uint32_t)chunkIndex); outp.append((uint32_t)chunkIndex);
uint8_t sig[256]; uint8_t sig[256];
const unsigned int siglen = m_ctx.identity.sign(reinterpret_cast<const uint8_t *>(outp.data()) + sigStart,outp.size() - sigStart,sig,sizeof(sig)); const unsigned int siglen = m_ctx.identity.sign(reinterpret_cast<const uint8_t *>(outp.data()) +
outp.append((uint8_t)1); sigStart,outp.size() - sigStart,sig,sizeof(sig)); outp.append((uint8_t)1); outp.append((uint16_t)siglen);
outp.append((uint16_t)siglen);
outp.append(sig,siglen); outp.append(sig,siglen);
outp.compress(); outp.compress();
@ -689,15 +744,21 @@ void Node::ncSendConfig(void *tPtr, int64_t clock, int64_t ticks, uint64_t nwid,
} }
} }
void Node::ncSendRevocation(void *tPtr, int64_t clock, int64_t ticks, const Address &destination, const RevocationCredential &rev) void Node::ncSendRevocation(
void* tPtr,
int64_t clock,
int64_t ticks,
const Address& destination,
const RevocationCredential& rev)
{ {
if (destination == m_ctx.identity.address()) { if (destination == m_ctx.identity.address()) {
SharedPtr< Network > n(m_ctx.networks->get(rev.networkId())); SharedPtr<Network> n(m_ctx.networks->get(rev.networkId()));
if (!n) if (! n)
return; return;
CallContext cc(clock, ticks, tPtr); CallContext cc(clock, ticks, tPtr);
n->addCredential(cc, m_ctx.identity, rev); n->addCredential(cc, m_ctx.identity, rev);
} else { }
else {
// TODO // TODO
/* /*
Packet outp(destination,m_ctx.identity.address(),Packet::VERB_NETWORK_CREDENTIALS); Packet outp(destination,m_ctx.identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
@ -712,11 +773,18 @@ void Node::ncSendRevocation(void *tPtr, int64_t clock, int64_t ticks, const Addr
} }
} }
void Node::ncSendError(void *tPtr, int64_t clock, int64_t ticks, uint64_t nwid, uint64_t requestPacketId, const Address &destination, NetworkController::ErrorCode errorCode) void Node::ncSendError(
void* tPtr,
int64_t clock,
int64_t ticks,
uint64_t nwid,
uint64_t requestPacketId,
const Address& destination,
NetworkController::ErrorCode errorCode)
{ {
if (destination == m_ctx.identity.address()) { if (destination == m_ctx.identity.address()) {
SharedPtr< Network > n(m_ctx.networks->get(nwid)); SharedPtr<Network> n(m_ctx.networks->get(nwid));
if (!n) if (! n)
return; return;
switch (errorCode) { switch (errorCode) {
case NetworkController::NC_ERROR_OBJECT_NOT_FOUND: case NetworkController::NC_ERROR_OBJECT_NOT_FOUND:
@ -730,7 +798,8 @@ void Node::ncSendError(void *tPtr, int64_t clock, int64_t ticks, uint64_t nwid,
default: default:
break; break;
} }
} else if (requestPacketId) { }
else if (requestPacketId) {
// TODO // TODO
/* /*
Packet outp(destination,m_ctx.identity.address(),Packet::VERB_ERROR); Packet outp(destination,m_ctx.identity.address(),Packet::VERB_ERROR);

View file

@ -14,19 +14,19 @@
#ifndef ZT_NODE_HPP #ifndef ZT_NODE_HPP
#define ZT_NODE_HPP #define ZT_NODE_HPP
#include "Buf.hpp"
#include "CallContext.hpp"
#include "Constants.hpp" #include "Constants.hpp"
#include "Containers.hpp"
#include "Context.hpp" #include "Context.hpp"
#include "InetAddress.hpp" #include "InetAddress.hpp"
#include "Mutex.hpp"
#include "MAC.hpp" #include "MAC.hpp"
#include "Mutex.hpp"
#include "Network.hpp" #include "Network.hpp"
#include "NetworkController.hpp"
#include "Path.hpp" #include "Path.hpp"
#include "Salsa20.hpp" #include "Salsa20.hpp"
#include "NetworkController.hpp"
#include "Buf.hpp"
#include "Containers.hpp"
#include "Store.hpp" #include "Store.hpp"
#include "CallContext.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -35,89 +35,64 @@ namespace ZeroTier {
* *
* The pointer returned by ZT_Node_new() is an instance of this class. * The pointer returned by ZT_Node_new() is an instance of this class.
*/ */
class Node : public NetworkController::Sender class Node : public NetworkController::Sender {
{ public:
public:
// Get rid of alignment warnings on 32-bit Windows // Get rid of alignment warnings on 32-bit Windows
#ifdef __WINDOWS__ #ifdef __WINDOWS__
void * operator new(size_t i) { return _mm_malloc(i,16); } void* operator new(size_t i)
void operator delete(void* p) { _mm_free(p); } {
return _mm_malloc(i, 16);
}
void operator delete(void* p)
{
_mm_free(p);
}
#endif #endif
Node(void *uPtr, const struct ZT_Node_Callbacks *callbacks, const CallContext &cc); Node(void* uPtr, const struct ZT_Node_Callbacks* callbacks, const CallContext& cc);
virtual ~Node(); virtual ~Node();
void shutdown(const CallContext &cc); void shutdown(const CallContext& cc);
ZT_ResultCode processBackgroundTasks( ZT_ResultCode processBackgroundTasks(const CallContext& cc, volatile int64_t* nextBackgroundTaskDeadline);
const CallContext &cc,
volatile int64_t *nextBackgroundTaskDeadline);
ZT_ResultCode join( ZT_ResultCode join(uint64_t nwid, const ZT_Fingerprint* controllerFingerprint, void* uptr, const CallContext& cc);
uint64_t nwid,
const ZT_Fingerprint *controllerFingerprint,
void *uptr,
const CallContext &cc);
ZT_ResultCode leave( ZT_ResultCode leave(uint64_t nwid, void** uptr, const CallContext& cc);
uint64_t nwid,
void **uptr,
const CallContext &cc);
ZT_ResultCode multicastSubscribe( ZT_ResultCode
const CallContext &cc, multicastSubscribe(const CallContext& cc, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi);
uint64_t nwid,
uint64_t multicastGroup,
unsigned long multicastAdi);
ZT_ResultCode multicastUnsubscribe( ZT_ResultCode
const CallContext &cc, multicastUnsubscribe(const CallContext& cc, uint64_t nwid, uint64_t multicastGroup, unsigned long multicastAdi);
uint64_t nwid,
uint64_t multicastGroup,
unsigned long multicastAdi);
void status( void status(ZT_NodeStatus* status) const;
ZT_NodeStatus *status) const;
ZT_PeerList *peers( ZT_PeerList* peers(const CallContext& cc) const;
const CallContext &cc) const;
ZT_VirtualNetworkConfig *networkConfig( ZT_VirtualNetworkConfig* networkConfig(uint64_t nwid) const;
uint64_t nwid) const;
ZT_VirtualNetworkList *networks() const; ZT_VirtualNetworkList* networks() const;
void setNetworkUserPtr( void setNetworkUserPtr(uint64_t nwid, void* ptr);
uint64_t nwid,
void *ptr);
void setInterfaceAddresses( void setInterfaceAddresses(const ZT_InterfaceAddress* addrs, unsigned int addrCount);
const ZT_InterfaceAddress *addrs,
unsigned int addrCount);
ZT_CertificateError addCertificate( ZT_CertificateError addCertificate(
const CallContext &cc, const CallContext& cc,
unsigned int localTrust, unsigned int localTrust,
const ZT_Certificate *cert, const ZT_Certificate* cert,
const void *certData, const void* certData,
unsigned int certSize); unsigned int certSize);
ZT_ResultCode deleteCertificate( ZT_ResultCode deleteCertificate(const CallContext& cc, const void* serialNo);
const CallContext &cc,
const void *serialNo);
ZT_CertificateList *listCertificates(); ZT_CertificateList* listCertificates();
int sendUserMessage( int sendUserMessage(const CallContext& cc, uint64_t dest, uint64_t typeId, const void* data, unsigned int len);
const CallContext &cc,
uint64_t dest,
uint64_t typeId,
const void *data,
unsigned int len);
void setController( void setController(void* networkControllerInstance);
void *networkControllerInstance);
/** /**
* Post an event via external callback * Post an event via external callback
@ -127,8 +102,12 @@ public:
* @param md Event data or NULL if none * @param md Event data or NULL if none
* @param mdSize Size of event data * @param mdSize Size of event data
*/ */
ZT_INLINE void postEvent(void *const tPtr, const ZT_Event ev, const void *const md = nullptr, const unsigned int mdSize = 0) noexcept ZT_INLINE void
{ m_ctx.cb.eventCallback(reinterpret_cast<ZT_Node *>(this), m_ctx.uPtr, tPtr, ev, md, mdSize); } postEvent(void* const tPtr, const ZT_Event ev, const void* const md = nullptr, const unsigned int mdSize = 0)
noexcept
{
m_ctx.cb.eventCallback(reinterpret_cast<ZT_Node*>(this), m_ctx.uPtr, tPtr, ev, md, mdSize);
}
/** /**
* Check whether a path should be used for ZeroTier traffic * Check whether a path should be used for ZeroTier traffic
@ -141,7 +120,7 @@ public:
* @param remoteAddress Remote address * @param remoteAddress Remote address
* @return True if path should be used * @return True if path should be used
*/ */
bool filterPotentialPath(void *tPtr, const Identity &id, int64_t localSocket, const InetAddress &remoteAddress); bool filterPotentialPath(void* tPtr, const Identity& id, int64_t localSocket, const InetAddress& remoteAddress);
/** /**
* Query callback for a physical address for a peer * Query callback for a physical address for a peer
@ -152,35 +131,59 @@ public:
* @param addr Buffer to store address (result paramter) * @param addr Buffer to store address (result paramter)
* @return True if addr was filled with something * @return True if addr was filled with something
*/ */
bool externalPathLookup(void *tPtr, const Identity &id, int family, InetAddress &addr); bool externalPathLookup(void* tPtr, const Identity& id, int family, InetAddress& addr);
ZT_INLINE const Identity &identity() const noexcept ZT_INLINE const Identity& identity() const noexcept
{ return m_ctx.identity; } {
return m_ctx.identity;
}
ZT_INLINE const Context &context() const noexcept ZT_INLINE const Context& context() const noexcept
{ return m_ctx; } {
return m_ctx;
}
// Implementation of NetworkController::Sender interface // Implementation of NetworkController::Sender interface
virtual void ncSendConfig(void *tPtr, int64_t clock, int64_t ticks, uint64_t nwid, uint64_t requestPacketId, const Address &destination, const NetworkConfig &nc, bool sendLegacyFormatConfig); virtual void ncSendConfig(
virtual void ncSendRevocation(void *tPtr, int64_t clock, int64_t ticks, const Address &destination, const RevocationCredential &rev); void* tPtr,
virtual void ncSendError(void *tPtr, int64_t clock, int64_t ticks, uint64_t nwid, uint64_t requestPacketId, const Address &destination, NetworkController::ErrorCode errorCode); int64_t clock,
int64_t ticks,
uint64_t nwid,
uint64_t requestPacketId,
const Address& destination,
const NetworkConfig& nc,
bool sendLegacyFormatConfig);
virtual void ncSendRevocation(
void* tPtr,
int64_t clock,
int64_t ticks,
const Address& destination,
const RevocationCredential& rev);
virtual void ncSendError(
void* tPtr,
int64_t clock,
int64_t ticks,
uint64_t nwid,
uint64_t requestPacketId,
const Address& destination,
NetworkController::ErrorCode errorCode);
private: private:
Context m_ctx; Context m_ctx;
// Data store wrapper // Data store wrapper
Store m_store; Store m_store;
// Pointer to a struct defined in Node that holds instances of core objects. // Pointer to a struct defined in Node that holds instances of core objects.
void *m_objects; void* m_objects;
// This stores networks for rapid iteration, while RR->networks is the primary lookup. // This stores networks for rapid iteration, while RR->networks is the primary lookup.
Vector< SharedPtr< Network > > m_allNetworks; Vector<SharedPtr<Network> > m_allNetworks;
Mutex m_allNetworks_l; Mutex m_allNetworks_l;
// These are local interface addresses that have been configured via the API // These are local interface addresses that have been configured via the API
// and can be pushed to other nodes. // and can be pushed to other nodes.
Vector< ZT_InterfaceAddress > m_localInterfaceAddresses; Vector<ZT_InterfaceAddress> m_localInterfaceAddresses;
Mutex m_localInterfaceAddresses_m; Mutex m_localInterfaceAddresses_m;
// This is locked while running processBackgroundTasks(). // This is locked while running processBackgroundTasks().
@ -193,7 +196,7 @@ private:
int64_t m_lastTrustStoreUpdate; int64_t m_lastTrustStoreUpdate;
// True if at least one root appears reachable. // True if at least one root appears reachable.
std::atomic< bool > m_online; std::atomic<bool> m_online;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -17,7 +17,9 @@
/* Uncomment this to force a whole lot of debug output. */ /* Uncomment this to force a whole lot of debug output. */
#define ZT_DEBUG_SPEW #define ZT_DEBUG_SPEW
#if !defined(__GNUC__) && (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__)) #if ! defined(__GNUC__) \
&& (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 __GNUC__ 3 #define __GNUC__ 3
#endif #endif
@ -48,46 +50,50 @@
#undef __BSD__ #undef __BSD__
#endif #endif
#include <Shlobj.h>
#include <WinSock2.h> #include <WinSock2.h>
#include <ws2tcpip.h>
#include <Windows.h> #include <Windows.h>
#include <memoryapi.h> #include <memoryapi.h>
#include <shlwapi.h> #include <shlwapi.h>
#include <Shlobj.h>
#include <sys/param.h> #include <sys/param.h>
#include <ws2tcpip.h>
#endif /* Microsoft Windows */ #endif /* Microsoft Windows */
#ifndef __WINDOWS__ #ifndef __WINDOWS__
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/types.h>
#include <sys/socket.h> #include <sys/socket.h>
#include <sys/types.h>
#endif /* NOT Microsoft Windows */ #endif /* NOT Microsoft Windows */
#include <stdint.h> #include <stdint.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h>
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64)) #if ( \
defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) \
|| defined(__AMD64__) || defined(_M_X64))
#define ZT_ARCH_X64 1 #define ZT_ARCH_X64 1
#include <xmmintrin.h>
#include <emmintrin.h> #include <emmintrin.h>
#include <immintrin.h> #include <immintrin.h>
#include <xmmintrin.h>
#endif #endif
#if defined(ZT_ARCH_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__386) #if defined(ZT_ARCH_X64) || defined(i386) || defined(__i386) || defined(__i386__) || defined(__i486__) \
|| defined(__i586__) || defined(__i686__) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) \
|| defined(__I86__) || defined(__INTEL__) || defined(__386)
#define ZT_ARCH_X86 1 #define ZT_ARCH_X86 1
#endif #endif
#if !defined(ZT_ARCH_X86) #if ! defined(ZT_ARCH_X86)
#ifndef ZT_NO_UNALIGNED_ACCESS #ifndef ZT_NO_UNALIGNED_ACCESS
#define ZT_NO_UNALIGNED_ACCESS 1 #define ZT_NO_UNALIGNED_ACCESS 1
#endif #endif
#endif #endif
#if defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(ZT_ARCH_ARM_HAS_NEON) #if defined(__ARM_NEON) || defined(__ARM_NEON__) || defined(ZT_ARCH_ARM_HAS_NEON)
#if (defined(__APPLE__) && !defined(__LP64__)) || (defined(__ANDROID__) && defined(__arm__)) #if (defined(__APPLE__) && ! defined(__LP64__)) || (defined(__ANDROID__) && defined(__arm__))
#ifdef ZT_ARCH_ARM_HAS_NEON #ifdef ZT_ARCH_ARM_HAS_NEON
#undef ZT_ARCH_ARM_HAS_NEON #undef ZT_ARCH_ARM_HAS_NEON
#endif #endif
@ -225,7 +231,7 @@
#ifndef likely #ifndef likely
#if defined(__GNUC__) || defined(__clang__) #if defined(__GNUC__) || defined(__clang__)
#define likely(x) __builtin_expect((x),1) #define likely(x) __builtin_expect((x), 1)
#else #else
#define likely(x) x #define likely(x) x
#endif #endif
@ -233,7 +239,7 @@
#ifndef unlikely #ifndef unlikely
#if defined(__GNUC__) || defined(__clang__) #if defined(__GNUC__) || defined(__clang__)
#define unlikely(x) __builtin_expect((x),0) #define unlikely(x) __builtin_expect((x), 0)
#else #else
#define unlikely(x) x #define unlikely(x) x
#endif #endif
@ -249,17 +255,17 @@ typedef unsigned uint128_t __attribute__((mode(TI)));
#endif #endif
#endif #endif
#if !defined(__BYTE_ORDER) && defined(__BYTE_ORDER__) #if ! defined(__BYTE_ORDER) && defined(__BYTE_ORDER__)
#define __BYTE_ORDER __BYTE_ORDER__ #define __BYTE_ORDER __BYTE_ORDER__
#define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__ #define __LITTLE_ENDIAN __ORDER_LITTLE_ENDIAN__
#define __BIG_ENDIAN __ORDER_BIG_ENDIAN__ #define __BIG_ENDIAN __ORDER_BIG_ENDIAN__
#endif #endif
#if !defined(__BYTE_ORDER) && defined(BYTE_ORDER) #if ! defined(__BYTE_ORDER) && defined(BYTE_ORDER)
#define __BYTE_ORDER BYTE_ORDER #define __BYTE_ORDER BYTE_ORDER
#define __LITTLE_ENDIAN LITTLE_ENDIAN #define __LITTLE_ENDIAN LITTLE_ENDIAN
#define __BIG_ENDIAN BIG_ENDIAN #define __BIG_ENDIAN BIG_ENDIAN
#endif #endif
#if !defined(__BYTE_ORDER) && defined(_BYTE_ORDER) #if ! defined(__BYTE_ORDER) && defined(_BYTE_ORDER)
#define __BYTE_ORDER _BYTE_ORDER #define __BYTE_ORDER _BYTE_ORDER
#define __LITTLE_ENDIAN _LITTLE_ENDIAN #define __LITTLE_ENDIAN _LITTLE_ENDIAN
#define __BIG_ENDIAN _BIG_ENDIAN #define __BIG_ENDIAN _BIG_ENDIAN
@ -268,9 +274,10 @@ typedef unsigned uint128_t __attribute__((mode(TI)));
#define ZT_VA_ARGS(...) , ##__VA_ARGS__ #define ZT_VA_ARGS(...) , ##__VA_ARGS__
#ifdef ZT_DEBUG_SPEW #ifdef ZT_DEBUG_SPEW
#define ZT_SPEW(f,...) fprintf(stderr,"%s:%d(%s): " f ZT_EOL_S,__FILE__,__LINE__,__FUNCTION__ ZT_VA_ARGS(__VA_ARGS__)) #define ZT_SPEW(f, ...) \
fprintf(stderr, "%s:%d(%s): " f ZT_EOL_S, __FILE__, __LINE__, __FUNCTION__ ZT_VA_ARGS(__VA_ARGS__))
#else #else
#define ZT_SPEW(f,...) #define ZT_SPEW(f, ...)
#endif #endif
#endif #endif

View file

@ -15,22 +15,27 @@
namespace ZeroTier { namespace ZeroTier {
void OwnershipCredential::addThing(const InetAddress &ip) void OwnershipCredential::addThing(const InetAddress& ip)
{ {
if (m_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) if (m_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS)
return; return;
if (ip.as.sa.sa_family == AF_INET) { if (ip.as.sa.sa_family == AF_INET) {
m_thingTypes[m_thingCount] = THING_IPV4_ADDRESS; m_thingTypes[m_thingCount] = THING_IPV4_ADDRESS;
Utils::copy<4>(m_thingValues[m_thingCount], &(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr)); Utils::copy<4>(
m_thingValues[m_thingCount],
&(reinterpret_cast<const struct sockaddr_in*>(&ip)->sin_addr.s_addr));
++m_thingCount; ++m_thingCount;
} else if (ip.as.sa.sa_family == AF_INET6) { }
else if (ip.as.sa.sa_family == AF_INET6) {
m_thingTypes[m_thingCount] = THING_IPV6_ADDRESS; m_thingTypes[m_thingCount] = THING_IPV6_ADDRESS;
Utils::copy<16>(m_thingValues[m_thingCount], reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr); Utils::copy<16>(
m_thingValues[m_thingCount],
reinterpret_cast<const struct sockaddr_in6*>(&ip)->sin6_addr.s6_addr);
++m_thingCount; ++m_thingCount;
} }
} }
void OwnershipCredential::addThing(const MAC &mac) void OwnershipCredential::addThing(const MAC& mac)
{ {
if (m_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) if (m_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS)
return; return;
@ -39,12 +44,12 @@ void OwnershipCredential::addThing(const MAC &mac)
++m_thingCount; ++m_thingCount;
} }
bool OwnershipCredential::sign(const Identity &signer) bool OwnershipCredential::sign(const Identity& signer)
{ {
uint8_t buf[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX + 16]; uint8_t buf[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX + 16];
if (signer.hasPrivate()) { if (signer.hasPrivate()) {
m_signedBy = signer.address(); m_signedBy = signer.address();
m_signatureLength = signer.sign(buf, (unsigned int) marshal(buf, true), m_signature, sizeof(m_signature)); m_signatureLength = signer.sign(buf, (unsigned int)marshal(buf, true), m_signature, sizeof(m_signature));
return true; return true;
} }
return false; return false;
@ -54,16 +59,16 @@ int OwnershipCredential::marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_
{ {
int p = 0; int p = 0;
if (forSign) { if (forSign) {
for (int k = 0;k < 16;++k) for (int k = 0; k < 16; ++k)
data[p++] = 0x7f; data[p++] = 0x7f;
} }
Utils::storeBigEndian<uint64_t>(data + p, m_networkId); Utils::storeBigEndian<uint64_t>(data + p, m_networkId);
Utils::storeBigEndian<uint64_t>(data + p + 8, (uint64_t) m_ts); Utils::storeBigEndian<uint64_t>(data + p + 8, (uint64_t)m_ts);
Utils::storeBigEndian<uint64_t>(data + p + 16, m_flags); Utils::storeBigEndian<uint64_t>(data + p + 16, m_flags);
Utils::storeBigEndian<uint32_t>(data + p + 24, m_id); Utils::storeBigEndian<uint32_t>(data + p + 24, m_id);
Utils::storeBigEndian<uint16_t>(data + p + 28, (uint16_t) m_thingCount); Utils::storeBigEndian<uint16_t>(data + p + 28, (uint16_t)m_thingCount);
p += 30; p += 30;
for (unsigned int i = 0, j = m_thingCount;i < j;++i) { for (unsigned int i = 0, j = m_thingCount; i < j; ++i) {
data[p++] = m_thingTypes[i]; data[p++] = m_thingTypes[i];
Utils::copy<ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE>(data + p, m_thingValues[i]); Utils::copy<ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE>(data + p, m_thingValues[i]);
p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE; p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE;
@ -72,29 +77,29 @@ int OwnershipCredential::marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
m_signedBy.copyTo(data + p); m_signedBy.copyTo(data + p);
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
if (!forSign) { if (! forSign) {
data[p++] = 1; data[p++] = 1;
Utils::storeBigEndian<uint16_t>(data + p, (uint16_t) m_signatureLength); Utils::storeBigEndian<uint16_t>(data + p, (uint16_t)m_signatureLength);
p += 2; p += 2;
Utils::copy(data + p, m_signature, m_signatureLength); Utils::copy(data + p, m_signature, m_signatureLength);
p += (int) m_signatureLength; p += (int)m_signatureLength;
} }
data[p++] = 0; data[p++] = 0;
data[p++] = 0; data[p++] = 0;
if (forSign) { if (forSign) {
for (int k = 0;k < 16;++k) for (int k = 0; k < 16; ++k)
data[p++] = 0x7f; data[p++] = 0x7f;
} }
return p; return p;
} }
int OwnershipCredential::unmarshal(const uint8_t *data, int len) noexcept int OwnershipCredential::unmarshal(const uint8_t* data, int len) noexcept
{ {
if (len < 30) if (len < 30)
return -1; return -1;
m_networkId = Utils::loadBigEndian<uint64_t>(data); m_networkId = Utils::loadBigEndian<uint64_t>(data);
m_ts = (int64_t) Utils::loadBigEndian<uint64_t>(data + 8); m_ts = (int64_t)Utils::loadBigEndian<uint64_t>(data + 8);
m_flags = Utils::loadBigEndian<uint64_t>(data + 16); m_flags = Utils::loadBigEndian<uint64_t>(data + 16);
m_id = Utils::loadBigEndian<uint32_t>(data + 24); m_id = Utils::loadBigEndian<uint32_t>(data + 24);
m_thingCount = Utils::loadBigEndian<uint16_t>(data + 28); m_thingCount = Utils::loadBigEndian<uint16_t>(data + 28);
@ -102,7 +107,7 @@ int OwnershipCredential::unmarshal(const uint8_t *data, int len) noexcept
return -1; return -1;
int p = 30; int p = 30;
for (unsigned int i = 0, j = m_thingCount;i < j;++i) { for (unsigned int i = 0, j = m_thingCount; i < j; ++i) {
if ((p + 1 + ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE) > len) if ((p + 1 + ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE) > len)
return -1; return -1;
m_thingTypes[i] = data[p++]; m_thingTypes[i] = data[p++];

View file

@ -14,10 +14,10 @@
#ifndef ZT_CERTIFICATEOFOWNERSHIP_HPP #ifndef ZT_CERTIFICATEOFOWNERSHIP_HPP
#define ZT_CERTIFICATEOFOWNERSHIP_HPP #define ZT_CERTIFICATEOFOWNERSHIP_HPP
#include "Address.hpp"
#include "C25519.hpp"
#include "Constants.hpp" #include "Constants.hpp"
#include "Credential.hpp" #include "Credential.hpp"
#include "C25519.hpp"
#include "Address.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "InetAddress.hpp" #include "InetAddress.hpp"
#include "MAC.hpp" #include "MAC.hpp"
@ -28,7 +28,9 @@
// Maximum size of a thing's value field in bytes // Maximum size of a thing's value field in bytes
#define ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE 16 #define ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE 16
#define ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX (8 + 8 + 8 + 4 + 2 + ((1 + ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE) * ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) + 5 + 5 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE + 2) #define ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX \
(8 + 8 + 8 + 4 + 2 + ((1 + ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE) * ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) \
+ 5 + 5 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE + 2)
namespace ZeroTier { namespace ZeroTier {
@ -40,26 +42,24 @@ class Context;
* These are used in conjunction with the rules engine to make IP addresses and * These are used in conjunction with the rules engine to make IP addresses and
* other identifiers un-spoofable. * other identifiers un-spoofable.
*/ */
class OwnershipCredential : public Credential class OwnershipCredential : public Credential {
{
friend class Credential; friend class Credential;
public: public:
static constexpr ZT_CredentialType credentialType() noexcept static constexpr ZT_CredentialType credentialType() noexcept
{ return ZT_CREDENTIAL_TYPE_COO; }
enum Thing
{ {
THING_NULL = 0, return ZT_CREDENTIAL_TYPE_COO;
THING_MAC_ADDRESS = 1, }
THING_IPV4_ADDRESS = 2,
THING_IPV6_ADDRESS = 3 enum Thing { THING_NULL = 0, THING_MAC_ADDRESS = 1, THING_IPV4_ADDRESS = 2, THING_IPV6_ADDRESS = 3 };
};
ZT_INLINE OwnershipCredential() noexcept ZT_INLINE OwnershipCredential() noexcept
{ memoryZero(this); } {
memoryZero(this);
}
ZT_INLINE OwnershipCredential(const uint64_t nwid, const int64_t ts, const Address &issuedTo, const uint32_t id) noexcept ZT_INLINE
OwnershipCredential(const uint64_t nwid, const int64_t ts, const Address& issuedTo, const uint32_t id) noexcept
{ {
memoryZero(this); memoryZero(this);
m_networkId = nwid; m_networkId = nwid;
@ -69,48 +69,77 @@ public:
} }
ZT_INLINE uint64_t networkId() const noexcept ZT_INLINE uint64_t networkId() const noexcept
{ return m_networkId; }
ZT_INLINE int64_t timestamp() const noexcept
{ return m_ts; }
ZT_INLINE int64_t revision() const noexcept
{ return m_ts; }
ZT_INLINE uint32_t id() const noexcept
{ return m_id; }
ZT_INLINE const Address &issuedTo() const noexcept
{ return m_issuedTo; }
ZT_INLINE const Address &signer() const noexcept
{ return m_signedBy; }
ZT_INLINE const uint8_t *signature() const noexcept
{ return m_signature; }
ZT_INLINE unsigned int signatureLength() const noexcept
{ return m_signatureLength; }
ZT_INLINE unsigned int thingCount() const noexcept
{ return (unsigned int)m_thingCount; }
ZT_INLINE Thing thingType(const unsigned int i) const noexcept
{ return (Thing)m_thingTypes[i]; }
ZT_INLINE const uint8_t *thingValue(const unsigned int i) const noexcept
{ return m_thingValues[i]; }
ZT_INLINE bool owns(const InetAddress &ip) const noexcept
{ {
if (ip.as.sa.sa_family == AF_INET) return m_networkId;
return this->_owns(THING_IPV4_ADDRESS, &(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr), 4);
else if (ip.as.sa.sa_family == AF_INET6)
return this->_owns(THING_IPV6_ADDRESS, reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr, 16);
else return false;
} }
ZT_INLINE bool owns(const MAC &mac) const noexcept ZT_INLINE int64_t timestamp() const noexcept
{
return m_ts;
}
ZT_INLINE int64_t revision() const noexcept
{
return m_ts;
}
ZT_INLINE uint32_t id() const noexcept
{
return m_id;
}
ZT_INLINE const Address& issuedTo() const noexcept
{
return m_issuedTo;
}
ZT_INLINE const Address& signer() const noexcept
{
return m_signedBy;
}
ZT_INLINE const uint8_t* signature() const noexcept
{
return m_signature;
}
ZT_INLINE unsigned int signatureLength() const noexcept
{
return m_signatureLength;
}
ZT_INLINE unsigned int thingCount() const noexcept
{
return (unsigned int)m_thingCount;
}
ZT_INLINE Thing thingType(const unsigned int i) const noexcept
{
return (Thing)m_thingTypes[i];
}
ZT_INLINE const uint8_t* thingValue(const unsigned int i) const noexcept
{
return m_thingValues[i];
}
ZT_INLINE bool owns(const InetAddress& ip) const noexcept
{
if (ip.as.sa.sa_family == AF_INET)
return this->_owns(
THING_IPV4_ADDRESS,
&(reinterpret_cast<const struct sockaddr_in*>(&ip)->sin_addr.s_addr),
4);
else if (ip.as.sa.sa_family == AF_INET6)
return this->_owns(
THING_IPV6_ADDRESS,
reinterpret_cast<const struct sockaddr_in6*>(&ip)->sin6_addr.s6_addr,
16);
else
return false;
}
ZT_INLINE bool owns(const MAC& mac) const noexcept
{ {
uint8_t tmp[6]; uint8_t tmp[6];
mac.copyTo(tmp); mac.copyTo(tmp);
@ -122,7 +151,7 @@ public:
* *
* @param ip IPv4 or IPv6 address * @param ip IPv4 or IPv6 address
*/ */
void addThing(const InetAddress &ip); void addThing(const InetAddress& ip);
/** /**
* Add an Ethernet MAC address * Add an Ethernet MAC address
@ -133,7 +162,7 @@ public:
* *
* @param mac 48-bit MAC address * @param mac 48-bit MAC address
*/ */
void addThing(const MAC &mac); void addThing(const MAC& mac);
/** /**
* Sign this certificate * Sign this certificate
@ -141,40 +170,50 @@ public:
* @param signer Signing identity, must have private key * @param signer Signing identity, must have private key
* @return True if signature was successful * @return True if signature was successful
*/ */
bool sign(const Identity &signer); bool sign(const Identity& signer);
/** /**
* Verify certificate signature * Verify certificate signature
* *
* @return Credential verification result: OK, bad signature, or identity needed * @return Credential verification result: OK, bad signature, or identity needed
*/ */
ZT_INLINE Credential::VerifyResult verify(const Context &ctx, const CallContext &cc) const ZT_INLINE Credential::VerifyResult verify(const Context& ctx, const CallContext& cc) const
{ return s_verify(ctx, cc, *this); } {
return s_verify(ctx, cc, *this);
}
static constexpr int marshalSizeMax() noexcept static constexpr int marshalSizeMax() noexcept
{ return ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX; } {
return ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX;
}
int marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX], bool forSign = false) const noexcept; int marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX], bool forSign = false) const noexcept;
int unmarshal(const uint8_t *data, int len) noexcept; int unmarshal(const uint8_t* data, int len) noexcept;
// Provides natural sort order by ID // Provides natural sort order by ID
ZT_INLINE bool operator<(const OwnershipCredential &coo) const noexcept ZT_INLINE bool operator<(const OwnershipCredential& coo) const noexcept
{ return (m_id < coo.m_id); } {
return (m_id < coo.m_id);
}
ZT_INLINE bool operator==(const OwnershipCredential &coo) const noexcept ZT_INLINE bool operator==(const OwnershipCredential& coo) const noexcept
{ return (memcmp(this, &coo, sizeof(OwnershipCredential)) == 0); } {
return (memcmp(this, &coo, sizeof(OwnershipCredential)) == 0);
}
ZT_INLINE bool operator!=(const OwnershipCredential &coo) const noexcept ZT_INLINE bool operator!=(const OwnershipCredential& coo) const noexcept
{ return (memcmp(this, &coo, sizeof(OwnershipCredential)) != 0); } {
return (memcmp(this, &coo, sizeof(OwnershipCredential)) != 0);
}
private: private:
ZT_INLINE bool _owns(const Thing &t, const void *v, unsigned int l) const noexcept ZT_INLINE bool _owns(const Thing& t, const void* v, unsigned int l) const noexcept
{ {
for (unsigned int i = 0, j = m_thingCount; i < j; ++i) { for (unsigned int i = 0, j = m_thingCount; i < j; ++i) {
if (m_thingTypes[i] == (uint8_t)t) { if (m_thingTypes[i] == (uint8_t)t) {
unsigned int k = 0; unsigned int k = 0;
while (k < l) { while (k < l) {
if (reinterpret_cast<const uint8_t *>(v)[k] != m_thingValues[i][k]) if (reinterpret_cast<const uint8_t*>(v)[k] != m_thingValues[i][k])
break; break;
++k; ++k;
} }

View file

@ -12,14 +12,25 @@
/****/ /****/
#include "Path.hpp" #include "Path.hpp"
#include "Context.hpp" #include "Context.hpp"
#include "Node.hpp" #include "Node.hpp"
namespace ZeroTier { namespace ZeroTier {
bool Path::send(const Context &ctx, const CallContext &cc, const void *const data, const unsigned int len) noexcept bool Path::send(const Context& ctx, const CallContext& cc, const void* const data, const unsigned int len) noexcept
{ {
if (likely(ctx.cb.wirePacketSendFunction(reinterpret_cast<ZT_Node *>(ctx.node), ctx.uPtr, cc.tPtr, m_localSocket, reinterpret_cast<const ZT_InetAddress *>(&m_addr), data, len, 0) == 0)) { if (likely(
ctx.cb.wirePacketSendFunction(
reinterpret_cast<ZT_Node*>(ctx.node),
ctx.uPtr,
cc.tPtr,
m_localSocket,
reinterpret_cast<const ZT_InetAddress*>(&m_addr),
data,
len,
0)
== 0)) {
m_lastOut = cc.ticks; m_lastOut = cc.ticks;
m_outMeter.log(cc.ticks, len); m_outMeter.log(cc.ticks, len);
return true; return true;

View file

@ -14,61 +14,63 @@
#ifndef ZT_PATH_HPP #ifndef ZT_PATH_HPP
#define ZT_PATH_HPP #define ZT_PATH_HPP
#include "CallContext.hpp"
#include "Constants.hpp" #include "Constants.hpp"
#include "Containers.hpp"
#include "InetAddress.hpp" #include "InetAddress.hpp"
#include "Meter.hpp"
#include "Mutex.hpp"
#include "SharedPtr.hpp" #include "SharedPtr.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include "Mutex.hpp"
#include "Meter.hpp"
#include "Containers.hpp"
#include "CallContext.hpp"
namespace ZeroTier { namespace ZeroTier {
class Context; class Context;
template< unsigned int MF, unsigned int MFP, unsigned int GCT, unsigned int GCS, typename P > template <unsigned int MF, unsigned int MFP, unsigned int GCT, unsigned int GCS, typename P> class Defragmenter;
class Defragmenter;
/** /**
* A path across the physical network * A path across the physical network
*/ */
class Path class Path {
{ friend class SharedPtr<Path>;
friend class SharedPtr< Path >;
// Allow defragmenter to access fragment-in-flight info stored in Path for performance reasons. // Allow defragmenter to access fragment-in-flight info stored in Path for performance reasons.
template< unsigned int MF, unsigned int MFP, unsigned int GCT, unsigned int GCS, typename P > template <unsigned int MF, unsigned int MFP, unsigned int GCT, unsigned int GCS, typename P>
friend friend class Defragmenter;
class Defragmenter;
public: public:
/** /**
* Map key for paths designed for very fast lookup * Map key for paths designed for very fast lookup
*/ */
class Key class Key {
{
public: public:
ZT_INLINE Key() noexcept ZT_INLINE Key() noexcept
{} {
}
ZT_INLINE Key(const InetAddress &ip) noexcept ZT_INLINE Key(const InetAddress& ip) noexcept
{ {
const unsigned int family = ip.as.sa.sa_family; const unsigned int family = ip.as.sa.sa_family;
if (family == AF_INET) { if (family == AF_INET) {
const uint16_t p = (uint16_t)ip.as.sa_in.sin_port; const uint16_t p = (uint16_t)ip.as.sa_in.sin_port;
m_hashCode = Utils::hash64((((uint64_t)ip.as.sa_in.sin_addr.s_addr) << 16U) ^ ((uint64_t)p) ^ Utils::s_mapNonce); m_hashCode =
Utils::hash64((((uint64_t)ip.as.sa_in.sin_addr.s_addr) << 16U) ^ ((uint64_t)p) ^ Utils::s_mapNonce);
m_ipv6Net64 = 0; // 0 for IPv4, never 0 for IPv6 m_ipv6Net64 = 0; // 0 for IPv4, never 0 for IPv6
m_port = p; m_port = p;
} else { }
else {
if (likely(family == AF_INET6)) { if (likely(family == AF_INET6)) {
const uint64_t a = Utils::loadMachineEndian< uint64_t >(reinterpret_cast<const uint8_t *>(ip.as.sa_in6.sin6_addr.s6_addr)); const uint64_t a = Utils::loadMachineEndian<uint64_t>(
const uint64_t b = Utils::loadMachineEndian< uint64_t >(reinterpret_cast<const uint8_t *>(ip.as.sa_in6.sin6_addr.s6_addr) + 8); reinterpret_cast<const uint8_t*>(ip.as.sa_in6.sin6_addr.s6_addr));
const uint64_t b = Utils::loadMachineEndian<uint64_t>(
reinterpret_cast<const uint8_t*>(ip.as.sa_in6.sin6_addr.s6_addr) + 8);
const uint16_t p = ip.as.sa_in6.sin6_port; const uint16_t p = ip.as.sa_in6.sin6_port;
m_hashCode = Utils::hash64(a ^ b ^ ((uint64_t)p) ^ Utils::s_mapNonce); m_hashCode = Utils::hash64(a ^ b ^ ((uint64_t)p) ^ Utils::s_mapNonce);
m_ipv6Net64 = a; // IPv6 /64 m_ipv6Net64 = a; // IPv6 /64
m_port = p; m_port = p;
} else { }
else {
// This is not reachable since InetAddress can only be AF_INET or AF_INET6, but implement something. // This is not reachable since InetAddress can only be AF_INET or AF_INET6, but implement something.
m_hashCode = Utils::fnv1a32(&ip, sizeof(InetAddress)); m_hashCode = Utils::fnv1a32(&ip, sizeof(InetAddress));
m_ipv6Net64 = 0; m_ipv6Net64 = 0;
@ -78,36 +80,50 @@ public:
} }
ZT_INLINE unsigned long hashCode() const noexcept ZT_INLINE unsigned long hashCode() const noexcept
{ return (unsigned long)m_hashCode; } {
return (unsigned long)m_hashCode;
}
ZT_INLINE bool operator==(const Key &k) const noexcept ZT_INLINE bool operator==(const Key& k) const noexcept
{ return (m_hashCode == k.m_hashCode) && (m_ipv6Net64 == k.m_ipv6Net64) && (m_port == k.m_port); } {
return (m_hashCode == k.m_hashCode) && (m_ipv6Net64 == k.m_ipv6Net64) && (m_port == k.m_port);
}
ZT_INLINE bool operator!=(const Key &k) const noexcept ZT_INLINE bool operator!=(const Key& k) const noexcept
{ return (!(*this == k)); } {
return (! (*this == k));
}
ZT_INLINE bool operator<(const Key &k) const noexcept ZT_INLINE bool operator<(const Key& k) const noexcept
{ {
if (m_hashCode < k.m_hashCode) { if (m_hashCode < k.m_hashCode) {
return true; return true;
} else if (m_hashCode == k.m_hashCode) { }
else if (m_hashCode == k.m_hashCode) {
if (m_ipv6Net64 < k.m_ipv6Net64) { if (m_ipv6Net64 < k.m_ipv6Net64) {
return true; return true;
} else if (m_ipv6Net64 == k.m_ipv6Net64) { }
else if (m_ipv6Net64 == k.m_ipv6Net64) {
return (m_port < k.m_port); return (m_port < k.m_port);
} }
} }
return false; return false;
} }
ZT_INLINE bool operator>(const Key &k) const noexcept ZT_INLINE bool operator>(const Key& k) const noexcept
{ return (k < *this); } {
return (k < *this);
}
ZT_INLINE bool operator<=(const Key &k) const noexcept ZT_INLINE bool operator<=(const Key& k) const noexcept
{ return !(k < *this); } {
return ! (k < *this);
}
ZT_INLINE bool operator>=(const Key &k) const noexcept ZT_INLINE bool operator>=(const Key& k) const noexcept
{ return !(*this < k); } {
return ! (*this < k);
}
private: private:
uint64_t m_hashCode; uint64_t m_hashCode;
@ -115,13 +131,14 @@ public:
uint16_t m_port; uint16_t m_port;
}; };
ZT_INLINE Path(const int64_t l, const InetAddress &r) noexcept: ZT_INLINE Path(const int64_t l, const InetAddress& r) noexcept
m_localSocket(l), : m_localSocket(l)
m_lastIn(0), , m_lastIn(0)
m_lastOut(0), , m_lastOut(0)
m_latency(-1), , m_latency(-1)
m_addr(r) , m_addr(r)
{} {
}
/** /**
* Send a packet via this path (last out time is also updated) * Send a packet via this path (last out time is also updated)
@ -130,7 +147,7 @@ public:
* @param len Packet length * @param len Packet length
* @return True if transport reported success * @return True if transport reported success
*/ */
bool send(const Context &ctx, const CallContext &cc, const void *data, unsigned int len) noexcept; bool send(const Context& ctx, const CallContext& cc, const void* data, unsigned int len) noexcept;
/** /**
* Explicitly update last sent time * Explicitly update last sent time
@ -138,7 +155,7 @@ public:
* @param now Time of send * @param now Time of send
* @param bytes Bytes sent * @param bytes Bytes sent
*/ */
ZT_INLINE void sent(const CallContext &cc, const unsigned int bytes) noexcept ZT_INLINE void sent(const CallContext& cc, const unsigned int bytes) noexcept
{ {
m_lastOut.store(cc.ticks, std::memory_order_relaxed); m_lastOut.store(cc.ticks, std::memory_order_relaxed);
m_outMeter.log(cc.ticks, bytes); m_outMeter.log(cc.ticks, bytes);
@ -150,7 +167,7 @@ public:
* @param now Time of receive * @param now Time of receive
* @param bytes Bytes received * @param bytes Bytes received
*/ */
ZT_INLINE void received(const CallContext &cc, const unsigned int bytes) noexcept ZT_INLINE void received(const CallContext& cc, const unsigned int bytes) noexcept
{ {
m_lastIn.store(cc.ticks, std::memory_order_relaxed); m_lastIn.store(cc.ticks, std::memory_order_relaxed);
m_inMeter.log(cc.ticks, bytes); m_inMeter.log(cc.ticks, bytes);
@ -166,7 +183,8 @@ public:
const int lat = m_latency.load(std::memory_order_relaxed); const int lat = m_latency.load(std::memory_order_relaxed);
if (likely(lat > 0)) { if (likely(lat > 0)) {
m_latency.store((lat + (int)newMeasurement) >> 1U, std::memory_order_relaxed); m_latency.store((lat + (int)newMeasurement) >> 1U, std::memory_order_relaxed);
} else { }
else {
m_latency.store((int)newMeasurement, std::memory_order_relaxed); m_latency.store((int)newMeasurement, std::memory_order_relaxed);
} }
} }
@ -175,45 +193,57 @@ public:
* @return Latency in milliseconds or -1 if unknown * @return Latency in milliseconds or -1 if unknown
*/ */
ZT_INLINE int latency() const noexcept ZT_INLINE int latency() const noexcept
{ return m_latency.load(std::memory_order_relaxed); } {
return m_latency.load(std::memory_order_relaxed);
}
/** /**
* Check path aliveness * Check path aliveness
* *
* @param now Current time * @param now Current time
*/ */
ZT_INLINE bool alive(const CallContext &cc) const noexcept ZT_INLINE bool alive(const CallContext& cc) const noexcept
{ return ((cc.ticks - m_lastIn.load(std::memory_order_relaxed)) < ZT_PATH_ALIVE_TIMEOUT); } {
return ((cc.ticks - m_lastIn.load(std::memory_order_relaxed)) < ZT_PATH_ALIVE_TIMEOUT);
}
/** /**
* @return Physical address * @return Physical address
*/ */
ZT_INLINE const InetAddress &address() const noexcept ZT_INLINE const InetAddress& address() const noexcept
{ return m_addr; } {
return m_addr;
}
/** /**
* @return Local socket as specified by external code * @return Local socket as specified by external code
*/ */
ZT_INLINE int64_t localSocket() const noexcept ZT_INLINE int64_t localSocket() const noexcept
{ return m_localSocket; } {
return m_localSocket;
}
/** /**
* @return Last time we received anything * @return Last time we received anything
*/ */
ZT_INLINE int64_t lastIn() const noexcept ZT_INLINE int64_t lastIn() const noexcept
{ return m_lastIn.load(std::memory_order_relaxed); } {
return m_lastIn.load(std::memory_order_relaxed);
}
/** /**
* @return Last time we sent something * @return Last time we sent something
*/ */
ZT_INLINE int64_t lastOut() const noexcept ZT_INLINE int64_t lastOut() const noexcept
{ return m_lastOut.load(std::memory_order_relaxed); } {
return m_lastOut.load(std::memory_order_relaxed);
}
private: private:
const int64_t m_localSocket; const int64_t m_localSocket;
std::atomic< int64_t > m_lastIn; std::atomic<int64_t> m_lastIn;
std::atomic< int64_t > m_lastOut; std::atomic<int64_t> m_lastOut;
std::atomic< int > m_latency; std::atomic<int> m_latency;
const InetAddress m_addr; const InetAddress m_addr;
Meter<> m_inMeter; Meter<> m_inMeter;
Meter<> m_outMeter; Meter<> m_outMeter;
@ -221,10 +251,10 @@ private:
// These fields belong to Defragmenter but are kept in Path for performance // These fields belong to Defragmenter but are kept in Path for performance
// as it's much faster this way than having Defragmenter maintain another // as it's much faster this way than having Defragmenter maintain another
// mapping from paths to inbound message IDs. // mapping from paths to inbound message IDs.
Set< uint64_t > m_inboundFragmentedMessages; Set<uint64_t> m_inboundFragmentedMessages;
Mutex m_inboundFragmentedMessages_l; Mutex m_inboundFragmentedMessages_l;
std::atomic< int > __refCount; std::atomic<int> __refCount;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -11,50 +11,54 @@
*/ */
/****/ /****/
#include "Peer.hpp"
#include "Constants.hpp" #include "Constants.hpp"
#include "Context.hpp" #include "Context.hpp"
#include "Trace.hpp"
#include "Peer.hpp"
#include "Topology.hpp"
#include "SelfAwareness.hpp"
#include "InetAddress.hpp"
#include "Protocol.hpp"
#include "Endpoint.hpp" #include "Endpoint.hpp"
#include "Expect.hpp" #include "Expect.hpp"
#include "InetAddress.hpp"
#include "Protocol.hpp"
#include "SelfAwareness.hpp"
#include "Topology.hpp"
#include "Trace.hpp"
namespace ZeroTier { namespace ZeroTier {
// An arbitrary byte to send in single byte probes, incremented on each probe. // An arbitrary byte to send in single byte probes, incremented on each probe.
static uint8_t s_arbitraryByte = (uint8_t)Utils::random(); static uint8_t s_arbitraryByte = (uint8_t)Utils::random();
Peer::Peer() : Peer::Peer()
m_key((uintptr_t)&m_identityKey), : m_key((uintptr_t)&m_identityKey)
m_keyRenegotiationNeeded(false), , m_keyRenegotiationNeeded(false)
m_lastReceive(0), , m_lastReceive(0)
m_lastSend(0), , m_lastSend(0)
m_lastSentHello(0), , m_lastSentHello(0)
m_lastWhoisRequestReceived(0), , m_lastWhoisRequestReceived(0)
m_lastEchoRequestReceived(0), , m_lastEchoRequestReceived(0)
m_lastProbeReceived(0), , m_lastProbeReceived(0)
m_alivePathCount(0), , m_alivePathCount(0)
m_bestPath(0), , m_bestPath(0)
m_vProto(0), , m_vProto(0)
m_vMajor(0), , m_vMajor(0)
m_vMinor(0), , m_vMinor(0)
m_vRevision(0) , m_vRevision(0)
{} {
}
Peer::~Peer() Peer::~Peer()
{ Utils::burn(m_helloMacKey, sizeof(m_helloMacKey)); } {
Utils::burn(m_helloMacKey, sizeof(m_helloMacKey));
}
bool Peer::init(const Context &ctx, const CallContext &cc, const Identity &peerIdentity) bool Peer::init(const Context& ctx, const CallContext& cc, const Identity& peerIdentity)
{ {
RWMutex::Lock l(m_lock); RWMutex::Lock l(m_lock);
m_id = peerIdentity; m_id = peerIdentity;
uint8_t k[ZT_SYMMETRIC_KEY_SIZE]; uint8_t k[ZT_SYMMETRIC_KEY_SIZE];
if (unlikely(!ctx.identity.agree(peerIdentity, k))) if (unlikely(! ctx.identity.agree(peerIdentity, k)))
return false; return false;
m_identityKey.init(cc.ticks, k); m_identityKey.init(cc.ticks, k);
Utils::burn(k, sizeof(k)); Utils::burn(k, sizeof(k));
@ -65,9 +69,9 @@ bool Peer::init(const Context &ctx, const CallContext &cc, const Identity &peerI
} }
void Peer::received( void Peer::received(
const Context &ctx, const Context& ctx,
const CallContext &cc, const CallContext& cc,
const SharedPtr< Path > &path, const SharedPtr<Path>& path,
const unsigned int hops, const unsigned int hops,
const uint64_t packetId, const uint64_t packetId,
const unsigned int payloadLength, const unsigned int payloadLength,
@ -103,44 +107,62 @@ void Peer::received(
m_prioritizePaths(cc); m_prioritizePaths(cc);
if (m_alivePathCount == ZT_MAX_PEER_NETWORK_PATHS) { if (m_alivePathCount == ZT_MAX_PEER_NETWORK_PATHS) {
newPathIdx = ZT_MAX_PEER_NETWORK_PATHS - 1; newPathIdx = ZT_MAX_PEER_NETWORK_PATHS - 1;
} else { }
else {
newPathIdx = m_alivePathCount++; newPathIdx = m_alivePathCount++;
} }
} else { }
else {
newPathIdx = m_alivePathCount++; newPathIdx = m_alivePathCount++;
} }
// Save a reference to the current path in case we replace it. This // Save a reference to the current path in case we replace it. This
// should technically never happen, but this ensures safety if it does. // should technically never happen, but this ensures safety if it does.
const SharedPtr< Path > currentBest(reinterpret_cast<Path *>(m_bestPath.load(std::memory_order_acquire))); const SharedPtr<Path> currentBest(reinterpret_cast<Path*>(m_bestPath.load(std::memory_order_acquire)));
SharedPtr< Path > old; SharedPtr<Path> old;
old.move(m_paths[newPathIdx]); old.move(m_paths[newPathIdx]);
m_paths[newPathIdx] = path; m_paths[newPathIdx] = path;
m_prioritizePaths(cc); m_prioritizePaths(cc);
ctx.t->learnedNewPath(cc, 0x582fabdd, packetId, m_id, path->address(), (old) ? old->address() : InetAddress()); ctx.t->learnedNewPath(
} else { cc,
int64_t &lt = m_lastTried[Endpoint(path->address())]; 0x582fabdd,
packetId,
m_id,
path->address(),
(old) ? old->address() : InetAddress());
}
else {
int64_t& lt = m_lastTried[Endpoint(path->address())];
if ((cc.ticks - lt) < ZT_PATH_MIN_TRY_INTERVAL) { if ((cc.ticks - lt) < ZT_PATH_MIN_TRY_INTERVAL) {
lt = cc.ticks; lt = cc.ticks;
path->sent(cc, m_hello(ctx, cc, path->localSocket(), path->address(), false)); path->sent(cc, m_hello(ctx, cc, path->localSocket(), path->address(), false));
ctx.t->tryingNewPath(cc, 0xb7747ddd, m_id, path->address(), path->address(), packetId, (uint8_t)verb, m_id); ctx.t->tryingNewPath(
cc,
0xb7747ddd,
m_id,
path->address(),
path->address(),
packetId,
(uint8_t)verb,
m_id);
} }
} }
} }
} }
} }
void Peer::send(const Context &ctx, const CallContext &cc, const void *data, unsigned int len) noexcept void Peer::send(const Context& ctx, const CallContext& cc, const void* data, unsigned int len) noexcept
{ {
SharedPtr< Path > via(reinterpret_cast<Path *>(m_bestPath.load(std::memory_order_acquire))); SharedPtr<Path> via(reinterpret_cast<Path*>(m_bestPath.load(std::memory_order_acquire)));
if (likely(via)) { if (likely(via)) {
if (likely(via->send(ctx, cc, data, len))) if (likely(via->send(ctx, cc, data, len)))
this->sent(cc, len); this->sent(cc, len);
} else { }
const SharedPtr< Peer > root(ctx.topology->root()); else {
const SharedPtr<Peer> root(ctx.topology->root());
if (likely((root) && (root.ptr() != this))) { if (likely((root) && (root.ptr() != this))) {
via = root->path(cc); via = root->path(cc);
if (likely(via)) { if (likely(via)) {
@ -153,17 +175,22 @@ void Peer::send(const Context &ctx, const CallContext &cc, const void *data, uns
} }
} }
void Peer::pulse(const Context &ctx, const CallContext &cc) void Peer::pulse(const Context& ctx, const CallContext& cc)
{ {
RWMutex::Lock l(m_lock); RWMutex::Lock l(m_lock);
// Grab current key (this is never NULL). // Grab current key (this is never NULL).
SymmetricKey *const key = reinterpret_cast<SymmetricKey *>(m_key.load(std::memory_order_relaxed)); SymmetricKey* const key = reinterpret_cast<SymmetricKey*>(m_key.load(std::memory_order_relaxed));
// Determine if we need a new ephemeral key pair and if a new HELLO needs // Determine if we need a new ephemeral key pair and if a new HELLO needs
// to be sent. The latter happens every ZT_PEER_HELLO_INTERVAL or if a new // to be sent. The latter happens every ZT_PEER_HELLO_INTERVAL or if a new
// ephemeral key pair is generated. // ephemeral key pair is generated.
bool needHello = (((m_vProto >= 20) && (m_keyRenegotiationNeeded || (key == &m_identityKey) || ((cc.ticks - key->timestamp()) >= (ZT_SYMMETRIC_KEY_TTL / 2)) || (key->odometer() > (ZT_SYMMETRIC_KEY_TTL_MESSAGES / 2)))) || ((cc.ticks - m_lastSentHello) >= ZT_PEER_HELLO_INTERVAL)); bool needHello =
(((m_vProto >= 20)
&& (m_keyRenegotiationNeeded || (key == &m_identityKey)
|| ((cc.ticks - key->timestamp()) >= (ZT_SYMMETRIC_KEY_TTL / 2))
|| (key->odometer() > (ZT_SYMMETRIC_KEY_TTL_MESSAGES / 2))))
|| ((cc.ticks - m_lastSentHello) >= ZT_PEER_HELLO_INTERVAL));
// Prioritize paths and more importantly for here forget dead ones. // Prioritize paths and more importantly for here forget dead ones.
m_prioritizePaths(cc); m_prioritizePaths(cc);
@ -175,13 +202,24 @@ void Peer::pulse(const Context &ctx, const CallContext &cc)
// callback (if one was supplied). // callback (if one was supplied).
if (m_locator) { if (m_locator) {
for (Vector< std::pair< Endpoint, SharedPtr< const Locator::EndpointAttributes > > >::const_iterator ep(m_locator->endpoints().begin()); ep != m_locator->endpoints().end(); ++ep) { for (Vector<std::pair<Endpoint, SharedPtr<const Locator::EndpointAttributes> > >::const_iterator ep(
m_locator->endpoints().begin());
ep != m_locator->endpoints().end();
++ep) {
if (ep->first.type == ZT_ENDPOINT_TYPE_IP_UDP) { if (ep->first.type == ZT_ENDPOINT_TYPE_IP_UDP) {
if (ctx.node->filterPotentialPath(cc.tPtr, m_id, -1, ep->first.ip())) { if (ctx.node->filterPotentialPath(cc.tPtr, m_id, -1, ep->first.ip())) {
int64_t &lt = m_lastTried[ep->first]; int64_t& lt = m_lastTried[ep->first];
if ((cc.ticks - lt) > ZT_PATH_MIN_TRY_INTERVAL) { if ((cc.ticks - lt) > ZT_PATH_MIN_TRY_INTERVAL) {
lt = cc.ticks; lt = cc.ticks;
ctx.t->tryingNewPath(cc, 0x84b22322, m_id, ep->first.ip(), InetAddress::NIL, 0, 0, Identity::NIL); ctx.t->tryingNewPath(
cc,
0x84b22322,
m_id,
ep->first.ip(),
InetAddress::NIL,
0,
0,
Identity::NIL);
sent(cc, m_sendProbe(ctx, cc, -1, ep->first.ip(), nullptr, 0)); sent(cc, m_sendProbe(ctx, cc, -1, ep->first.ip(), nullptr, 0));
} }
} }
@ -192,7 +230,7 @@ void Peer::pulse(const Context &ctx, const CallContext &cc)
InetAddress addr; InetAddress addr;
if (ctx.node->externalPathLookup(cc.tPtr, m_id, -1, addr)) { if (ctx.node->externalPathLookup(cc.tPtr, m_id, -1, addr)) {
if ((addr) && ctx.node->filterPotentialPath(cc.tPtr, m_id, -1, addr)) { if ((addr) && ctx.node->filterPotentialPath(cc.tPtr, m_id, -1, addr)) {
int64_t &lt = m_lastTried[Endpoint(addr)]; int64_t& lt = m_lastTried[Endpoint(addr)];
if ((cc.ticks - lt) > ZT_PATH_MIN_TRY_INTERVAL) { if ((cc.ticks - lt) > ZT_PATH_MIN_TRY_INTERVAL) {
lt = cc.ticks; lt = cc.ticks;
ctx.t->tryingNewPath(cc, 0x84a10000, m_id, addr, InetAddress::NIL, 0, 0, Identity::NIL); ctx.t->tryingNewPath(cc, 0x84a10000, m_id, addr, InetAddress::NIL, 0, 0, Identity::NIL);
@ -201,10 +239,11 @@ void Peer::pulse(const Context &ctx, const CallContext &cc)
} }
} }
} }
} else { }
else {
unsigned int attempts = 0; unsigned int attempts = 0;
for (;;) { for (;;) {
p_TryQueueItem &qi = m_tryQueue.front(); p_TryQueueItem& qi = m_tryQueue.front();
if (qi.target.isInetAddr()) { if (qi.target.isInetAddr()) {
// Skip entry if it overlaps with any currently active IP. // Skip entry if it overlaps with any currently active IP.
@ -219,21 +258,19 @@ void Peer::pulse(const Context &ctx, const CallContext &cc)
++attempts; ++attempts;
if (qi.iteration < 0) { if (qi.iteration < 0) {
// If iteration is less than zero, try to contact the original address. // If iteration is less than zero, try to contact the original address.
// It may be set to a larger negative value to try multiple times such // It may be set to a larger negative value to try multiple times such
// as e.g. -3 to try 3 times. // as e.g. -3 to try 3 times.
sent(cc, m_sendProbe(ctx, cc, -1, qi.target.ip(), nullptr, 0)); sent(cc, m_sendProbe(ctx, cc, -1, qi.target.ip(), nullptr, 0));
++qi.iteration; ++qi.iteration;
goto requeue_item; goto requeue_item;
}
} else if (qi.target.ip().isV4() && (m_alivePathCount == 0)) { else if (qi.target.ip().isV4() && (m_alivePathCount == 0)) {
// When iteration reaches zero the queue item is dropped unless it's // When iteration reaches zero the queue item is dropped unless it's
// IPv4 and we have no direct paths. In that case some heavier NAT-t // IPv4 and we have no direct paths. In that case some heavier NAT-t
// strategies are attempted. // strategies are attempted.
if (qi.target.ip().port() < 1024) { if (qi.target.ip().port() < 1024) {
// If the source port is privileged, we actually scan every possible // If the source port is privileged, we actually scan every possible
// privileged port in random order slowly over multiple iterations // privileged port in random order slowly over multiple iterations
// of pulse(). This is done in batches of ZT_NAT_T_PORT_SCAN_MAX. // of pulse(). This is done in batches of ZT_NAT_T_PORT_SCAN_MAX.
@ -248,9 +285,8 @@ void Peer::pulse(const Context &ctx, const CallContext &cc)
sent(cc, m_sendProbe(ctx, cc, -1, qi.target.ip(), ports, pn)); sent(cc, m_sendProbe(ctx, cc, -1, qi.target.ip(), ports, pn));
if (qi.iteration < 1023) if (qi.iteration < 1023)
goto requeue_item; goto requeue_item;
}
} else { else {
// For un-privileged ports we'll try ZT_NAT_T_PORT_SCAN_MAX ports // For un-privileged ports we'll try ZT_NAT_T_PORT_SCAN_MAX ports
// beyond the one we were sent to catch some sequentially assigning // beyond the one we were sent to catch some sequentially assigning
// symmetric NATs. // symmetric NATs.
@ -262,7 +298,6 @@ void Peer::pulse(const Context &ctx, const CallContext &cc)
sent(cc, m_sendProbe(ctx, cc, -1, tmp, nullptr, 0)); sent(cc, m_sendProbe(ctx, cc, -1, tmp, nullptr, 0));
if (qi.iteration < ZT_NAT_T_PORT_SCAN_MAX) if (qi.iteration < ZT_NAT_T_PORT_SCAN_MAX)
goto requeue_item; goto requeue_item;
} }
} }
} }
@ -272,7 +307,8 @@ void Peer::pulse(const Context &ctx, const CallContext &cc)
m_tryQueue.pop_front(); m_tryQueue.pop_front();
if (attempts >= std::min((unsigned int)m_tryQueue.size(), (unsigned int)ZT_NAT_T_PORT_SCAN_MAX)) if (attempts >= std::min((unsigned int)m_tryQueue.size(), (unsigned int)ZT_NAT_T_PORT_SCAN_MAX))
break; break;
else continue; else
continue;
// If the code skips here the front item is instead moved to the back. // If the code skips here the front item is instead moved to the back.
requeue_item: requeue_item:
@ -280,7 +316,8 @@ void Peer::pulse(const Context &ctx, const CallContext &cc)
m_tryQueue.splice(m_tryQueue.end(), m_tryQueue, m_tryQueue.begin()); m_tryQueue.splice(m_tryQueue.end(), m_tryQueue, m_tryQueue.begin());
if (attempts >= std::min((unsigned int)m_tryQueue.size(), (unsigned int)ZT_NAT_T_PORT_SCAN_MAX)) if (attempts >= std::min((unsigned int)m_tryQueue.size(), (unsigned int)ZT_NAT_T_PORT_SCAN_MAX))
break; break;
else continue; else
continue;
} }
} }
@ -289,14 +326,16 @@ void Peer::pulse(const Context &ctx, const CallContext &cc)
for (unsigned int i = 0; i < m_alivePathCount; ++i) { for (unsigned int i = 0; i < m_alivePathCount; ++i) {
if (needHello) { if (needHello) {
needHello = false; needHello = false;
const unsigned int bytes = m_hello(ctx, cc, m_paths[i]->localSocket(), m_paths[i]->address(), m_keyRenegotiationNeeded); const unsigned int bytes =
m_hello(ctx, cc, m_paths[i]->localSocket(), m_paths[i]->address(), m_keyRenegotiationNeeded);
if (bytes) { if (bytes) {
m_paths[i]->sent(cc, bytes); m_paths[i]->sent(cc, bytes);
sent(cc, bytes); sent(cc, bytes);
m_lastSentHello = cc.ticks; m_lastSentHello = cc.ticks;
m_keyRenegotiationNeeded = false; m_keyRenegotiationNeeded = false;
} }
} else if ((cc.ticks - m_paths[i]->lastOut()) >= ZT_PATH_KEEPALIVE_PERIOD) { }
else if ((cc.ticks - m_paths[i]->lastOut()) >= ZT_PATH_KEEPALIVE_PERIOD) {
m_paths[i]->send(ctx, cc, &s_arbitraryByte, 1); m_paths[i]->send(ctx, cc, &s_arbitraryByte, 1);
++s_arbitraryByte; ++s_arbitraryByte;
sent(cc, 1); sent(cc, 1);
@ -305,11 +344,12 @@ void Peer::pulse(const Context &ctx, const CallContext &cc)
// Send a HELLO indirectly if we were not able to send one via any direct path. // Send a HELLO indirectly if we were not able to send one via any direct path.
if (needHello) { if (needHello) {
const SharedPtr< Peer > root(ctx.topology->root()); const SharedPtr<Peer> root(ctx.topology->root());
if (root) { if (root) {
const SharedPtr< Path > via(root->path(cc)); const SharedPtr<Path> via(root->path(cc));
if (via) { if (via) {
const unsigned int bytes = m_hello(ctx, cc, via->localSocket(), via->address(), m_keyRenegotiationNeeded); const unsigned int bytes =
m_hello(ctx, cc, via->localSocket(), via->address(), m_keyRenegotiationNeeded);
if (bytes) { if (bytes) {
via->sent(cc, bytes); via->sent(cc, bytes);
root->relayed(cc, bytes); root->relayed(cc, bytes);
@ -322,14 +362,15 @@ void Peer::pulse(const Context &ctx, const CallContext &cc)
} }
// Clean m_lastTried // Clean m_lastTried
for (Map< Endpoint, int64_t >::iterator i(m_lastTried.begin()); i != m_lastTried.end();) { for (Map<Endpoint, int64_t>::iterator i(m_lastTried.begin()); i != m_lastTried.end();) {
if ((cc.ticks - i->second) > (ZT_PATH_MIN_TRY_INTERVAL * 3)) if ((cc.ticks - i->second) > (ZT_PATH_MIN_TRY_INTERVAL * 3))
m_lastTried.erase(i++); m_lastTried.erase(i++);
else ++i; else
++i;
} }
} }
void Peer::contact(const Context &ctx, const CallContext &cc, const Endpoint &ep, int tries) void Peer::contact(const Context& ctx, const CallContext& cc, const Endpoint& ep, int tries)
{ {
RWMutex::Lock l(m_lock); RWMutex::Lock l(m_lock);
@ -342,7 +383,7 @@ void Peer::contact(const Context &ctx, const CallContext &cc, const Endpoint &ep
} }
// Check underlying path attempt rate limit. // Check underlying path attempt rate limit.
int64_t &lt = m_lastTried[ep]; int64_t& lt = m_lastTried[ep];
if ((cc.ticks - lt) < ZT_PATH_MIN_TRY_INTERVAL) if ((cc.ticks - lt) < ZT_PATH_MIN_TRY_INTERVAL)
return; return;
lt = cc.ticks; lt = cc.ticks;
@ -350,12 +391,20 @@ void Peer::contact(const Context &ctx, const CallContext &cc, const Endpoint &ep
// For IPv4 addresses we send a tiny packet with a low TTL, which helps to // For IPv4 addresses we send a tiny packet with a low TTL, which helps to
// traverse some NAT types. It has no effect otherwise. // traverse some NAT types. It has no effect otherwise.
if (ep.isInetAddr() && ep.ip().isV4()) { if (ep.isInetAddr() && ep.ip().isV4()) {
ctx.cb.wirePacketSendFunction(reinterpret_cast<ZT_Node *>(ctx.node), ctx.uPtr, cc.tPtr, -1, reinterpret_cast<const ZT_InetAddress *>(&ep.ip()), &s_arbitraryByte, 1, 2); ctx.cb.wirePacketSendFunction(
reinterpret_cast<ZT_Node*>(ctx.node),
ctx.uPtr,
cc.tPtr,
-1,
reinterpret_cast<const ZT_InetAddress*>(&ep.ip()),
&s_arbitraryByte,
1,
2);
++s_arbitraryByte; ++s_arbitraryByte;
} }
// Make sure address is not already in the try queue. If so just update it. // Make sure address is not already in the try queue. If so just update it.
for (List< p_TryQueueItem >::iterator i(m_tryQueue.begin()); i != m_tryQueue.end(); ++i) { for (List<p_TryQueueItem>::iterator i(m_tryQueue.begin()); i != m_tryQueue.end(); ++i) {
if (i->target.isSameAddress(ep)) { if (i->target.isSameAddress(ep)) {
i->target = ep; i->target = ep;
i->iteration = -tries; i->iteration = -tries;
@ -366,16 +415,24 @@ void Peer::contact(const Context &ctx, const CallContext &cc, const Endpoint &ep
m_tryQueue.push_back(p_TryQueueItem(ep, -tries)); m_tryQueue.push_back(p_TryQueueItem(ep, -tries));
} }
void Peer::resetWithinScope(const Context &ctx, const CallContext &cc, InetAddress::IpScope scope, int inetAddressFamily) void Peer::resetWithinScope(
const Context& ctx,
const CallContext& cc,
InetAddress::IpScope scope,
int inetAddressFamily)
{ {
RWMutex::Lock l(m_lock); RWMutex::Lock l(m_lock);
unsigned int pc = 0; unsigned int pc = 0;
for (unsigned int i = 0; i < m_alivePathCount; ++i) { for (unsigned int i = 0; i < m_alivePathCount; ++i) {
if ((m_paths[i]) && (((int)m_paths[i]->address().as.sa.sa_family == inetAddressFamily) && (m_paths[i]->address().ipScope() == scope))) { if ((m_paths[i])
const unsigned int bytes = m_sendProbe(ctx, cc, m_paths[i]->localSocket(), m_paths[i]->address(), nullptr, 0); && (((int)m_paths[i]->address().as.sa.sa_family == inetAddressFamily)
&& (m_paths[i]->address().ipScope() == scope))) {
const unsigned int bytes =
m_sendProbe(ctx, cc, m_paths[i]->localSocket(), m_paths[i]->address(), nullptr, 0);
m_paths[i]->sent(cc, bytes); m_paths[i]->sent(cc, bytes);
sent(cc, bytes); sent(cc, bytes);
} else if (pc != i) { }
else if (pc != i) {
m_paths[pc++] = m_paths[i]; m_paths[pc++] = m_paths[i];
} }
} }
@ -384,12 +441,12 @@ void Peer::resetWithinScope(const Context &ctx, const CallContext &cc, InetAddre
m_paths[pc++].zero(); m_paths[pc++].zero();
} }
void Peer::save(const Context &ctx, const CallContext &cc) const void Peer::save(const Context& ctx, const CallContext& cc) const
{ {
uint8_t buf[8 + ZT_PEER_MARSHAL_SIZE_MAX]; uint8_t buf[8 + ZT_PEER_MARSHAL_SIZE_MAX];
// Prefix each saved peer with the current timestamp. // Prefix each saved peer with the current timestamp.
Utils::storeBigEndian< uint64_t >(buf, (uint64_t)cc.clock); Utils::storeBigEndian<uint64_t>(buf, (uint64_t)cc.clock);
const int len = marshal(ctx, buf + 8); const int len = marshal(ctx, buf + 8);
if (len > 0) { if (len > 0) {
@ -400,7 +457,7 @@ void Peer::save(const Context &ctx, const CallContext &cc) const
} }
} }
int Peer::marshal(const Context &ctx, uint8_t data[ZT_PEER_MARSHAL_SIZE_MAX]) const noexcept int Peer::marshal(const Context& ctx, uint8_t data[ZT_PEER_MARSHAL_SIZE_MAX]) const noexcept
{ {
RWMutex::RLock l(m_lock); RWMutex::RLock l(m_lock);
@ -430,7 +487,8 @@ int Peer::marshal(const Context &ctx, uint8_t data[ZT_PEER_MARSHAL_SIZE_MAX]) co
if (s <= 0) if (s <= 0)
return s; return s;
p += s; p += s;
} else { }
else {
data[p++] = 0; data[p++] = 0;
} }
@ -449,7 +507,7 @@ int Peer::marshal(const Context &ctx, uint8_t data[ZT_PEER_MARSHAL_SIZE_MAX]) co
return p; return p;
} }
int Peer::unmarshal(const Context &ctx, const int64_t ticks, const uint8_t *restrict data, const int len) noexcept int Peer::unmarshal(const Context& ctx, const int64_t ticks, const uint8_t* restrict data, const int len) noexcept
{ {
RWMutex::Lock l(m_lock); RWMutex::Lock l(m_lock);
@ -465,7 +523,9 @@ int Peer::unmarshal(const Context &ctx, const int64_t ticks, const uint8_t *rest
bool identityKeyRestored = false; bool identityKeyRestored = false;
if (Address(data + 1) == ctx.identity.address()) { if (Address(data + 1) == ctx.identity.address()) {
uint8_t k[ZT_SYMMETRIC_KEY_SIZE]; uint8_t k[ZT_SYMMETRIC_KEY_SIZE];
static_assert(ZT_SYMMETRIC_KEY_SIZE == 48, "marshal() and unmarshal() must be revisited if ZT_SYMMETRIC_KEY_SIZE is changed"); static_assert(
ZT_SYMMETRIC_KEY_SIZE == 48,
"marshal() and unmarshal() must be revisited if ZT_SYMMETRIC_KEY_SIZE is changed");
ctx.localSecretCipher.decrypt(data + 1 + ZT_ADDRESS_LENGTH, k); ctx.localSecretCipher.decrypt(data + 1 + ZT_ADDRESS_LENGTH, k);
ctx.localSecretCipher.decrypt(data + 1 + ZT_ADDRESS_LENGTH + 16, k + 16); ctx.localSecretCipher.decrypt(data + 1 + ZT_ADDRESS_LENGTH + 16, k + 16);
ctx.localSecretCipher.decrypt(data + 1 + ZT_ADDRESS_LENGTH + 32, k + 32); ctx.localSecretCipher.decrypt(data + 1 + ZT_ADDRESS_LENGTH + 32, k + 32);
@ -481,9 +541,9 @@ int Peer::unmarshal(const Context &ctx, const int64_t ticks, const uint8_t *rest
return s; return s;
p += s; p += s;
if (!identityKeyRestored) { if (! identityKeyRestored) {
uint8_t k[ZT_SYMMETRIC_KEY_SIZE]; uint8_t k[ZT_SYMMETRIC_KEY_SIZE];
if (!ctx.identity.agree(m_id, k)) if (! ctx.identity.agree(m_id, k))
return -1; return -1;
m_identityKey.init(ticks, k); m_identityKey.init(ticks, k);
Utils::burn(k, sizeof(k)); Utils::burn(k, sizeof(k));
@ -494,55 +554,58 @@ int Peer::unmarshal(const Context &ctx, const int64_t ticks, const uint8_t *rest
if (data[p] == 0) { if (data[p] == 0) {
++p; ++p;
m_locator.zero(); m_locator.zero();
} else if (data[p] == 1) { }
else if (data[p] == 1) {
++p; ++p;
Locator *const loc = new Locator(); Locator* const loc = new Locator();
s = loc->unmarshal(data + p, len - p); s = loc->unmarshal(data + p, len - p);
m_locator.set(loc); m_locator.set(loc);
if (s < 0) if (s < 0)
return s; return s;
p += s; p += s;
} else { }
else {
return -1; return -1;
} }
if ((p + 10) > len) if ((p + 10) > len)
return -1; return -1;
m_vProto = Utils::loadBigEndian< uint16_t >(data + p); m_vProto = Utils::loadBigEndian<uint16_t>(data + p);
p += 2; p += 2;
m_vMajor = Utils::loadBigEndian< uint16_t >(data + p); m_vMajor = Utils::loadBigEndian<uint16_t>(data + p);
p += 2; p += 2;
m_vMinor = Utils::loadBigEndian< uint16_t >(data + p); m_vMinor = Utils::loadBigEndian<uint16_t>(data + p);
p += 2; p += 2;
m_vRevision = Utils::loadBigEndian< uint16_t >(data + p); m_vRevision = Utils::loadBigEndian<uint16_t>(data + p);
p += 2; p += 2;
p += 2 + (int)Utils::loadBigEndian< uint16_t >(data + p); p += 2 + (int)Utils::loadBigEndian<uint16_t>(data + p);
m_deriveSecondaryIdentityKeys(); m_deriveSecondaryIdentityKeys();
return (p > len) ? -1 : p; return (p > len) ? -1 : p;
} }
struct _PathPriorityComparisonOperator struct _PathPriorityComparisonOperator {
{ ZT_INLINE bool operator()(const SharedPtr<Path>& a, const SharedPtr<Path>& b) const noexcept
ZT_INLINE bool operator()(const SharedPtr< Path > &a, const SharedPtr< Path > &b) const noexcept
{ {
if (a) { if (a) {
if (b) if (b)
return (a->lastIn() > b->lastIn()); return (a->lastIn() > b->lastIn());
else return true; else
} else { return true;
}
else {
return false; return false;
} }
} }
}; };
void Peer::m_prioritizePaths(const CallContext &cc) void Peer::m_prioritizePaths(const CallContext& cc)
{ {
// assumes m_lock is locked // assumes m_lock is locked
// Need to hold the current best just in case we drop it before changing the atomic. // Need to hold the current best just in case we drop it before changing the atomic.
const SharedPtr< Path > oldBest(reinterpret_cast<Path *>(m_bestPath.load(std::memory_order_acquire))); const SharedPtr<Path> oldBest(reinterpret_cast<Path*>(m_bestPath.load(std::memory_order_acquire)));
// Clean and reprioritize paths. // Clean and reprioritize paths.
if (m_alivePathCount != 0) { if (m_alivePathCount != 0) {
@ -565,7 +628,13 @@ void Peer::m_prioritizePaths(const CallContext &cc)
m_bestPath.store((m_alivePathCount != 0) ? (uintptr_t)m_paths[0].ptr() : (uintptr_t)0, std::memory_order_release); m_bestPath.store((m_alivePathCount != 0) ? (uintptr_t)m_paths[0].ptr() : (uintptr_t)0, std::memory_order_release);
} }
unsigned int Peer::m_sendProbe(const Context &ctx, const CallContext &cc, int64_t localSocket, const InetAddress &atAddress, const uint16_t *ports, const unsigned int numPorts) unsigned int Peer::m_sendProbe(
const Context& ctx,
const CallContext& cc,
int64_t localSocket,
const InetAddress& atAddress,
const uint16_t* ports,
const unsigned int numPorts)
{ {
// Assumes m_lock is locked // Assumes m_lock is locked
@ -574,7 +643,9 @@ unsigned int Peer::m_sendProbe(const Context &ctx, const CallContext &cc, int64_
// some future attacker compromises it. // some future attacker compromises it.
uint8_t p[ZT_PROTO_MIN_PACKET_LENGTH]; uint8_t p[ZT_PROTO_MIN_PACKET_LENGTH];
Utils::storeMachineEndian< uint64_t >(p + ZT_PROTO_PACKET_ID_INDEX, m_identityKey.nextMessage(ctx.identity.address(), m_id.address())); Utils::storeMachineEndian<uint64_t>(
p + ZT_PROTO_PACKET_ID_INDEX,
m_identityKey.nextMessage(ctx.identity.address(), m_id.address()));
m_id.address().copyTo(p + ZT_PROTO_PACKET_DESTINATION_INDEX); m_id.address().copyTo(p + ZT_PROTO_PACKET_DESTINATION_INDEX);
ctx.identity.address().copyTo(p + ZT_PROTO_PACKET_SOURCE_INDEX); ctx.identity.address().copyTo(p + ZT_PROTO_PACKET_SOURCE_INDEX);
p[ZT_PROTO_PACKET_FLAGS_INDEX] = 0; p[ZT_PROTO_PACKET_FLAGS_INDEX] = 0;
@ -586,11 +657,28 @@ unsigned int Peer::m_sendProbe(const Context &ctx, const CallContext &cc, int64_
InetAddress tmp(atAddress); InetAddress tmp(atAddress);
for (unsigned int i = 0; i < numPorts; ++i) { for (unsigned int i = 0; i < numPorts; ++i) {
tmp.setPort(ports[i]); tmp.setPort(ports[i]);
ctx.cb.wirePacketSendFunction(reinterpret_cast<ZT_Node *>(ctx.node), ctx.uPtr, cc.tPtr, -1, reinterpret_cast<const ZT_InetAddress *>(&tmp), p, ZT_PROTO_MIN_PACKET_LENGTH, 0); ctx.cb.wirePacketSendFunction(
reinterpret_cast<ZT_Node*>(ctx.node),
ctx.uPtr,
cc.tPtr,
-1,
reinterpret_cast<const ZT_InetAddress*>(&tmp),
p,
ZT_PROTO_MIN_PACKET_LENGTH,
0);
} }
return ZT_PROTO_MIN_PACKET_LENGTH * numPorts; return ZT_PROTO_MIN_PACKET_LENGTH * numPorts;
} else { }
ctx.cb.wirePacketSendFunction(reinterpret_cast<ZT_Node *>(ctx.node), ctx.uPtr, cc.tPtr, -1, reinterpret_cast<const ZT_InetAddress *>(&atAddress), p, ZT_PROTO_MIN_PACKET_LENGTH, 0); else {
ctx.cb.wirePacketSendFunction(
reinterpret_cast<ZT_Node*>(ctx.node),
ctx.uPtr,
cc.tPtr,
-1,
reinterpret_cast<const ZT_InetAddress*>(&atAddress),
p,
ZT_PROTO_MIN_PACKET_LENGTH,
0);
return ZT_PROTO_MIN_PACKET_LENGTH; return ZT_PROTO_MIN_PACKET_LENGTH;
} }
} }
@ -609,7 +697,12 @@ void Peer::m_deriveSecondaryIdentityKeys() noexcept
KBKDFHMACSHA384(m_identityKey.key(), ZT_KBKDF_LABEL_PACKET_HMAC, 0, 0, m_helloMacKey); KBKDFHMACSHA384(m_identityKey.key(), ZT_KBKDF_LABEL_PACKET_HMAC, 0, 0, m_helloMacKey);
} }
unsigned int Peer::m_hello(const Context &ctx, const CallContext &cc, int64_t localSocket, const InetAddress &atAddress, const bool forceNewKey) unsigned int Peer::m_hello(
const Context& ctx,
const CallContext& cc,
int64_t localSocket,
const InetAddress& atAddress,
const bool forceNewKey)
{ {
// assumes m_lock is at least locked for reading // assumes m_lock is at least locked for reading
@ -624,10 +717,10 @@ unsigned int Peer::m_hello(const Context &ctx, const CallContext &cc, int64_t lo
* here is also needed to satisfy some FIPS/NIST type requirements. */ * here is also needed to satisfy some FIPS/NIST type requirements. */
// Pick or generate an ephemeral key to send with this HELLO. // Pick or generate an ephemeral key to send with this HELLO.
p_EphemeralPrivate *ephemeral; p_EphemeralPrivate* ephemeral;
{ {
p_EphemeralPrivate *earliest = m_ephemeralKeysSent; p_EphemeralPrivate* earliest = m_ephemeralKeysSent;
p_EphemeralPrivate *latest = nullptr; p_EphemeralPrivate* latest = nullptr;
int64_t earliestEphemeralPrivate = 9223372036854775807LL; int64_t earliestEphemeralPrivate = 9223372036854775807LL;
int64_t latestEphemeralPrivate = 0; int64_t latestEphemeralPrivate = 0;
for (unsigned int k = 0; k < ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE; ++k) { for (unsigned int k = 0; k < ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE; ++k) {
@ -635,15 +728,18 @@ unsigned int Peer::m_hello(const Context &ctx, const CallContext &cc, int64_t lo
if (ct <= earliestEphemeralPrivate) { if (ct <= earliestEphemeralPrivate) {
earliestEphemeralPrivate = ct; earliestEphemeralPrivate = ct;
earliest = m_ephemeralKeysSent + k; earliest = m_ephemeralKeysSent + k;
} else if (ct >= latestEphemeralPrivate) { // creationTime will be -1 if not initialized }
else if (ct >= latestEphemeralPrivate) { // creationTime will be -1 if not initialized
latestEphemeralPrivate = ct; latestEphemeralPrivate = ct;
latest = m_ephemeralKeysSent + k; latest = m_ephemeralKeysSent + k;
} }
} }
if ((latest != nullptr) && (!forceNewKey) && ((cc.ticks - latest->creationTime) < (ZT_SYMMETRIC_KEY_TTL / 2))) { if ((latest != nullptr) && (! forceNewKey)
&& ((cc.ticks - latest->creationTime) < (ZT_SYMMETRIC_KEY_TTL / 2))) {
ephemeral = latest; ephemeral = latest;
} else { }
else {
earliest->creationTime = cc.ticks; earliest->creationTime = cc.ticks;
earliest->pub.type = ZT_PROTO_EPHEMERAL_KEY_TYPE_C25519_P384; earliest->pub.type = ZT_PROTO_EPHEMERAL_KEY_TYPE_C25519_P384;
C25519::generateC25519(earliest->pub.c25519Public, earliest->c25519Private); C25519::generateC25519(earliest->pub.c25519Public, earliest->c25519Private);
@ -672,14 +768,14 @@ unsigned int Peer::m_hello(const Context &ctx, const CallContext &cc, int64_t lo
// LEGACY: the six reserved bytes after the IV exist for legacy compatibility with v1.x nodes. // LEGACY: the six reserved bytes after the IV exist for legacy compatibility with v1.x nodes.
// Once those are dead they'll become just reserved bytes for future use as flags etc. // Once those are dead they'll become just reserved bytes for future use as flags etc.
outp.wI32(ii, 0); // reserved bytes outp.wI32(ii, 0); // reserved bytes
void *const legacyMoonCountStart = outp.unsafeData + ii; void* const legacyMoonCountStart = outp.unsafeData + ii;
outp.wI16(ii, 0); outp.wI16(ii, 0);
const uint64_t legacySalsaIv = packetId & ZT_CONST_TO_BE_UINT64(0xfffffffffffffff8ULL); const uint64_t legacySalsaIv = packetId & ZT_CONST_TO_BE_UINT64(0xfffffffffffffff8ULL);
Salsa20(m_identityKey.key(), &legacySalsaIv).crypt12(legacyMoonCountStart, legacyMoonCountStart, 2); Salsa20(m_identityKey.key(), &legacySalsaIv).crypt12(legacyMoonCountStart, legacyMoonCountStart, 2);
// Append dictionary containinig meta-data and ephemeral key info. // Append dictionary containinig meta-data and ephemeral key info.
const int cryptSectionStart = ii; const int cryptSectionStart = ii;
FCV< uint8_t, 2048 > md; FCV<uint8_t, 2048> md;
Dictionary::append(md, ZT_PROTO_HELLO_NODE_META_INSTANCE_ID, ctx.instanceId); Dictionary::append(md, ZT_PROTO_HELLO_NODE_META_INSTANCE_ID, ctx.instanceId);
// TODO: add other fields and ephemeral key info // TODO: add other fields and ephemeral key info
outp.wI16(ii, (uint16_t)md.size()); outp.wI16(ii, (uint16_t)md.size());
@ -694,7 +790,7 @@ unsigned int Peer::m_hello(const Context &ctx, const CallContext &cc, int64_t lo
// particular this means that the public keys exchanged for ephemeral keying // particular this means that the public keys exchanged for ephemeral keying
// are concealed from any observer. // are concealed from any observer.
AES::CTR ctr(m_helloCipher); AES::CTR ctr(m_helloCipher);
void *const cryptSection = outp.unsafeData + ii; void* const cryptSection = outp.unsafeData + ii;
ctr.init(outp.unsafeData + ivStart, 0, cryptSection); ctr.init(outp.unsafeData + ivStart, 0, cryptSection);
ctr.crypt(cryptSection, ii - cryptSectionStart); ctr.crypt(cryptSection, ii - cryptSectionStart);
ctr.finish(); ctr.finish();
@ -708,12 +804,26 @@ unsigned int Peer::m_hello(const Context &ctx, const CallContext &cc, int64_t lo
Protocol::salsa2012DeriveKey(m_identityKey.key(), perPacketKey, outp, ii); Protocol::salsa2012DeriveKey(m_identityKey.key(), perPacketKey, outp, ii);
Salsa20(perPacketKey, &packetId).crypt12(Utils::ZERO256, polyKey, sizeof(polyKey)); Salsa20(perPacketKey, &packetId).crypt12(Utils::ZERO256, polyKey, sizeof(polyKey));
Poly1305 p1305(polyKey); Poly1305 p1305(polyKey);
p1305.update(outp.unsafeData + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START, ii - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START); p1305.update(
outp.unsafeData + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,
ii - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START);
uint64_t polyMac[2]; uint64_t polyMac[2];
p1305.finish(polyMac); p1305.finish(polyMac);
Utils::storeMachineEndian< uint64_t >(outp.unsafeData + ZT_PROTO_PACKET_MAC_INDEX, polyMac[0]); Utils::storeMachineEndian<uint64_t>(outp.unsafeData + ZT_PROTO_PACKET_MAC_INDEX, polyMac[0]);
return (likely(ctx.cb.wirePacketSendFunction(reinterpret_cast<ZT_Node *>(ctx.node), ctx.uPtr, cc.tPtr, localSocket, reinterpret_cast<const ZT_InetAddress *>(&atAddress), outp.unsafeData, ii, 0) == 0)) ? (unsigned int)ii : 0U; return (likely(
ctx.cb.wirePacketSendFunction(
reinterpret_cast<ZT_Node*>(ctx.node),
ctx.uPtr,
cc.tPtr,
localSocket,
reinterpret_cast<const ZT_InetAddress*>(&atAddress),
outp.unsafeData,
ii,
0)
== 0))
? (unsigned int)ii
: 0U;
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -14,31 +14,26 @@
#ifndef ZT_PEER_HPP #ifndef ZT_PEER_HPP
#define ZT_PEER_HPP #define ZT_PEER_HPP
#include "Constants.hpp" #include "AES.hpp"
#include "Context.hpp"
#include "Node.hpp"
#include "Path.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Utils.hpp" #include "Constants.hpp"
#include "Containers.hpp"
#include "Context.hpp"
#include "Endpoint.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "InetAddress.hpp" #include "InetAddress.hpp"
#include "SharedPtr.hpp"
#include "Mutex.hpp"
#include "Endpoint.hpp"
#include "Locator.hpp" #include "Locator.hpp"
#include "Mutex.hpp"
#include "Node.hpp"
#include "Path.hpp"
#include "Protocol.hpp" #include "Protocol.hpp"
#include "AES.hpp" #include "SharedPtr.hpp"
#include "SymmetricKey.hpp" #include "SymmetricKey.hpp"
#include "Containers.hpp" #include "Utils.hpp"
#define ZT_PEER_MARSHAL_SIZE_MAX ( \ #define ZT_PEER_MARSHAL_SIZE_MAX \
1 + \ (1 + ZT_ADDRESS_LENGTH + ZT_SYMMETRIC_KEY_SIZE + ZT_IDENTITY_MARSHAL_SIZE_MAX + 1 + ZT_LOCATOR_MARSHAL_SIZE_MAX \
ZT_ADDRESS_LENGTH + \ + (2 * 4) + 2)
ZT_SYMMETRIC_KEY_SIZE + \
ZT_IDENTITY_MARSHAL_SIZE_MAX + \
1 + ZT_LOCATOR_MARSHAL_SIZE_MAX + \
(2 * 4) + \
2 )
#define ZT_PEER_DEDUP_BUFFER_SIZE 1024 #define ZT_PEER_DEDUP_BUFFER_SIZE 1024
#define ZT_PEER_DEDUP_BUFFER_MASK 1023U #define ZT_PEER_DEDUP_BUFFER_MASK 1023U
@ -52,12 +47,11 @@ class Topology;
/** /**
* Peer on P2P Network (virtual layer 1) * Peer on P2P Network (virtual layer 1)
*/ */
class Peer class Peer {
{ friend class SharedPtr<Peer>;
friend class SharedPtr< Peer >;
friend class Topology; friend class Topology;
public: public:
/** /**
* Create an uninitialized peer * Create an uninitialized peer
* *
@ -74,24 +68,28 @@ public:
* @param peerIdentity The peer's identity * @param peerIdentity The peer's identity
* @return True if initialization was succcesful * @return True if initialization was succcesful
*/ */
bool init(const Context &ctx, const CallContext &cc, const Identity &peerIdentity); bool init(const Context& ctx, const CallContext& cc, const Identity& peerIdentity);
/** /**
* @return This peer's ZT address (short for identity().address()) * @return This peer's ZT address (short for identity().address())
*/ */
ZT_INLINE Address address() const noexcept ZT_INLINE Address address() const noexcept
{ return m_id.address(); } {
return m_id.address();
}
/** /**
* @return This peer's identity * @return This peer's identity
*/ */
ZT_INLINE const Identity &identity() const noexcept ZT_INLINE const Identity& identity() const noexcept
{ return m_id; } {
return m_id;
}
/** /**
* @return Current locator or NULL if no locator is known * @return Current locator or NULL if no locator is known
*/ */
ZT_INLINE const SharedPtr< const Locator > locator() const noexcept ZT_INLINE const SharedPtr<const Locator> locator() const noexcept
{ {
RWMutex::RLock l(m_lock); RWMutex::RLock l(m_lock);
return m_locator; return m_locator;
@ -107,11 +105,11 @@ public:
* @param verify If true, verify locator's signature and structure * @param verify If true, verify locator's signature and structure
* @return New locator or previous if it was not replaced. * @return New locator or previous if it was not replaced.
*/ */
ZT_INLINE SharedPtr< const Locator > setLocator(const SharedPtr< const Locator > &loc, const bool verify) noexcept ZT_INLINE SharedPtr<const Locator> setLocator(const SharedPtr<const Locator>& loc, const bool verify) noexcept
{ {
RWMutex::Lock l(m_lock); RWMutex::Lock l(m_lock);
if ((loc) && ((!m_locator) || (m_locator->revision() < loc->revision()))) { if ((loc) && ((! m_locator) || (m_locator->revision() < loc->revision()))) {
if ((!verify) || loc->verify(m_id)) if ((! verify) || loc->verify(m_id))
m_locator = loc; m_locator = loc;
} }
return m_locator; return m_locator;
@ -130,9 +128,9 @@ public:
* @param inReVerb In-reply verb for OK or ERROR verbs * @param inReVerb In-reply verb for OK or ERROR verbs
*/ */
void received( void received(
const Context &ctx, const Context& ctx,
const CallContext &cc, const CallContext& cc,
const SharedPtr< Path > &path, const SharedPtr<Path>& path,
unsigned int hops, unsigned int hops,
uint64_t packetId, uint64_t packetId,
unsigned int payloadLength, unsigned int payloadLength,
@ -144,7 +142,7 @@ public:
* *
* @param bytes Number of bytes written * @param bytes Number of bytes written
*/ */
ZT_INLINE void sent(const CallContext &cc, const unsigned int bytes) noexcept ZT_INLINE void sent(const CallContext& cc, const unsigned int bytes) noexcept
{ {
m_lastSend.store(cc.ticks, std::memory_order_relaxed); m_lastSend.store(cc.ticks, std::memory_order_relaxed);
m_outMeter.log(cc.ticks, bytes); m_outMeter.log(cc.ticks, bytes);
@ -155,16 +153,20 @@ public:
* *
* @param bytes Number of bytes relayed * @param bytes Number of bytes relayed
*/ */
ZT_INLINE void relayed(const CallContext &cc, const unsigned int bytes) noexcept ZT_INLINE void relayed(const CallContext& cc, const unsigned int bytes) noexcept
{ m_relayedMeter.log(cc.ticks, bytes); } {
m_relayedMeter.log(cc.ticks, bytes);
}
/** /**
* Get the current best direct path or NULL if none * Get the current best direct path or NULL if none
* *
* @return Current best path or NULL if there is no direct path * @return Current best path or NULL if there is no direct path
*/ */
ZT_INLINE SharedPtr< Path > path(const CallContext &cc) noexcept ZT_INLINE SharedPtr<Path> path(const CallContext& cc) noexcept
{ return SharedPtr< Path >(reinterpret_cast<Path *>(m_bestPath.load(std::memory_order_acquire))); } {
return SharedPtr<Path>(reinterpret_cast<Path*>(m_bestPath.load(std::memory_order_acquire)));
}
/** /**
* Send data to this peer over a specific path only * Send data to this peer over a specific path only
@ -173,7 +175,9 @@ public:
* @param len Length in bytes * @param len Length in bytes
* @param via Path over which to send data (may or may not be an already-learned path for this peer) * @param via Path over which to send data (may or may not be an already-learned path for this peer)
*/ */
ZT_INLINE void send(const Context &ctx, const CallContext &cc, const void *data, unsigned int len, const SharedPtr< Path > &via) noexcept ZT_INLINE void
send(const Context& ctx, const CallContext& cc, const void* data, unsigned int len, const SharedPtr<Path>& via)
noexcept
{ {
via->send(ctx, cc, data, len); via->send(ctx, cc, data, len);
sent(cc, len); sent(cc, len);
@ -188,12 +192,12 @@ public:
* @param data Data to send * @param data Data to send
* @param len Length in bytes * @param len Length in bytes
*/ */
void send(const Context &ctx, const CallContext &cc, const void *data, unsigned int len) noexcept; void send(const Context& ctx, const CallContext& cc, const void* data, unsigned int len) noexcept;
/** /**
* Do ping, probes, re-keying, and keepalive with this peer, as needed. * Do ping, probes, re-keying, and keepalive with this peer, as needed.
*/ */
void pulse(const Context &ctx, const CallContext &cc); void pulse(const Context& ctx, const CallContext& cc);
/** /**
* Attempt to contact this peer at a given endpoint. * Attempt to contact this peer at a given endpoint.
@ -204,7 +208,7 @@ public:
* @param ep Endpoint to attempt to contact * @param ep Endpoint to attempt to contact
* @param tries Number of times to try (default: 1) * @param tries Number of times to try (default: 1)
*/ */
void contact(const Context &ctx, const CallContext &cc, const Endpoint &ep, int tries = 1); void contact(const Context& ctx, const CallContext& cc, const Endpoint& ep, int tries = 1);
/** /**
* Reset paths within a given IP scope and address family * Reset paths within a given IP scope and address family
@ -217,13 +221,15 @@ public:
* @param scope IP scope * @param scope IP scope
* @param inetAddressFamily Family e.g. AF_INET * @param inetAddressFamily Family e.g. AF_INET
*/ */
void resetWithinScope(const Context &ctx, const CallContext &cc, InetAddress::IpScope scope, int inetAddressFamily); void resetWithinScope(const Context& ctx, const CallContext& cc, InetAddress::IpScope scope, int inetAddressFamily);
/** /**
* @return Time of last receive of anything, whether direct or relayed * @return Time of last receive of anything, whether direct or relayed
*/ */
ZT_INLINE int64_t lastReceive() const noexcept ZT_INLINE int64_t lastReceive() const noexcept
{ return m_lastReceive.load(std::memory_order_relaxed); } {
return m_lastReceive.load(std::memory_order_relaxed);
}
/** /**
* @return Average latency of all direct paths or -1 if no direct paths or unknown * @return Average latency of all direct paths or -1 if no direct paths or unknown
@ -248,7 +254,7 @@ public:
*/ */
ZT_INLINE uint8_t cipher() const noexcept ZT_INLINE uint8_t cipher() const noexcept
{ {
//if (m_vProto >= 11) // if (m_vProto >= 11)
// return ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV; // return ZT_PROTO_CIPHER_SUITE__AES_GMAC_SIV;
return ZT_PROTO_CIPHER_POLY1305_SALSA2012; return ZT_PROTO_CIPHER_POLY1305_SALSA2012;
} }
@ -256,32 +262,42 @@ public:
/** /**
* @return The permanent shared key for this peer computed by simple identity agreement * @return The permanent shared key for this peer computed by simple identity agreement
*/ */
ZT_INLINE SymmetricKey &identityKey() noexcept ZT_INLINE SymmetricKey& identityKey() noexcept
{ return m_identityKey; } {
return m_identityKey;
}
/** /**
* @return AES instance for HELLO dictionary / encrypted section encryption/decryption * @return AES instance for HELLO dictionary / encrypted section encryption/decryption
*/ */
ZT_INLINE const AES &identityHelloDictionaryEncryptionCipher() const noexcept ZT_INLINE const AES& identityHelloDictionaryEncryptionCipher() const noexcept
{ return m_helloCipher; } {
return m_helloCipher;
}
/** /**
* @return Key for HMAC on HELLOs * @return Key for HMAC on HELLOs
*/ */
ZT_INLINE const uint8_t *identityHelloHmacKey() const noexcept ZT_INLINE const uint8_t* identityHelloHmacKey() const noexcept
{ return m_helloMacKey; } {
return m_helloMacKey;
}
/** /**
* @return Raw identity key bytes * @return Raw identity key bytes
*/ */
ZT_INLINE const uint8_t *rawIdentityKey() const noexcept ZT_INLINE const uint8_t* rawIdentityKey() const noexcept
{ return m_identityKey.key(); } {
return m_identityKey.key();
}
/** /**
* @return Current best key: either the latest ephemeral or the identity key * @return Current best key: either the latest ephemeral or the identity key
*/ */
ZT_INLINE SymmetricKey &key() noexcept ZT_INLINE SymmetricKey& key() noexcept
{ return *reinterpret_cast<SymmetricKey *>(m_key.load(std::memory_order_relaxed)); } {
return *reinterpret_cast<SymmetricKey*>(m_key.load(std::memory_order_relaxed));
}
/** /**
* Get keys other than a key we have already tried. * Get keys other than a key we have already tried.
@ -294,14 +310,16 @@ public:
* @param notYetTried All keys known (long lived or session) other than alreadyTried * @param notYetTried All keys known (long lived or session) other than alreadyTried
* @return Number of pointers written to notYetTried[] * @return Number of pointers written to notYetTried[]
*/ */
ZT_INLINE int getOtherKeys(const SymmetricKey *const alreadyTried, SymmetricKey *notYetTried[ZT_PEER_EPHEMERAL_KEY_COUNT_MAX]) noexcept ZT_INLINE int getOtherKeys(
const SymmetricKey* const alreadyTried,
SymmetricKey* notYetTried[ZT_PEER_EPHEMERAL_KEY_COUNT_MAX]) noexcept
{ {
RWMutex::RLock l(m_lock); RWMutex::RLock l(m_lock);
int cnt = 0; int cnt = 0;
if (alreadyTried != &m_identityKey) if (alreadyTried != &m_identityKey)
notYetTried[cnt++] = &m_identityKey; notYetTried[cnt++] = &m_identityKey;
for (unsigned int k=0;k<ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE;++k) { for (unsigned int k = 0; k < ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE; ++k) {
SymmetricKey *const kk = &m_ephemeralSessions[k].key; SymmetricKey* const kk = &m_ephemeralSessions[k].key;
if (m_ephemeralSessions[k].established && (alreadyTried != kk)) if (m_ephemeralSessions[k].established && (alreadyTried != kk))
notYetTried[cnt++] = kk; notYetTried[cnt++] = kk;
} }
@ -330,7 +348,8 @@ public:
* @param vmin Minor version * @param vmin Minor version
* @param vrev Revision * @param vrev Revision
*/ */
ZT_INLINE void setRemoteVersion(unsigned int vproto, unsigned int vmaj, unsigned int vmin, unsigned int vrev) noexcept ZT_INLINE void
setRemoteVersion(unsigned int vproto, unsigned int vmaj, unsigned int vmin, unsigned int vrev) noexcept
{ {
RWMutex::Lock l(m_lock); RWMutex::Lock l(m_lock);
m_vProto = (uint16_t)vproto; m_vProto = (uint16_t)vproto;
@ -351,10 +370,10 @@ public:
* @param vRevision Set to revision * @param vRevision Set to revision
* @return True if remote version is known * @return True if remote version is known
*/ */
ZT_INLINE bool remoteVersion(uint16_t &vProto, uint16_t &vMajor, uint16_t &vMinor, uint16_t &vRevision) ZT_INLINE bool remoteVersion(uint16_t& vProto, uint16_t& vMajor, uint16_t& vMinor, uint16_t& vRevision)
{ {
RWMutex::RLock l(m_lock); RWMutex::RLock l(m_lock);
return (((vProto = m_vProto)|(vMajor = m_vMajor)|(vMinor = m_vMinor)|(vRevision = m_vRevision)) != 0); return (((vProto = m_vProto) | (vMajor = m_vMajor) | (vMinor = m_vMinor) | (vRevision = m_vRevision)) != 0);
} }
/** /**
@ -371,7 +390,7 @@ public:
* *
* @param paths Vector of paths with the first path being the current preferred path * @param paths Vector of paths with the first path being the current preferred path
*/ */
ZT_INLINE void getAllPaths(Vector< SharedPtr< Path > > &paths) const ZT_INLINE void getAllPaths(Vector<SharedPtr<Path> >& paths) const
{ {
RWMutex::RLock l(m_lock); RWMutex::RLock l(m_lock);
paths.assign(m_paths, m_paths + m_alivePathCount); paths.assign(m_paths, m_paths + m_alivePathCount);
@ -380,18 +399,20 @@ public:
/** /**
* Save the latest version of this peer to the data store * Save the latest version of this peer to the data store
*/ */
void save(const Context &ctx, const CallContext &cc) const; void save(const Context& ctx, const CallContext& cc) const;
static constexpr int marshalSizeMax() noexcept static constexpr int marshalSizeMax() noexcept
{ return ZT_PEER_MARSHAL_SIZE_MAX; } {
return ZT_PEER_MARSHAL_SIZE_MAX;
}
int marshal(const Context &ctx, uint8_t data[ZT_PEER_MARSHAL_SIZE_MAX]) const noexcept; int marshal(const Context& ctx, uint8_t data[ZT_PEER_MARSHAL_SIZE_MAX]) const noexcept;
int unmarshal(const Context &ctx, int64_t ticks, const uint8_t *restrict data, int len) noexcept; int unmarshal(const Context& ctx, int64_t ticks, const uint8_t* restrict data, int len) noexcept;
/** /**
* Rate limit gate for inbound WHOIS requests * Rate limit gate for inbound WHOIS requests
*/ */
ZT_INLINE bool rateGateInboundWhoisRequest(CallContext &cc) noexcept ZT_INLINE bool rateGateInboundWhoisRequest(CallContext& cc) noexcept
{ {
if ((cc.ticks - m_lastWhoisRequestReceived.load(std::memory_order_relaxed)) >= ZT_PEER_WHOIS_RATE_LIMIT) { if ((cc.ticks - m_lastWhoisRequestReceived.load(std::memory_order_relaxed)) >= ZT_PEER_WHOIS_RATE_LIMIT) {
m_lastWhoisRequestReceived.store(cc.ticks, std::memory_order_relaxed); m_lastWhoisRequestReceived.store(cc.ticks, std::memory_order_relaxed);
@ -403,7 +424,7 @@ public:
/** /**
* Rate limit gate for inbound ECHO requests * Rate limit gate for inbound ECHO requests
*/ */
ZT_INLINE bool rateGateEchoRequest(CallContext &cc) noexcept ZT_INLINE bool rateGateEchoRequest(CallContext& cc) noexcept
{ {
if ((cc.ticks - m_lastEchoRequestReceived.load(std::memory_order_relaxed)) >= ZT_PEER_GENERAL_RATE_LIMIT) { if ((cc.ticks - m_lastEchoRequestReceived.load(std::memory_order_relaxed)) >= ZT_PEER_GENERAL_RATE_LIMIT) {
m_lastEchoRequestReceived.store(cc.ticks, std::memory_order_relaxed); m_lastEchoRequestReceived.store(cc.ticks, std::memory_order_relaxed);
@ -415,7 +436,7 @@ public:
/** /**
* Rate limit gate for inbound probes * Rate limit gate for inbound probes
*/ */
ZT_INLINE bool rateGateProbeRequest(CallContext &cc) noexcept ZT_INLINE bool rateGateProbeRequest(CallContext& cc) noexcept
{ {
if ((cc.ticks - m_lastProbeReceived.load(std::memory_order_relaxed)) > ZT_PEER_PROBE_RESPONSE_RATE_LIMIT) { if ((cc.ticks - m_lastProbeReceived.load(std::memory_order_relaxed)) > ZT_PEER_PROBE_RESPONSE_RATE_LIMIT) {
m_lastProbeReceived.store(cc.ticks, std::memory_order_relaxed); m_lastProbeReceived.store(cc.ticks, std::memory_order_relaxed);
@ -434,25 +455,33 @@ public:
* @return True if this is a duplicate * @return True if this is a duplicate
*/ */
ZT_INLINE bool deduplicateIncomingPacket(const uint64_t packetId) noexcept ZT_INLINE bool deduplicateIncomingPacket(const uint64_t packetId) noexcept
{ return m_dedup[Utils::hash32((uint32_t)packetId) & ZT_PEER_DEDUP_BUFFER_MASK].exchange(packetId, std::memory_order_relaxed) == packetId; }
private:
struct p_EphemeralPublic
{ {
return m_dedup[Utils::hash32((uint32_t)packetId) & ZT_PEER_DEDUP_BUFFER_MASK].exchange(
packetId,
std::memory_order_relaxed)
== packetId;
}
private:
struct p_EphemeralPublic {
uint8_t type; uint8_t type;
uint8_t c25519Public[ZT_C25519_ECDH_PUBLIC_KEY_SIZE]; uint8_t c25519Public[ZT_C25519_ECDH_PUBLIC_KEY_SIZE];
uint8_t p384Public[ZT_ECC384_PUBLIC_KEY_SIZE]; uint8_t p384Public[ZT_ECC384_PUBLIC_KEY_SIZE];
}; };
static_assert(sizeof(p_EphemeralPublic) == (1 + ZT_C25519_ECDH_PUBLIC_KEY_SIZE + ZT_ECC384_PUBLIC_KEY_SIZE), "p_EphemeralPublic has extra padding"); static_assert(
sizeof(p_EphemeralPublic) == (1 + ZT_C25519_ECDH_PUBLIC_KEY_SIZE + ZT_ECC384_PUBLIC_KEY_SIZE),
"p_EphemeralPublic has extra padding");
struct p_EphemeralPrivate struct p_EphemeralPrivate {
ZT_INLINE p_EphemeralPrivate() noexcept : creationTime(-1)
{ {
ZT_INLINE p_EphemeralPrivate() noexcept: creationTime(-1) }
{}
ZT_INLINE ~p_EphemeralPrivate() ZT_INLINE ~p_EphemeralPrivate()
{ Utils::burn(this, sizeof(p_EphemeralPublic)); } {
Utils::burn(this, sizeof(p_EphemeralPublic));
}
int64_t creationTime; int64_t creationTime;
uint64_t sha384OfPublic[6]; uint64_t sha384OfPublic[6];
@ -461,20 +490,31 @@ private:
uint8_t p384Private[ZT_ECC384_PRIVATE_KEY_SIZE]; uint8_t p384Private[ZT_ECC384_PRIVATE_KEY_SIZE];
}; };
struct p_EphemeralSession struct p_EphemeralSession {
ZT_INLINE p_EphemeralSession() noexcept : established(false)
{ {
ZT_INLINE p_EphemeralSession() noexcept: established(false) }
{}
uint64_t sha384OfPeerPublic[6]; uint64_t sha384OfPeerPublic[6];
SymmetricKey key; SymmetricKey key;
bool established; bool established;
}; };
void m_prioritizePaths(const CallContext &cc); void m_prioritizePaths(const CallContext& cc);
unsigned int m_sendProbe(const Context &ctx, const CallContext &cc, int64_t localSocket, const InetAddress &atAddress, const uint16_t *ports, unsigned int numPorts); unsigned int m_sendProbe(
const Context& ctx,
const CallContext& cc,
int64_t localSocket,
const InetAddress& atAddress,
const uint16_t* ports,
unsigned int numPorts);
void m_deriveSecondaryIdentityKeys() noexcept; void m_deriveSecondaryIdentityKeys() noexcept;
unsigned int m_hello(const Context &ctx, const CallContext &cc, int64_t localSocket, const InetAddress &atAddress, bool forceNewKey); unsigned int m_hello(
const Context& ctx,
const CallContext& cc,
int64_t localSocket,
const InetAddress& atAddress,
bool forceNewKey);
// Guards all fields except those otherwise indicated (and atomics of course). // Guards all fields except those otherwise indicated (and atomics of course).
RWMutex m_lock; RWMutex m_lock;
@ -495,7 +535,7 @@ private:
p_EphemeralSession m_ephemeralSessions[ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE]; p_EphemeralSession m_ephemeralSessions[ZT_PEER_EPHEMERAL_KEY_BUFFER_SIZE];
// Pointer to active key (SymmetricKey). // Pointer to active key (SymmetricKey).
std::atomic< uintptr_t > m_key; std::atomic<uintptr_t> m_key;
// Flag indicating that we should rekey at next pulse(). // Flag indicating that we should rekey at next pulse().
bool m_keyRenegotiationNeeded; bool m_keyRenegotiationNeeded;
@ -504,26 +544,26 @@ private:
Identity m_id; Identity m_id;
// This peer's most recent (by revision) locator, or NULL if none on file. // This peer's most recent (by revision) locator, or NULL if none on file.
SharedPtr< const Locator > m_locator; SharedPtr<const Locator> m_locator;
// The last time something was received or sent. // The last time something was received or sent.
std::atomic< int64_t > m_lastReceive; std::atomic<int64_t> m_lastReceive;
std::atomic< int64_t > m_lastSend; std::atomic<int64_t> m_lastSend;
// The last time we sent a full HELLO to this peer. // The last time we sent a full HELLO to this peer.
int64_t m_lastSentHello; // only checked while locked int64_t m_lastSentHello; // only checked while locked
// The last time a WHOIS request was received from this peer (anti-DOS / anti-flood). // The last time a WHOIS request was received from this peer (anti-DOS / anti-flood).
std::atomic< int64_t > m_lastWhoisRequestReceived; std::atomic<int64_t> m_lastWhoisRequestReceived;
// The last time an ECHO request was received from this peer (anti-DOS / anti-flood). // The last time an ECHO request was received from this peer (anti-DOS / anti-flood).
std::atomic< int64_t > m_lastEchoRequestReceived; std::atomic<int64_t> m_lastEchoRequestReceived;
// The last time we got a probe from this peer. // The last time we got a probe from this peer.
std::atomic< int64_t > m_lastProbeReceived; std::atomic<int64_t> m_lastProbeReceived;
// Deduplication buffer. // Deduplication buffer.
std::atomic< uint64_t > m_dedup[ZT_PEER_DEDUP_BUFFER_SIZE]; std::atomic<uint64_t> m_dedup[ZT_PEER_DEDUP_BUFFER_SIZE];
// Meters measuring actual bandwidth in, out, and relayed via this peer (mostly if this is a root). // Meters measuring actual bandwidth in, out, and relayed via this peer (mostly if this is a root).
Meter<> m_inMeter; Meter<> m_inMeter;
@ -531,7 +571,7 @@ private:
Meter<> m_relayedMeter; Meter<> m_relayedMeter;
// Direct paths sorted in descending order of preference. // Direct paths sorted in descending order of preference.
SharedPtr< Path > m_paths[ZT_MAX_PEER_NETWORK_PATHS]; SharedPtr<Path> m_paths[ZT_MAX_PEER_NETWORK_PATHS];
// Size of m_paths[] in non-NULL paths (max: MAX_PEER_NETWORK_PATHS). // Size of m_paths[] in non-NULL paths (max: MAX_PEER_NETWORK_PATHS).
unsigned int m_alivePathCount; unsigned int m_alivePathCount;
@ -540,29 +580,26 @@ private:
std::atomic<uintptr_t> m_bestPath; std::atomic<uintptr_t> m_bestPath;
// For SharedPtr<> // For SharedPtr<>
std::atomic< int > __refCount; std::atomic<int> __refCount;
struct p_TryQueueItem struct p_TryQueueItem {
ZT_INLINE p_TryQueueItem() : target(), iteration(0)
{ {
ZT_INLINE p_TryQueueItem() : }
target(),
iteration(0)
{}
ZT_INLINE p_TryQueueItem(const Endpoint &t, int iter) : ZT_INLINE p_TryQueueItem(const Endpoint& t, int iter) : target(t), iteration(iter)
target(t), {
iteration(iter) }
{}
Endpoint target; Endpoint target;
int iteration; int iteration;
}; };
// Queue of endpoints to try. // Queue of endpoints to try.
List< p_TryQueueItem > m_tryQueue; List<p_TryQueueItem> m_tryQueue;
// Time each endpoint was last tried, for rate limiting. // Time each endpoint was last tried, for rate limiting.
Map< Endpoint, int64_t > m_lastTried; Map<Endpoint, int64_t> m_lastTried;
// Version of remote peer, if known. // Version of remote peer, if known.
uint16_t m_vProto; uint16_t m_vProto;

View file

@ -6,20 +6,21 @@ Public domain.
// Small modifications have been made for ZeroTier, but this code remains in the public domain. // Small modifications have been made for ZeroTier, but this code remains in the public domain.
#include "Constants.hpp"
#include "Poly1305.hpp" #include "Poly1305.hpp"
#include "Constants.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#include <cstring> #include <cstring>
#ifdef __WINDOWS__ #ifdef __WINDOWS__
#pragma warning(disable: 4146) #pragma warning(disable : 4146)
#endif #endif
#define U8TO64(p) Utils::loadLittleEndian<uint64_t>(p) #define U8TO64(p) Utils::loadLittleEndian<uint64_t>(p)
#define U64TO8(p,v) Utils::storeLittleEndian<uint64_t>(p,v) #define U64TO8(p, v) Utils::storeLittleEndian<uint64_t>(p, v)
#define U8TO32(p) Utils::loadLittleEndian<uint32_t>(p) #define U8TO32(p) Utils::loadLittleEndian<uint32_t>(p)
#define U32TO8(p,v) Utils::storeLittleEndian<uint32_t>(p,v) #define U32TO8(p, v) Utils::storeLittleEndian<uint32_t>(p, v)
namespace ZeroTier { namespace ZeroTier {
@ -49,18 +50,18 @@ typedef struct poly1305_state_internal_t {
unsigned char final; unsigned char final;
} poly1305_state_internal_t; } poly1305_state_internal_t;
ZT_INLINE void poly1305_init(poly1305_context *ctx,const unsigned char key[32]) ZT_INLINE void poly1305_init(poly1305_context* ctx, const unsigned char key[32])
{ {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
unsigned long long t0,t1; unsigned long long t0, t1;
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
t0 = U8TO64(&key[0]); t0 = U8TO64(&key[0]);
t1 = U8TO64(&key[8]); t1 = U8TO64(&key[8]);
st->r[0] = ( t0 ) & 0xffc0fffffff; st->r[0] = (t0)&0xffc0fffffff;
st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff; st->r[1] = ((t0 >> 44) | (t1 << 20)) & 0xfffffc0ffff;
st->r[2] = ((t1 >> 24) ) & 0x00ffffffc0f; st->r[2] = ((t1 >> 24)) & 0x00ffffffc0f;
/* h = 0 */ /* h = 0 */
st->h[0] = 0; st->h[0] = 0;
@ -75,13 +76,13 @@ ZT_INLINE void poly1305_init(poly1305_context *ctx,const unsigned char key[32])
st->final = 0; st->final = 0;
} }
void poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) void poly1305_blocks(poly1305_state_internal_t* st, const unsigned char* m, size_t bytes)
{ {
const unsigned long long hibit = (st->final) ? 0 : ((unsigned long long)1 << 40); /* 1 << 128 */ const unsigned long long hibit = (st->final) ? 0 : ((unsigned long long)1 << 40); /* 1 << 128 */
unsigned long long r0,r1,r2; unsigned long long r0, r1, r2;
unsigned long long s1,s2; unsigned long long s1, s2;
unsigned long long h0,h1,h2; unsigned long long h0, h1, h2;
uint128_t d0,d1,d2,d; uint128_t d0, d1, d2, d;
r0 = st->r[0]; r0 = st->r[0];
r1 = st->r[1]; r1 = st->r[1];
@ -95,26 +96,45 @@ void poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size
s2 = r2 * (5 << 2); s2 = r2 * (5 << 2);
while (bytes >= poly1305_block_size) { while (bytes >= poly1305_block_size) {
unsigned long long t0,t1; unsigned long long t0, t1;
/* h += m[i] */ /* h += m[i] */
t0 = U8TO64(&m[0]); t0 = U8TO64(&m[0]);
t1 = U8TO64(&m[8]); t1 = U8TO64(&m[8]);
h0 += (( t0 ) & 0xfffffffffff); h0 += ((t0)&0xfffffffffff);
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff); h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff);
h2 += (((t1 >> 24) ) & 0x3ffffffffff) | hibit; h2 += (((t1 >> 24)) & 0x3ffffffffff) | hibit;
/* h *= r */ /* h *= r */
MUL(d0, h0, r0); MUL(d, h1, s2); ADD(d0, d); MUL(d, h2, s1); ADD(d0, d); MUL(d0, h0, r0);
MUL(d1, h0, r1); MUL(d, h1, r0); ADD(d1, d); MUL(d, h2, s2); ADD(d1, d); MUL(d, h1, s2);
MUL(d2, h0, r2); MUL(d, h1, r1); ADD(d2, d); MUL(d, h2, r0); ADD(d2, d); ADD(d0, d);
MUL(d, h2, s1);
ADD(d0, d);
MUL(d1, h0, r1);
MUL(d, h1, r0);
ADD(d1, d);
MUL(d, h2, s2);
ADD(d1, d);
MUL(d2, h0, r2);
MUL(d, h1, r1);
ADD(d2, d);
MUL(d, h2, r0);
ADD(d2, d);
/* (partial) h %= p */ /* (partial) h %= p */
unsigned long long c = SHR(d0, 44); h0 = LO(d0) & 0xfffffffffff; unsigned long long c = SHR(d0, 44);
ADDLO(d1, c); c = SHR(d1, 44); h1 = LO(d1) & 0xfffffffffff; h0 = LO(d0) & 0xfffffffffff;
ADDLO(d2, c); c = SHR(d2, 42); h2 = LO(d2) & 0x3ffffffffff; ADDLO(d1, c);
h0 += c * 5; c = (h0 >> 44); h0 = h0 & 0xfffffffffff; c = SHR(d1, 44);
h1 = LO(d1) & 0xfffffffffff;
ADDLO(d2, c);
c = SHR(d2, 42);
h2 = LO(d2) & 0x3ffffffffff;
h0 += c * 5;
c = (h0 >> 44);
h0 = h0 & 0xfffffffffff;
h1 += c; h1 += c;
m += poly1305_block_size; m += poly1305_block_size;
@ -126,12 +146,12 @@ void poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size
st->h[2] = h2; st->h[2] = h2;
} }
ZT_INLINE void poly1305_finish(poly1305_context *ctx,unsigned char mac[16]) ZT_INLINE void poly1305_finish(poly1305_context* ctx, unsigned char mac[16])
{ {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
unsigned long long h0,h1,h2,c; unsigned long long h0, h1, h2, c;
unsigned long long g0,g1,g2; unsigned long long g0, g1, g2;
unsigned long long t0,t1; unsigned long long t0, t1;
/* process the remaining block */ /* process the remaining block */
if (st->leftover) { if (st->leftover) {
@ -148,17 +168,32 @@ ZT_INLINE void poly1305_finish(poly1305_context *ctx,unsigned char mac[16])
h1 = st->h[1]; h1 = st->h[1];
h2 = st->h[2]; h2 = st->h[2];
c = (h1 >> 44); h1 &= 0xfffffffffff; c = (h1 >> 44);
h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff; h1 &= 0xfffffffffff;
h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff; h2 += c;
h1 += c; c = (h1 >> 44); h1 &= 0xfffffffffff; c = (h2 >> 42);
h2 += c; c = (h2 >> 42); h2 &= 0x3ffffffffff; h2 &= 0x3ffffffffff;
h0 += c * 5; c = (h0 >> 44); h0 &= 0xfffffffffff; h0 += c * 5;
c = (h0 >> 44);
h0 &= 0xfffffffffff;
h1 += c;
c = (h1 >> 44);
h1 &= 0xfffffffffff;
h2 += c;
c = (h2 >> 42);
h2 &= 0x3ffffffffff;
h0 += c * 5;
c = (h0 >> 44);
h0 &= 0xfffffffffff;
h1 += c; h1 += c;
/* compute h + -p */ /* compute h + -p */
g0 = h0 + 5; c = (g0 >> 44); g0 &= 0xfffffffffff; g0 = h0 + 5;
g1 = h1 + c; c = (g1 >> 44); g1 &= 0xfffffffffff; c = (g0 >> 44);
g0 &= 0xfffffffffff;
g1 = h1 + c;
c = (g1 >> 44);
g1 &= 0xfffffffffff;
g2 = h2 + c - ((unsigned long long)1 << 42); g2 = h2 + c - ((unsigned long long)1 << 42);
/* select h if h < p, or h + -p if h >= p */ /* select h if h < p, or h + -p if h >= p */
@ -175,12 +210,17 @@ ZT_INLINE void poly1305_finish(poly1305_context *ctx,unsigned char mac[16])
t0 = st->pad[0]; t0 = st->pad[0];
t1 = st->pad[1]; t1 = st->pad[1];
h0 += (( t0 ) & 0xfffffffffff) ; c = (h0 >> 44); h0 &= 0xfffffffffff; h0 += ((t0)&0xfffffffffff);
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c; c = (h1 >> 44); h1 &= 0xfffffffffff; c = (h0 >> 44);
h2 += (((t1 >> 24) ) & 0x3ffffffffff) + c; h2 &= 0x3ffffffffff; h0 &= 0xfffffffffff;
h1 += (((t0 >> 44) | (t1 << 20)) & 0xfffffffffff) + c;
c = (h1 >> 44);
h1 &= 0xfffffffffff;
h2 += (((t1 >> 24)) & 0x3ffffffffff) + c;
h2 &= 0x3ffffffffff;
/* mac = h % (2^128) */ /* mac = h % (2^128) */
h0 = ((h0 ) | (h1 << 44)); h0 = ((h0) | (h1 << 44));
h1 = ((h1 >> 20) | (h2 << 24)); h1 = ((h1 >> 20) | (h2 << 24));
U64TO8(&mac[0], h0); U64TO8(&mac[0], h0);
@ -210,15 +250,15 @@ typedef struct poly1305_state_internal_t {
unsigned char final; unsigned char final;
} poly1305_state_internal_t; } poly1305_state_internal_t;
ZT_INLINE void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) ZT_INLINE void poly1305_init(poly1305_context* ctx, const unsigned char key[32])
{ {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
/* r &= 0xffffffc0ffffffc0ffffffc0fffffff */ /* r &= 0xffffffc0ffffffc0ffffffc0fffffff */
st->r[0] = (U8TO32(&key[ 0]) ) & 0x3ffffff; st->r[0] = (U8TO32(&key[0])) & 0x3ffffff;
st->r[1] = (U8TO32(&key[ 3]) >> 2) & 0x3ffff03; st->r[1] = (U8TO32(&key[3]) >> 2) & 0x3ffff03;
st->r[2] = (U8TO32(&key[ 6]) >> 4) & 0x3ffc0ff; st->r[2] = (U8TO32(&key[6]) >> 4) & 0x3ffc0ff;
st->r[3] = (U8TO32(&key[ 9]) >> 6) & 0x3f03fff; st->r[3] = (U8TO32(&key[9]) >> 6) & 0x3f03fff;
st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff; st->r[4] = (U8TO32(&key[12]) >> 8) & 0x00fffff;
/* h = 0 */ /* h = 0 */
@ -238,12 +278,12 @@ ZT_INLINE void poly1305_init(poly1305_context *ctx, const unsigned char key[32])
st->final = 0; st->final = 0;
} }
void poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) void poly1305_blocks(poly1305_state_internal_t* st, const unsigned char* m, size_t bytes)
{ {
const unsigned long hibit = (st->final) ? 0 : (1 << 24); /* 1 << 128 */ const unsigned long hibit = (st->final) ? 0 : (1 << 24); /* 1 << 128 */
unsigned long r0,r1,r2,r3,r4; unsigned long r0, r1, r2, r3, r4;
unsigned long s1,s2,s3,s4; unsigned long s1, s2, s3, s4;
unsigned long h0,h1,h2,h3,h4; unsigned long h0, h1, h2, h3, h4;
r0 = st->r[0]; r0 = st->r[0];
r1 = st->r[1]; r1 = st->r[1];
@ -264,26 +304,47 @@ void poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size
while (bytes >= poly1305_block_size) { while (bytes >= poly1305_block_size) {
/* h += m[i] */ /* h += m[i] */
h0 += (U8TO32(m+ 0) ) & 0x3ffffff; h0 += (U8TO32(m + 0)) & 0x3ffffff;
h1 += (U8TO32(m+ 3) >> 2) & 0x3ffffff; h1 += (U8TO32(m + 3) >> 2) & 0x3ffffff;
h2 += (U8TO32(m+ 6) >> 4) & 0x3ffffff; h2 += (U8TO32(m + 6) >> 4) & 0x3ffffff;
h3 += (U8TO32(m+ 9) >> 6) & 0x3ffffff; h3 += (U8TO32(m + 9) >> 6) & 0x3ffffff;
h4 += (U8TO32(m+12) >> 8) | hibit; h4 += (U8TO32(m + 12) >> 8) | hibit;
/* h *= r */ /* h *= r */
unsigned long long d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4) + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2) + ((unsigned long long)h4 * s1); unsigned long long d0 = ((unsigned long long)h0 * r0) + ((unsigned long long)h1 * s4)
unsigned long long d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0) + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3) + ((unsigned long long)h4 * s2); + ((unsigned long long)h2 * s3) + ((unsigned long long)h3 * s2)
unsigned long long d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1) + ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4) + ((unsigned long long)h4 * s3); + ((unsigned long long)h4 * s1);
unsigned long long d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2) + ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0) + ((unsigned long long)h4 * s4); unsigned long long d1 = ((unsigned long long)h0 * r1) + ((unsigned long long)h1 * r0)
unsigned long long d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3) + ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1) + ((unsigned long long)h4 * r0); + ((unsigned long long)h2 * s4) + ((unsigned long long)h3 * s3)
+ ((unsigned long long)h4 * s2);
unsigned long long d2 = ((unsigned long long)h0 * r2) + ((unsigned long long)h1 * r1)
+ ((unsigned long long)h2 * r0) + ((unsigned long long)h3 * s4)
+ ((unsigned long long)h4 * s3);
unsigned long long d3 = ((unsigned long long)h0 * r3) + ((unsigned long long)h1 * r2)
+ ((unsigned long long)h2 * r1) + ((unsigned long long)h3 * r0)
+ ((unsigned long long)h4 * s4);
unsigned long long d4 = ((unsigned long long)h0 * r4) + ((unsigned long long)h1 * r3)
+ ((unsigned long long)h2 * r2) + ((unsigned long long)h3 * r1)
+ ((unsigned long long)h4 * r0);
/* (partial) h %= p */ /* (partial) h %= p */
unsigned long c = (unsigned long)(d0 >> 26); h0 = (unsigned long)d0 & 0x3ffffff; unsigned long c = (unsigned long)(d0 >> 26);
d1 += c; c = (unsigned long)(d1 >> 26); h1 = (unsigned long)d1 & 0x3ffffff; h0 = (unsigned long)d0 & 0x3ffffff;
d2 += c; c = (unsigned long)(d2 >> 26); h2 = (unsigned long)d2 & 0x3ffffff; d1 += c;
d3 += c; c = (unsigned long)(d3 >> 26); h3 = (unsigned long)d3 & 0x3ffffff; c = (unsigned long)(d1 >> 26);
d4 += c; c = (unsigned long)(d4 >> 26); h4 = (unsigned long)d4 & 0x3ffffff; h1 = (unsigned long)d1 & 0x3ffffff;
h0 += c * 5; c = (h0 >> 26); h0 = h0 & 0x3ffffff; d2 += c;
c = (unsigned long)(d2 >> 26);
h2 = (unsigned long)d2 & 0x3ffffff;
d3 += c;
c = (unsigned long)(d3 >> 26);
h3 = (unsigned long)d3 & 0x3ffffff;
d4 += c;
c = (unsigned long)(d4 >> 26);
h4 = (unsigned long)d4 & 0x3ffffff;
h0 += c * 5;
c = (h0 >> 26);
h0 = h0 & 0x3ffffff;
h1 += c; h1 += c;
m += poly1305_block_size; m += poly1305_block_size;
@ -297,11 +358,11 @@ void poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size
st->h[4] = h4; st->h[4] = h4;
} }
ZT_INLINE void poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) ZT_INLINE void poly1305_finish(poly1305_context* ctx, unsigned char mac[16])
{ {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
unsigned long h0,h1,h2,h3,h4,c; unsigned long h0, h1, h2, h3, h4, c;
unsigned long g0,g1,g2,g3,g4; unsigned long g0, g1, g2, g3, g4;
unsigned long long f; unsigned long long f;
unsigned long mask; unsigned long mask;
@ -322,18 +383,35 @@ ZT_INLINE void poly1305_finish(poly1305_context *ctx, unsigned char mac[16])
h3 = st->h[3]; h3 = st->h[3];
h4 = st->h[4]; h4 = st->h[4];
c = h1 >> 26; h1 = h1 & 0x3ffffff; c = h1 >> 26;
h2 += c; c = h2 >> 26; h2 = h2 & 0x3ffffff; h1 = h1 & 0x3ffffff;
h3 += c; c = h3 >> 26; h3 = h3 & 0x3ffffff; h2 += c;
h4 += c; c = h4 >> 26; h4 = h4 & 0x3ffffff; c = h2 >> 26;
h0 += c * 5; c = h0 >> 26; h0 = h0 & 0x3ffffff; h2 = h2 & 0x3ffffff;
h3 += c;
c = h3 >> 26;
h3 = h3 & 0x3ffffff;
h4 += c;
c = h4 >> 26;
h4 = h4 & 0x3ffffff;
h0 += c * 5;
c = h0 >> 26;
h0 = h0 & 0x3ffffff;
h1 += c; h1 += c;
/* compute h + -p */ /* compute h + -p */
g0 = h0 + 5; c = g0 >> 26; g0 &= 0x3ffffff; g0 = h0 + 5;
g1 = h1 + c; c = g1 >> 26; g1 &= 0x3ffffff; c = g0 >> 26;
g2 = h2 + c; c = g2 >> 26; g2 &= 0x3ffffff; g0 &= 0x3ffffff;
g3 = h3 + c; c = g3 >> 26; g3 &= 0x3ffffff; g1 = h1 + c;
c = g1 >> 26;
g1 &= 0x3ffffff;
g2 = h2 + c;
c = g2 >> 26;
g2 &= 0x3ffffff;
g3 = h3 + c;
c = g3 >> 26;
g3 &= 0x3ffffff;
g4 = h4 + c - (1 << 26); g4 = h4 + c - (1 << 26);
/* select h if h < p, or h + -p if h >= p */ /* select h if h < p, or h + -p if h >= p */
@ -351,16 +429,20 @@ ZT_INLINE void poly1305_finish(poly1305_context *ctx, unsigned char mac[16])
h4 = (h4 & mask) | g4; h4 = (h4 & mask) | g4;
/* h = h % (2^128) */ /* h = h % (2^128) */
h0 = ((h0 ) | (h1 << 26)) & 0xffffffff; h0 = ((h0) | (h1 << 26)) & 0xffffffff;
h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff; h1 = ((h1 >> 6) | (h2 << 20)) & 0xffffffff;
h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff; h2 = ((h2 >> 12) | (h3 << 14)) & 0xffffffff;
h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff; h3 = ((h3 >> 18) | (h4 << 8)) & 0xffffffff;
/* mac = (h + pad) % (2^128) */ /* mac = (h + pad) % (2^128) */
f = (unsigned long long)h0 + st->pad[0] ; h0 = (unsigned long)f; f = (unsigned long long)h0 + st->pad[0];
f = (unsigned long long)h1 + st->pad[1] + (f >> 32); h1 = (unsigned long)f; h0 = (unsigned long)f;
f = (unsigned long long)h2 + st->pad[2] + (f >> 32); h2 = (unsigned long)f; f = (unsigned long long)h1 + st->pad[1] + (f >> 32);
f = (unsigned long long)h3 + st->pad[3] + (f >> 32); h3 = (unsigned long)f; h1 = (unsigned long)f;
f = (unsigned long long)h2 + st->pad[2] + (f >> 32);
h2 = (unsigned long)f;
f = (unsigned long long)h3 + st->pad[3] + (f >> 32);
h3 = (unsigned long)f;
U32TO8(mac + 0, h0); U32TO8(mac + 0, h0);
U32TO8(mac + 4, h1); U32TO8(mac + 4, h1);
@ -386,9 +468,9 @@ ZT_INLINE void poly1305_finish(poly1305_context *ctx, unsigned char mac[16])
#endif // uint128_t or portable version? #endif // uint128_t or portable version?
ZT_INLINE void poly1305_update(poly1305_context *ctx,const unsigned char *m,size_t bytes) noexcept ZT_INLINE void poly1305_update(poly1305_context* ctx, const unsigned char* m, size_t bytes) noexcept
{ {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx; poly1305_state_internal_t* st = (poly1305_state_internal_t*)ctx;
size_t i; size_t i;
/* handle leftover */ /* handle leftover */
@ -425,20 +507,23 @@ ZT_INLINE void poly1305_update(poly1305_context *ctx,const unsigned char *m,size
} // anonymous namespace } // anonymous namespace
void Poly1305::init(const void *key) noexcept void Poly1305::init(const void* key) noexcept
{ {
static_assert(sizeof(ctx) >= sizeof(poly1305_context),"buffer in class smaller than required structure size"); static_assert(sizeof(ctx) >= sizeof(poly1305_context), "buffer in class smaller than required structure size");
poly1305_init(reinterpret_cast<poly1305_context *>(&ctx),reinterpret_cast<const unsigned char *>(key)); poly1305_init(reinterpret_cast<poly1305_context*>(&ctx), reinterpret_cast<const unsigned char*>(key));
} }
void Poly1305::update(const void *data,unsigned int len) noexcept void Poly1305::update(const void* data, unsigned int len) noexcept
{ {
poly1305_update(reinterpret_cast<poly1305_context *>(&ctx),reinterpret_cast<const unsigned char *>(data),(size_t)len); poly1305_update(
reinterpret_cast<poly1305_context*>(&ctx),
reinterpret_cast<const unsigned char*>(data),
(size_t)len);
} }
void Poly1305::finish(void *auth) noexcept void Poly1305::finish(void* auth) noexcept
{ {
poly1305_finish(reinterpret_cast<poly1305_context *>(&ctx),reinterpret_cast<unsigned char *>(auth)); poly1305_finish(reinterpret_cast<poly1305_context*>(&ctx), reinterpret_cast<unsigned char*>(auth));
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -22,29 +22,31 @@ namespace ZeroTier {
/** /**
* Poly1305 one-time MAC calculator * Poly1305 one-time MAC calculator
*/ */
class Poly1305 class Poly1305 {
{ public:
public:
ZT_INLINE Poly1305() ZT_INLINE Poly1305()
{} {
}
ZT_INLINE Poly1305(const void *key) ZT_INLINE Poly1305(const void* key)
{ this->init(key); } {
this->init(key);
}
void init(const void *key) noexcept; void init(const void* key) noexcept;
void update(const void *data, unsigned int len) noexcept; void update(const void* data, unsigned int len) noexcept;
void finish(void *auth) noexcept; void finish(void* auth) noexcept;
static ZT_INLINE void compute(void *const auth, const void *const data, const unsigned int len, const void *const key) noexcept static ZT_INLINE void
compute(void* const auth, const void* const data, const unsigned int len, const void* const key) noexcept
{ {
Poly1305 p(key); Poly1305 p(key);
p.update(data, len); p.update(data, len);
p.finish(auth); p.finish(auth);
} }
private: private:
struct struct {
{
size_t aligner; size_t aligner;
unsigned char opaque[136]; unsigned char opaque[136];
} ctx; } ctx;

View file

@ -14,14 +14,14 @@
#ifndef ZT_PROTOCOL_HPP #ifndef ZT_PROTOCOL_HPP
#define ZT_PROTOCOL_HPP #define ZT_PROTOCOL_HPP
#include "Constants.hpp"
#include "AES.hpp" #include "AES.hpp"
#include "Salsa20.hpp"
#include "Poly1305.hpp"
#include "LZ4.hpp"
#include "Buf.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Buf.hpp"
#include "Constants.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "LZ4.hpp"
#include "Poly1305.hpp"
#include "Salsa20.hpp"
#include "SymmetricKey.hpp" #include "SymmetricKey.hpp"
/* /*
@ -253,7 +253,9 @@
#define ZT_PROTO_HELLO_NODE_META_EPHEMERAL_ACK "E" #define ZT_PROTO_HELLO_NODE_META_EPHEMERAL_ACK "E"
static_assert(ZT_PROTO_MAX_PACKET_LENGTH < ZT_BUF_MEM_SIZE, "maximum packet length won't fit in Buf"); 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"); 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 ZeroTier {
namespace Protocol { namespace Protocol {
@ -261,8 +263,7 @@ namespace Protocol {
/** /**
* Packet verb (message type) * Packet verb (message type)
*/ */
enum Verb enum Verb {
{
/** /**
* No operation * No operation
* *
@ -685,7 +686,7 @@ enum Verb
#ifdef ZT_DEBUG_SPEW #ifdef ZT_DEBUG_SPEW
static ZT_INLINE const char *verbName(const Verb v) noexcept static ZT_INLINE const char* verbName(const Verb v) noexcept
{ {
switch (v) { switch (v) {
case VERB_NOP: case VERB_NOP:
@ -736,8 +737,7 @@ static ZT_INLINE const char *verbName(const Verb v) noexcept
/** /**
* Error codes used in ERROR packets. * Error codes used in ERROR packets.
*/ */
enum ErrorCode enum ErrorCode {
{
/* Invalid request */ /* Invalid request */
ERROR_INVALID_REQUEST = 0x01, ERROR_INVALID_REQUEST = 0x01,
@ -766,8 +766,7 @@ enum ErrorCode
* This allows the node to know whether this is a normal frame or one generated * This allows the node to know whether this is a normal frame or one generated
* by a special tee or redirect type flow rule. * by a special tee or redirect type flow rule.
*/ */
enum ExtFrameSubtype enum ExtFrameSubtype {
{
EXT_FRAME_SUBTYPE_NORMAL = 0x0, EXT_FRAME_SUBTYPE_NORMAL = 0x0,
EXT_FRAME_SUBTYPE_TEE_OUTBOUND = 0x1, EXT_FRAME_SUBTYPE_TEE_OUTBOUND = 0x1,
EXT_FRAME_SUBTYPE_REDIRECT_OUTBOUND = 0x2, EXT_FRAME_SUBTYPE_REDIRECT_OUTBOUND = 0x2,
@ -780,8 +779,7 @@ enum ExtFrameSubtype
/** /**
* EXT_FRAME flags * EXT_FRAME flags
*/ */
enum ExtFrameFlag enum ExtFrameFlag {
{
/** /**
* A certifiate of membership was included (no longer used but still accepted) * A certifiate of membership was included (no longer used but still accepted)
*/ */
@ -798,8 +796,7 @@ enum ExtFrameFlag
/** /**
* NETWORK_CONFIG (or OK(NETWORK_CONFIG_REQUEST)) flags * NETWORK_CONFIG (or OK(NETWORK_CONFIG_REQUEST)) flags
*/ */
enum NetworkConfigFlag enum NetworkConfigFlag {
{
/** /**
* Indicates that this network config chunk should be fast propagated via rumor mill flooding. * Indicates that this network config chunk should be fast propagated via rumor mill flooding.
*/ */
@ -816,17 +813,22 @@ enum NetworkConfigFlag
* @param in Input key (32 bytes) * @param in Input key (32 bytes)
* @param out Output buffer (32 bytes) * @param out Output buffer (32 bytes)
*/ */
static ZT_INLINE void salsa2012DeriveKey(const uint8_t *const in, uint8_t *const out, const Buf &packet, const unsigned int packetSize) noexcept static ZT_INLINE void
salsa2012DeriveKey(const uint8_t* const in, uint8_t* const out, const Buf& packet, const unsigned int packetSize)
noexcept
{ {
// IV and source/destination addresses. Using the addresses divides the // IV and source/destination addresses. Using the addresses divides the
// key space into two halves-- A->B and B->A (since order will change). // key space into two halves-- A->B and B->A (since order will change).
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
for(int i=0;i<18;++i) for (int i = 0; i < 18; ++i)
out[i] = in[i] ^ packet.unsafeData[i]; out[i] = in[i] ^ packet.unsafeData[i];
#else #else
*reinterpret_cast<uint64_t *>(out) = *reinterpret_cast<const uint64_t *>(in) ^ *reinterpret_cast<const uint64_t *>(packet.unsafeData); *reinterpret_cast<uint64_t*>(out) =
*reinterpret_cast<uint64_t *>(out + 8) = *reinterpret_cast<const uint64_t *>(in + 8) ^ *reinterpret_cast<const uint64_t *>(packet.unsafeData + 8); *reinterpret_cast<const uint64_t*>(in) ^ *reinterpret_cast<const uint64_t*>(packet.unsafeData);
*reinterpret_cast<uint16_t *>(out + 16) = *reinterpret_cast<const uint16_t *>(in + 16) ^ *reinterpret_cast<const uint16_t *>(packet.unsafeData + 16); *reinterpret_cast<uint64_t*>(out + 8) =
*reinterpret_cast<const uint64_t*>(in + 8) ^ *reinterpret_cast<const uint64_t*>(packet.unsafeData + 8);
*reinterpret_cast<uint16_t*>(out + 16) =
*reinterpret_cast<const uint16_t*>(in + 16) ^ *reinterpret_cast<const uint16_t*>(packet.unsafeData + 16);
#endif #endif
// Flags, but with hop count masked off. Hop count is altered by forwarding // Flags, but with hop count masked off. Hop count is altered by forwarding
@ -839,13 +841,13 @@ static ZT_INLINE void salsa2012DeriveKey(const uint8_t *const in, uint8_t *const
// Rest of raw key is used unchanged // Rest of raw key is used unchanged
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
for(int i=21;i<32;++i) for (int i = 21; i < 32; ++i)
out[i] = in[i]; out[i] = in[i];
#else #else
out[21] = in[21]; out[21] = in[21];
out[22] = in[22]; out[22] = in[22];
out[23] = in[23]; out[23] = in[23];
*reinterpret_cast<uint64_t *>(out + 24) = *reinterpret_cast<const uint64_t *>(in + 24); *reinterpret_cast<uint64_t*>(out + 24) = *reinterpret_cast<const uint64_t*>(in + 24);
#endif #endif
} }
@ -859,19 +861,24 @@ static ZT_INLINE void salsa2012DeriveKey(const uint8_t *const in, uint8_t *const
* @param verb Protocol verb * @param verb Protocol verb
* @return Index of packet start * @return Index of packet start
*/ */
static ZT_INLINE int newPacket(uint8_t pkt[28], const uint64_t packetId, const Address destination, const Address source, const Verb verb) noexcept static ZT_INLINE int
newPacket(uint8_t pkt[28], const uint64_t packetId, const Address destination, const Address source, const Verb verb)
noexcept
{ {
Utils::storeMachineEndian< uint64_t >(pkt + ZT_PROTO_PACKET_ID_INDEX, packetId); Utils::storeMachineEndian<uint64_t>(pkt + ZT_PROTO_PACKET_ID_INDEX, packetId);
destination.copyTo(pkt + ZT_PROTO_PACKET_DESTINATION_INDEX); destination.copyTo(pkt + ZT_PROTO_PACKET_DESTINATION_INDEX);
source.copyTo(pkt + ZT_PROTO_PACKET_SOURCE_INDEX); source.copyTo(pkt + ZT_PROTO_PACKET_SOURCE_INDEX);
pkt[ZT_PROTO_PACKET_FLAGS_INDEX] = 0; pkt[ZT_PROTO_PACKET_FLAGS_INDEX] = 0;
Utils::storeMachineEndian< uint64_t >(pkt + ZT_PROTO_PACKET_MAC_INDEX, 0); Utils::storeMachineEndian<uint64_t>(pkt + ZT_PROTO_PACKET_MAC_INDEX, 0);
pkt[ZT_PROTO_PACKET_VERB_INDEX] = (uint8_t)verb; pkt[ZT_PROTO_PACKET_VERB_INDEX] = (uint8_t)verb;
return ZT_PROTO_PACKET_VERB_INDEX + 1; return ZT_PROTO_PACKET_VERB_INDEX + 1;
} }
static ZT_INLINE int newPacket(Buf &pkt, const uint64_t packetId, const Address destination, const Address source, const Verb verb) noexcept static ZT_INLINE int
{ return newPacket(pkt.unsafeData, packetId, destination, source, verb); } newPacket(Buf& pkt, const uint64_t packetId, const Address destination, const Address source, const Verb verb) noexcept
{
return newPacket(pkt.unsafeData, packetId, destination, source, verb);
}
/** /**
* Encrypt and compute packet MAC * Encrypt and compute packet MAC
@ -882,7 +889,8 @@ static ZT_INLINE int newPacket(Buf &pkt, const uint64_t packetId, const Address
* @param cipherSuite Cipher suite to use for AEAD encryption or just MAC * @param cipherSuite Cipher suite to use for AEAD encryption or just MAC
* @return Packet ID of packet (which may change!) * @return Packet ID of packet (which may change!)
*/ */
static ZT_INLINE uint64_t armor(uint8_t *const pkt, const int packetSize, const SymmetricKey &key, const uint8_t cipherSuite) noexcept static ZT_INLINE uint64_t
armor(uint8_t* const pkt, const int packetSize, const SymmetricKey& key, const uint8_t cipherSuite) noexcept
{ {
// TODO // TODO
#if 0 #if 0
@ -940,7 +948,7 @@ static ZT_INLINE uint64_t armor(uint8_t *const pkt, const int packetSize, const
* @param packetSize Total size of packet in bytes (including headers) * @param packetSize Total size of packet in bytes (including headers)
* @return New size of packet after compression or original size of compression wasn't helpful * @return New size of packet after compression or original size of compression wasn't helpful
*/ */
static ZT_INLINE int compress(Buf &pkt, int packetSize) noexcept static ZT_INLINE int compress(Buf& pkt, int packetSize) noexcept
{ {
// TODO // TODO
return packetSize; return packetSize;

View file

@ -7,7 +7,7 @@ Give it wire packets and it gives you Ethernet packets, and vice versa. The core
Code in here follows these guidelines: Code in here follows these guidelines:
- Keep it minimal, especially in terms of code footprint and memory use. - Keep it minimal, especially in terms of code footprint and memory use.
- There should be no OS-dependent code here unless absolutely necessary (e.g. getSecureRandom). - There should be no OS-dependent code here unless absolutely necessary (e.g. getSecureRandom).
- If it's not part of the core virtual Ethernet switch it does not belong here. - If it's not part of the core virtual Ethernet switch it does not belong here.
- Minimize the use of complex C++ features since at some point we might end up "minus-minus'ing" this code if doing so proves necessary to port to tiny embedded systems. - Minimize the use of complex C++ features since at some point we might end up "minus-minus'ing" this code if doing so proves necessary to port to tiny embedded systems.

View file

@ -15,7 +15,7 @@
namespace ZeroTier { namespace ZeroTier {
bool RevocationCredential::sign(const Identity &signer) noexcept bool RevocationCredential::sign(const Identity& signer) noexcept
{ {
uint8_t buf[ZT_REVOCATION_MARSHAL_SIZE_MAX + 32]; uint8_t buf[ZT_REVOCATION_MARSHAL_SIZE_MAX + 32];
if (signer.hasPrivate()) { if (signer.hasPrivate()) {
@ -33,22 +33,22 @@ int RevocationCredential::marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX],
for (int k = 0; k < 8; ++k) for (int k = 0; k < 8; ++k)
data[p++] = 0x7f; data[p++] = 0x7f;
} }
Utils::storeBigEndian< uint32_t >(data + p, 0); Utils::storeBigEndian<uint32_t>(data + p, 0);
Utils::storeBigEndian< uint32_t >(data + p + 4, m_id); Utils::storeBigEndian<uint32_t>(data + p + 4, m_id);
Utils::storeBigEndian< uint64_t >(data + p + 8, m_networkId); Utils::storeBigEndian<uint64_t>(data + p + 8, m_networkId);
Utils::storeBigEndian< uint32_t >(data + p + 16, 0); Utils::storeBigEndian<uint32_t>(data + p + 16, 0);
Utils::storeBigEndian< uint32_t >(data + p + 20, m_credentialId); Utils::storeBigEndian<uint32_t>(data + p + 20, m_credentialId);
Utils::storeBigEndian< uint64_t >(data + p + 24, (uint64_t)m_threshold); Utils::storeBigEndian<uint64_t>(data + p + 24, (uint64_t)m_threshold);
Utils::storeBigEndian< uint64_t >(data + p + 32, m_flags); Utils::storeBigEndian<uint64_t>(data + p + 32, m_flags);
p += 40; p += 40;
m_target.copyTo(data + p); m_target.copyTo(data + p);
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
m_signedBy.copyTo(data + p); m_signedBy.copyTo(data + p);
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
data[p++] = (uint8_t)m_type; data[p++] = (uint8_t)m_type;
if (!forSign) { if (! forSign) {
data[p++] = 1; data[p++] = 1;
Utils::storeBigEndian< uint16_t >(data + p, (uint16_t)m_signatureLength); Utils::storeBigEndian<uint16_t>(data + p, (uint16_t)m_signatureLength);
Utils::copy(data + p, m_signature, m_signatureLength); Utils::copy(data + p, m_signature, m_signatureLength);
p += (int)m_signatureLength; p += (int)m_signatureLength;
} }
@ -61,29 +61,29 @@ int RevocationCredential::marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX],
return p; return p;
} }
int RevocationCredential::unmarshal(const uint8_t *restrict data, const int len) noexcept int RevocationCredential::unmarshal(const uint8_t* restrict data, const int len) noexcept
{ {
if (len < 54) if (len < 54)
return -1; return -1;
// 4 bytes reserved // 4 bytes reserved
m_id = Utils::loadBigEndian< uint32_t >(data + 4); m_id = Utils::loadBigEndian<uint32_t>(data + 4);
m_networkId = Utils::loadBigEndian< uint64_t >(data + 8); m_networkId = Utils::loadBigEndian<uint64_t>(data + 8);
// 4 bytes reserved // 4 bytes reserved
m_credentialId = Utils::loadBigEndian< uint32_t >(data + 20); m_credentialId = Utils::loadBigEndian<uint32_t>(data + 20);
m_threshold = (int64_t)Utils::loadBigEndian< uint64_t >(data + 24); m_threshold = (int64_t)Utils::loadBigEndian<uint64_t>(data + 24);
m_flags = Utils::loadBigEndian< uint64_t >(data + 32); m_flags = Utils::loadBigEndian<uint64_t>(data + 32);
m_target.setTo(data + 40); m_target.setTo(data + 40);
m_signedBy.setTo(data + 45); m_signedBy.setTo(data + 45);
m_type = (ZT_CredentialType)data[50]; m_type = (ZT_CredentialType)data[50];
// 1 byte reserved // 1 byte reserved
m_signatureLength = Utils::loadBigEndian< uint16_t >(data + 52); m_signatureLength = Utils::loadBigEndian<uint16_t>(data + 52);
int p = 54 + (int)m_signatureLength; int p = 54 + (int)m_signatureLength;
if ((m_signatureLength > ZT_SIGNATURE_BUFFER_SIZE) || (p > len)) if ((m_signatureLength > ZT_SIGNATURE_BUFFER_SIZE) || (p > len))
return -1; return -1;
Utils::copy(m_signature, data + 54, m_signatureLength); Utils::copy(m_signature, data + 54, m_signatureLength);
if ((p + 2) > len) if ((p + 2) > len)
return -1; return -1;
p += 2 + Utils::loadBigEndian< uint16_t >(data + p); p += 2 + Utils::loadBigEndian<uint16_t>(data + p);
if (p > len) if (p > len)
return -1; return -1;
return p; return p;

View file

@ -14,12 +14,12 @@
#ifndef ZT_REVOCATION_HPP #ifndef ZT_REVOCATION_HPP
#define ZT_REVOCATION_HPP #define ZT_REVOCATION_HPP
#include "Constants.hpp"
#include "Credential.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "C25519.hpp" #include "C25519.hpp"
#include "Utils.hpp" #include "Constants.hpp"
#include "Credential.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#include "Utils.hpp"
/** /**
* Flag: fast propagation via rumor mill algorithm * Flag: fast propagation via rumor mill algorithm
@ -35,16 +35,19 @@ class Context;
/** /**
* Revocation certificate to instantaneously revoke a COM, capability, or tag * Revocation certificate to instantaneously revoke a COM, capability, or tag
*/ */
class RevocationCredential : public Credential class RevocationCredential : public Credential {
{
friend class Credential; friend class Credential;
public: public:
static constexpr ZT_CredentialType credentialType() noexcept static constexpr ZT_CredentialType credentialType() noexcept
{ return ZT_CREDENTIAL_TYPE_REVOCATION; } {
return ZT_CREDENTIAL_TYPE_REVOCATION;
}
ZT_INLINE RevocationCredential() noexcept ZT_INLINE RevocationCredential() noexcept
{ memoryZero(this); } {
memoryZero(this);
}
/** /**
* @param i ID (arbitrary for revocations, currently random) * @param i ID (arbitrary for revocations, currently random)
@ -55,53 +58,82 @@ public:
* @param tgt Target node whose credential(s) are being revoked * @param tgt Target node whose credential(s) are being revoked
* @param ct Credential type being revoked * @param ct Credential type being revoked
*/ */
ZT_INLINE RevocationCredential(const uint32_t i, const uint64_t nwid, const uint32_t cid, const uint64_t thr, const uint64_t fl, const Address &tgt, const ZT_CredentialType ct) noexcept: // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init) ZT_INLINE RevocationCredential(
m_id(i), const uint32_t i,
m_credentialId(cid), const uint64_t nwid,
m_networkId(nwid), const uint32_t cid,
m_threshold(thr), const uint64_t thr,
m_flags(fl), const uint64_t fl,
m_target(tgt), const Address& tgt,
m_signedBy(), const ZT_CredentialType ct) noexcept
m_type(ct), : // NOLINT(cppcoreguidelines-pro-type-member-init,hicpp-member-init)
m_signatureLength(0) m_id(i)
{} , m_credentialId(cid)
, m_networkId(nwid)
, m_threshold(thr)
, m_flags(fl)
, m_target(tgt)
, m_signedBy()
, m_type(ct)
, m_signatureLength(0)
{
}
ZT_INLINE uint32_t id() const noexcept ZT_INLINE uint32_t id() const noexcept
{ return m_id; } {
return m_id;
}
ZT_INLINE uint32_t credentialId() const noexcept ZT_INLINE uint32_t credentialId() const noexcept
{ return m_credentialId; } {
return m_credentialId;
}
ZT_INLINE uint64_t networkId() const noexcept ZT_INLINE uint64_t networkId() const noexcept
{ return m_networkId; } {
return m_networkId;
}
ZT_INLINE int64_t threshold() const noexcept ZT_INLINE int64_t threshold() const noexcept
{ return m_threshold; } {
return m_threshold;
}
ZT_INLINE const Address &target() const noexcept ZT_INLINE const Address& target() const noexcept
{ return m_target; } {
return m_target;
}
ZT_INLINE const Address &signer() const noexcept ZT_INLINE const Address& signer() const noexcept
{ return m_signedBy; } {
return m_signedBy;
}
ZT_INLINE ZT_CredentialType typeBeingRevoked() const noexcept ZT_INLINE ZT_CredentialType typeBeingRevoked() const noexcept
{ return m_type; } {
return m_type;
}
ZT_INLINE const uint8_t *signature() const noexcept ZT_INLINE const uint8_t* signature() const noexcept
{ return m_signature; } {
return m_signature;
}
ZT_INLINE unsigned int signatureLength() const noexcept ZT_INLINE unsigned int signatureLength() const noexcept
{ return m_signatureLength; } {
return m_signatureLength;
}
ZT_INLINE bool fastPropagate() const noexcept ZT_INLINE bool fastPropagate() const noexcept
{ return ((m_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); } {
return ((m_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0);
}
/** /**
* @param signer Signing identity, must have private key * @param signer Signing identity, must have private key
* @return True if signature was successful * @return True if signature was successful
*/ */
bool sign(const Identity &signer) noexcept; bool sign(const Identity& signer) noexcept;
/** /**
* Verify this revocation's signature * Verify this revocation's signature
@ -109,16 +141,20 @@ public:
* @param RR Runtime environment to provide for peer lookup, etc. * @param RR Runtime environment to provide for peer lookup, etc.
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
*/ */
ZT_INLINE Credential::VerifyResult verify(const Context &ctx, const CallContext &cc) const noexcept ZT_INLINE Credential::VerifyResult verify(const Context& ctx, const CallContext& cc) const noexcept
{ return s_verify(ctx, cc, *this); } {
return s_verify(ctx, cc, *this);
}
static constexpr int marshalSizeMax() noexcept static constexpr int marshalSizeMax() noexcept
{ return ZT_REVOCATION_MARSHAL_SIZE_MAX; } {
return ZT_REVOCATION_MARSHAL_SIZE_MAX;
}
int marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX], bool forSign = false) const noexcept; int marshal(uint8_t data[ZT_REVOCATION_MARSHAL_SIZE_MAX], bool forSign = false) const noexcept;
int unmarshal(const uint8_t *restrict data, int len) noexcept; int unmarshal(const uint8_t* restrict data, int len) noexcept;
private: private:
uint32_t m_id; uint32_t m_id;
uint32_t m_credentialId; uint32_t m_credentialId;
uint64_t m_networkId; uint64_t m_networkId;

View file

@ -1,6 +1,7 @@
// This code is public domain, taken from a PD crypto source file on GitHub. // This code is public domain, taken from a PD crypto source file on GitHub.
#include "SHA512.hpp" #include "SHA512.hpp"
#include "Utils.hpp" #include "Utils.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -10,48 +11,44 @@ namespace ZeroTier {
namespace { namespace {
struct sha512_state { struct sha512_state {
uint64_t length,state[8]; uint64_t length, state[8];
unsigned long curlen; unsigned long curlen;
uint8_t buf[128]; uint8_t buf[128];
}; };
static const uint64_t K[80] = { static const uint64_t K[80] = {
0x428a2f98d728ae22ULL,0x7137449123ef65cdULL,0xb5c0fbcfec4d3b2fULL,0xe9b5dba58189dbbcULL, 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, 0x3956c25bf348b538ULL,
0x3956c25bf348b538ULL,0x59f111f1b605d019ULL,0x923f82a4af194f9bULL,0xab1c5ed5da6d8118ULL, 0x59f111f1b605d019ULL, 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL,
0xd807aa98a3030242ULL,0x12835b0145706fbeULL,0x243185be4ee4b28cULL,0x550c7dc3d5ffb4e2ULL, 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, 0x9bdc06a725c71235ULL,
0x72be5d74f27b896fULL,0x80deb1fe3b1696b1ULL,0x9bdc06a725c71235ULL,0xc19bf174cf692694ULL, 0xc19bf174cf692694ULL, 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL,
0xe49b69c19ef14ad2ULL,0xefbe4786384f25e3ULL,0x0fc19dc68b8cd5b5ULL,0x240ca1cc77ac9c65ULL, 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, 0x983e5152ee66dfabULL,
0x2de92c6f592b0275ULL,0x4a7484aa6ea6e483ULL,0x5cb0a9dcbd41fbd4ULL,0x76f988da831153b5ULL, 0xa831c66d2db43210ULL, 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL,
0x983e5152ee66dfabULL,0xa831c66d2db43210ULL,0xb00327c898fb213fULL,0xbf597fc7beef0ee4ULL, 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, 0x4d2c6dfc5ac42aedULL,
0xc6e00bf33da88fc2ULL,0xd5a79147930aa725ULL,0x06ca6351e003826fULL,0x142929670a0e6e70ULL, 0x53380d139d95b3dfULL, 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL,
0x27b70a8546d22ffcULL,0x2e1b21385c26c926ULL,0x4d2c6dfc5ac42aedULL,0x53380d139d95b3dfULL, 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, 0xd192e819d6ef5218ULL,
0x650a73548baf63deULL,0x766a0abb3c77b2a8ULL,0x81c2c92e47edaee6ULL,0x92722c851482353bULL, 0xd69906245565a910ULL, 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL,
0xa2bfe8a14cf10364ULL,0xa81a664bbc423001ULL,0xc24b8b70d0f89791ULL,0xc76c51a30654be30ULL, 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, 0x5b9cca4f7763e373ULL,
0xd192e819d6ef5218ULL,0xd69906245565a910ULL,0xf40e35855771202aULL,0x106aa07032bbd1b8ULL, 0x682e6ff3d6b2b8a3ULL, 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL,
0x19a4c116b8d2d0c8ULL,0x1e376c085141ab53ULL,0x2748774cdf8eeb99ULL,0x34b0bcb5e19b48a8ULL, 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, 0xca273eceea26619cULL,
0x391c0cb3c5c95a63ULL,0x4ed8aa4ae3418acbULL,0x5b9cca4f7763e373ULL,0x682e6ff3d6b2b8a3ULL, 0xd186b8c721c0c207ULL, 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL,
0x748f82ee5defb2fcULL,0x78a5636f43172f60ULL,0x84c87814a1f0ab72ULL,0x8cc702081a6439ecULL, 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, 0x3c9ebe0a15c9bebcULL,
0x90befffa23631e28ULL,0xa4506cebde82bde9ULL,0xbef9a3f7b2c67915ULL,0xc67178f2e372532bULL, 0x431d67c49c100d4cULL, 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL
0xca273eceea26619cULL,0xd186b8c721c0c207ULL,0xeada7dd6cde0eb1eULL,0xf57d4f7fee6ed178ULL,
0x06f067aa72176fbaULL,0x0a637dc5a2c898a6ULL,0x113f9804bef90daeULL,0x1b710b35131c471bULL,
0x28db77f523047d84ULL,0x32caab7b40c72493ULL,0x3c9ebe0a15c9bebcULL,0x431d67c49c100d4cULL,
0x4cc5d4becb3e42b6ULL,0x597f299cfc657e2aULL,0x5fcb6fab3ad6faecULL,0x6c44198c4a475817ULL
}; };
#define STORE64H(x, y) Utils::storeBigEndian<uint64_t>(y,x) #define STORE64H(x, y) Utils::storeBigEndian<uint64_t>(y, x)
#define LOAD64H(x, y) x = Utils::loadBigEndian<uint64_t>(y) #define LOAD64H(x, y) x = Utils::loadBigEndian<uint64_t>(y)
#define ROL64c(x,y) (((x)<<(y)) | ((x)>>(64-(y)))) #define ROL64c(x, y) (((x) << (y)) | ((x) >> (64 - (y))))
#define ROR64c(x,y) (((x)>>(y)) | ((x)<<(64-(y)))) #define ROR64c(x, y) (((x) >> (y)) | ((x) << (64 - (y))))
#define Ch(x,y,z) (z ^ (x & (y ^ z))) #define Ch(x, y, z) (z ^ (x & (y ^ z)))
#define Maj(x,y,z) (((x | y) & z) | (x & y)) #define Maj(x, y, z) (((x | y) & z) | (x & y))
#define S(x, n) ROR64c(x, n) #define S(x, n) ROR64c(x, n)
#define R(x, n) ((x)>>(n)) #define R(x, n) ((x) >> (n))
#define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39)) #define Sigma0(x) (S(x, 28) ^ S(x, 34) ^ S(x, 39))
#define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41)) #define Sigma1(x) (S(x, 14) ^ S(x, 18) ^ S(x, 41))
#define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7)) #define Gamma0(x) (S(x, 1) ^ S(x, 8) ^ R(x, 7))
#define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6)) #define Gamma1(x) (S(x, 19) ^ S(x, 61) ^ R(x, 6))
static ZT_INLINE void sha512_compress(sha512_state *const md,uint8_t *const buf) static ZT_INLINE void sha512_compress(sha512_state* const md, uint8_t* const buf)
{ {
uint64_t S[8], W[80], t0, t1; uint64_t S[8], W[80], t0, t1;
int i; int i;
@ -59,32 +56,32 @@ static ZT_INLINE void sha512_compress(sha512_state *const md,uint8_t *const buf)
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
S[i] = md->state[i]; S[i] = md->state[i];
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
LOAD64H(W[i], buf + (8*i)); LOAD64H(W[i], buf + (8 * i));
for (i = 16; i < 80; i++) for (i = 16; i < 80; i++)
W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16]; W[i] = Gamma1(W[i - 2]) + W[i - 7] + Gamma0(W[i - 15]) + W[i - 16];
#define RND(a,b,c,d,e,f,g,h,i) \ #define RND(a, b, c, d, e, f, g, h, i) \
t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \ t0 = h + Sigma1(e) + Ch(e, f, g) + K[i] + W[i]; \
t1 = Sigma0(a) + Maj(a, b, c); \ t1 = Sigma0(a) + Maj(a, b, c); \
d += t0; \ d += t0; \
h = t0 + t1; h = t0 + t1;
for (i = 0; i < 80; i += 8) { for (i = 0; i < 80; i += 8) {
RND(S[0],S[1],S[2],S[3],S[4],S[5],S[6],S[7],i+0); RND(S[0], S[1], S[2], S[3], S[4], S[5], S[6], S[7], i + 0);
RND(S[7],S[0],S[1],S[2],S[3],S[4],S[5],S[6],i+1); RND(S[7], S[0], S[1], S[2], S[3], S[4], S[5], S[6], i + 1);
RND(S[6],S[7],S[0],S[1],S[2],S[3],S[4],S[5],i+2); RND(S[6], S[7], S[0], S[1], S[2], S[3], S[4], S[5], i + 2);
RND(S[5],S[6],S[7],S[0],S[1],S[2],S[3],S[4],i+3); RND(S[5], S[6], S[7], S[0], S[1], S[2], S[3], S[4], i + 3);
RND(S[4],S[5],S[6],S[7],S[0],S[1],S[2],S[3],i+4); RND(S[4], S[5], S[6], S[7], S[0], S[1], S[2], S[3], i + 4);
RND(S[3],S[4],S[5],S[6],S[7],S[0],S[1],S[2],i+5); RND(S[3], S[4], S[5], S[6], S[7], S[0], S[1], S[2], i + 5);
RND(S[2],S[3],S[4],S[5],S[6],S[7],S[0],S[1],i+6); RND(S[2], S[3], S[4], S[5], S[6], S[7], S[0], S[1], i + 6);
RND(S[1],S[2],S[3],S[4],S[5],S[6],S[7],S[0],i+7); RND(S[1], S[2], S[3], S[4], S[5], S[6], S[7], S[0], i + 7);
} }
for (i = 0; i < 8; i++) for (i = 0; i < 8; i++)
md->state[i] = md->state[i] + S[i]; md->state[i] = md->state[i] + S[i];
} }
static ZT_INLINE void sha384_init(sha512_state *const md) static ZT_INLINE void sha384_init(sha512_state* const md)
{ {
md->curlen = 0; md->curlen = 0;
md->length = 0; md->length = 0;
@ -98,7 +95,7 @@ static ZT_INLINE void sha384_init(sha512_state *const md)
md->state[7] = 0x47b5481dbefa4fa4ULL; md->state[7] = 0x47b5481dbefa4fa4ULL;
} }
static ZT_INLINE void sha512_init(sha512_state *const md) static ZT_INLINE void sha512_init(sha512_state* const md)
{ {
md->curlen = 0; md->curlen = 0;
md->length = 0; md->length = 0;
@ -112,30 +109,31 @@ static ZT_INLINE void sha512_init(sha512_state *const md)
md->state[7] = 0x5be0cd19137e2179ULL; md->state[7] = 0x5be0cd19137e2179ULL;
} }
static void sha512_process(sha512_state *const md,const uint8_t *in,unsigned long inlen) static void sha512_process(sha512_state* const md, const uint8_t* in, unsigned long inlen)
{ {
while (inlen > 0) { while (inlen > 0) {
if (md->curlen == 0 && inlen >= 128) { if (md->curlen == 0 && inlen >= 128) {
sha512_compress(md,(uint8_t *)in); sha512_compress(md, (uint8_t*)in);
md->length += 128 * 8; md->length += 128 * 8;
in += 128; in += 128;
inlen -= 128; inlen -= 128;
} else { }
unsigned long n = std::min(inlen,(128 - md->curlen)); else {
Utils::copy(md->buf + md->curlen,in,n); unsigned long n = std::min(inlen, (128 - md->curlen));
Utils::copy(md->buf + md->curlen, in, n);
md->curlen += n; md->curlen += n;
in += n; in += n;
inlen -= n; inlen -= n;
if (md->curlen == 128) { if (md->curlen == 128) {
sha512_compress(md,md->buf); sha512_compress(md, md->buf);
md->length += 8*128; md->length += 8 * 128;
md->curlen = 0; md->curlen = 0;
} }
} }
} }
} }
static ZT_INLINE void sha512_done(sha512_state *const md,uint8_t *out) static ZT_INLINE void sha512_done(sha512_state* const md, uint8_t* out)
{ {
int i; int i;
@ -154,58 +152,58 @@ static ZT_INLINE void sha512_done(sha512_state *const md,uint8_t *out)
md->buf[md->curlen++] = (uint8_t)0; md->buf[md->curlen++] = (uint8_t)0;
} }
STORE64H(md->length, md->buf+120); STORE64H(md->length, md->buf + 120);
sha512_compress(md, md->buf); sha512_compress(md, md->buf);
for (i = 0; i < 8; i++) { for (i = 0; i < 8; i++) {
STORE64H(md->state[i], out+(8*i)); STORE64H(md->state[i], out + (8 * i));
} }
} }
} // anonymous namespace } // anonymous namespace
void SHA512(void *digest,const void *data,unsigned int len) void SHA512(void* digest, const void* data, unsigned int len)
{ {
sha512_state state; sha512_state state;
sha512_init(&state); sha512_init(&state);
sha512_process(&state,(uint8_t *)data,(unsigned long)len); sha512_process(&state, (uint8_t*)data, (unsigned long)len);
sha512_done(&state,(uint8_t *)digest); sha512_done(&state, (uint8_t*)digest);
} }
void SHA384(void *digest,const void *data,unsigned int len) void SHA384(void* digest, const void* data, unsigned int len)
{ {
uint8_t tmp[64]; uint8_t tmp[64];
sha512_state state; sha512_state state;
sha384_init(&state); sha384_init(&state);
sha512_process(&state,(uint8_t *)data,(unsigned long)len); sha512_process(&state, (uint8_t*)data, (unsigned long)len);
sha512_done(&state,tmp); sha512_done(&state, tmp);
Utils::copy<48>(digest,tmp); Utils::copy<48>(digest, tmp);
} }
void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1) void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1)
{ {
uint8_t tmp[64]; uint8_t tmp[64];
sha512_state state; sha512_state state;
sha384_init(&state); sha384_init(&state);
sha512_process(&state,(uint8_t *)data0,(unsigned long)len0); sha512_process(&state, (uint8_t*)data0, (unsigned long)len0);
sha512_process(&state,(uint8_t *)data1,(unsigned long)len1); sha512_process(&state, (uint8_t*)data1, (unsigned long)len1);
sha512_done(&state,tmp); sha512_done(&state, tmp);
Utils::copy<48>(digest,tmp); Utils::copy<48>(digest, tmp);
} }
#endif // !ZT_HAVE_NATIVE_SHA512 #endif // !ZT_HAVE_NATIVE_SHA512
void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,const unsigned int msglen,uint8_t mac[48]) void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], const void* msg, const unsigned int msglen, uint8_t mac[48])
{ {
uint64_t kInPadded[16]; // input padded key uint64_t kInPadded[16]; // input padded key
uint64_t outer[22]; // output padded key | H(input padded key | msg) uint64_t outer[22]; // output padded key | H(input padded key | msg)
const uint64_t k0 = Utils::loadMachineEndian< uint64_t >(key); const uint64_t k0 = Utils::loadMachineEndian<uint64_t>(key);
const uint64_t k1 = Utils::loadMachineEndian< uint64_t >(key + 8); const uint64_t k1 = Utils::loadMachineEndian<uint64_t>(key + 8);
const uint64_t k2 = Utils::loadMachineEndian< uint64_t >(key + 16); const uint64_t k2 = Utils::loadMachineEndian<uint64_t>(key + 16);
const uint64_t k3 = Utils::loadMachineEndian< uint64_t >(key + 24); const uint64_t k3 = Utils::loadMachineEndian<uint64_t>(key + 24);
const uint64_t k4 = Utils::loadMachineEndian< uint64_t >(key + 32); const uint64_t k4 = Utils::loadMachineEndian<uint64_t>(key + 32);
const uint64_t k5 = Utils::loadMachineEndian< uint64_t >(key + 40); const uint64_t k5 = Utils::loadMachineEndian<uint64_t>(key + 40);
const uint64_t ipad = 0x3636363636363636ULL; const uint64_t ipad = 0x3636363636363636ULL;
kInPadded[0] = k0 ^ ipad; kInPadded[0] = k0 ^ ipad;
@ -244,15 +242,20 @@ void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,const u
outer[15] = opad; outer[15] = opad;
// H(output padded key | H(input padded key | msg)) // H(output padded key | H(input padded key | msg))
SHA384(reinterpret_cast<uint8_t *>(outer) + 128,kInPadded,128,msg,msglen); SHA384(reinterpret_cast<uint8_t*>(outer) + 128, kInPadded, 128, msg, msglen);
SHA384(mac,outer,176); SHA384(mac, outer, 176);
} }
void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const char label,const char context,const uint32_t iter,uint8_t out[ZT_SYMMETRIC_KEY_SIZE]) void KBKDFHMACSHA384(
const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],
const char label,
const char context,
const uint32_t iter,
uint8_t out[ZT_SYMMETRIC_KEY_SIZE])
{ {
uint8_t kbkdfMsg[13]; uint8_t kbkdfMsg[13];
Utils::storeBigEndian<uint32_t>(kbkdfMsg,(uint32_t)iter); Utils::storeBigEndian<uint32_t>(kbkdfMsg, (uint32_t)iter);
kbkdfMsg[4] = (uint8_t)'Z'; kbkdfMsg[4] = (uint8_t)'Z';
kbkdfMsg[5] = (uint8_t)'T'; // preface our labels with something ZT-specific kbkdfMsg[5] = (uint8_t)'T'; // preface our labels with something ZT-specific
@ -267,8 +270,8 @@ void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const char label,c
kbkdfMsg[11] = 0x01; kbkdfMsg[11] = 0x01;
kbkdfMsg[12] = 0x80; kbkdfMsg[12] = 0x80;
static_assert(ZT_SYMMETRIC_KEY_SIZE == ZT_SHA384_DIGEST_SIZE,"sizeof(out) != ZT_SHA384_DIGEST_SIZE"); static_assert(ZT_SYMMETRIC_KEY_SIZE == ZT_SHA384_DIGEST_SIZE, "sizeof(out) != ZT_SHA384_DIGEST_SIZE");
HMACSHA384(key,&kbkdfMsg,sizeof(kbkdfMsg),out); HMACSHA384(key, &kbkdfMsg, sizeof(kbkdfMsg), out);
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -32,34 +32,34 @@ namespace ZeroTier {
// SHA384 and SHA512 are actually in the standard libraries on MacOS and iOS // SHA384 and SHA512 are actually in the standard libraries on MacOS and iOS
#ifdef __APPLE__ #ifdef __APPLE__
#define ZT_HAVE_NATIVE_SHA512 1 #define ZT_HAVE_NATIVE_SHA512 1
static ZT_INLINE void SHA512(void *digest,const void *data,unsigned int len) static ZT_INLINE void SHA512(void* digest, const void* data, unsigned int len)
{ {
CC_SHA512_CTX ctx; CC_SHA512_CTX ctx;
CC_SHA512_Init(&ctx); CC_SHA512_Init(&ctx);
CC_SHA512_Update(&ctx,data,len); CC_SHA512_Update(&ctx, data, len);
CC_SHA512_Final(reinterpret_cast<unsigned char *>(digest),&ctx); CC_SHA512_Final(reinterpret_cast<unsigned char*>(digest), &ctx);
} }
static ZT_INLINE void SHA384(void *digest,const void *data,unsigned int len) static ZT_INLINE void SHA384(void* digest, const void* data, unsigned int len)
{ {
CC_SHA512_CTX ctx; CC_SHA512_CTX ctx;
CC_SHA384_Init(&ctx); CC_SHA384_Init(&ctx);
CC_SHA384_Update(&ctx,data,len); CC_SHA384_Update(&ctx, data, len);
CC_SHA384_Final(reinterpret_cast<unsigned char *>(digest),&ctx); CC_SHA384_Final(reinterpret_cast<unsigned char*>(digest), &ctx);
} }
static ZT_INLINE void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1) static ZT_INLINE void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1)
{ {
CC_SHA512_CTX ctx; CC_SHA512_CTX ctx;
CC_SHA384_Init(&ctx); CC_SHA384_Init(&ctx);
CC_SHA384_Update(&ctx,data0,len0); CC_SHA384_Update(&ctx, data0, len0);
CC_SHA384_Update(&ctx,data1,len1); CC_SHA384_Update(&ctx, data1, len1);
CC_SHA384_Final(reinterpret_cast<unsigned char *>(digest),&ctx); CC_SHA384_Final(reinterpret_cast<unsigned char*>(digest), &ctx);
} }
#endif #endif
#ifndef ZT_HAVE_NATIVE_SHA512 #ifndef ZT_HAVE_NATIVE_SHA512
void SHA512(void *digest,const void *data,unsigned int len); void SHA512(void* digest, const void* data, unsigned int len);
void SHA384(void *digest,const void *data,unsigned int len); void SHA384(void* digest, const void* data, unsigned int len);
void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,unsigned int len1); void SHA384(void* digest, const void* data0, unsigned int len0, const void* data1, unsigned int len1);
#endif #endif
/** /**
@ -70,7 +70,7 @@ void SHA384(void *digest,const void *data0,unsigned int len0,const void *data1,u
* @param msglen Length of message * @param msglen Length of message
* @param mac Buffer to fill with result * @param mac Buffer to fill with result
*/ */
void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,unsigned int msglen,uint8_t mac[48]); void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE], const void* msg, unsigned int msglen, uint8_t mac[48]);
/** /**
* Compute KBKDF (key-based key derivation function) using HMAC-SHA-384 as a PRF * Compute KBKDF (key-based key derivation function) using HMAC-SHA-384 as a PRF
@ -81,7 +81,12 @@ void HMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],const void *msg,unsigne
* @param iter Key iteration for generation of multiple keys for the same label/context * @param iter Key iteration for generation of multiple keys for the same label/context
* @param out Output to receive derived key * @param out Output to receive derived key
*/ */
void KBKDFHMACSHA384(const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],char label,char context,uint32_t iter,uint8_t out[ZT_SYMMETRIC_KEY_SIZE]); void KBKDFHMACSHA384(
const uint8_t key[ZT_SYMMETRIC_KEY_SIZE],
char label,
char context,
uint32_t iter,
uint8_t out[ZT_SYMMETRIC_KEY_SIZE]);
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -7,9 +7,10 @@
* Since the original was public domain, this is too. * Since the original was public domain, this is too.
*/ */
#include "Constants.hpp"
#include "Salsa20.hpp" #include "Salsa20.hpp"
#include "Constants.hpp"
#define ROTATE(v, c) (((v) << (c)) | ((v) >> (32 - (c)))) #define ROTATE(v, c) (((v) << (c)) | ((v) >> (32 - (c))))
#define XOR(v, w) ((v) ^ (w)) #define XOR(v, w) ((v) ^ (w))
#define PLUS(v, w) ((uint32_t)((v) + (w))) #define PLUS(v, w) ((uint32_t)((v) + (w)))
@ -18,30 +19,43 @@
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
// Slower version that does not use type punning // Slower version that does not use type punning
#define U8TO32_LITTLE(p) ( ((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24) ) #define U8TO32_LITTLE(p) \
static ZT_INLINE void U32TO8_LITTLE(uint8_t *const c,const uint32_t v) { c[0] = (uint8_t)v; c[1] = (uint8_t)(v >> 8); c[2] = (uint8_t)(v >> 16); c[3] = (uint8_t)(v >> 24); } (((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24))
static ZT_INLINE void U32TO8_LITTLE(uint8_t* const c, const uint32_t v)
{
c[0] = (uint8_t)v;
c[1] = (uint8_t)(v >> 8);
c[2] = (uint8_t)(v >> 16);
c[3] = (uint8_t)(v >> 24);
}
#else #else
// Fast version that just does 32-bit load/store // Fast version that just does 32-bit load/store
#define U8TO32_LITTLE(p) (*((const uint32_t *)((const void *)(p)))) #define U8TO32_LITTLE(p) (*((const uint32_t*)((const void*)(p))))
#define U32TO8_LITTLE(c,v) *((uint32_t *)((void *)(c))) = (v) #define U32TO8_LITTLE(c, v) *((uint32_t*)((void*)(c))) = (v)
#endif // ZT_NO_UNALIGNED_ACCESS #endif // ZT_NO_UNALIGNED_ACCESS
#else // __BYTE_ORDER == __BIG_ENDIAN (we don't support anything else... does MIDDLE_ENDIAN even still exist?) #else // __BYTE_ORDER == __BIG_ENDIAN (we don't support anything else... does MIDDLE_ENDIAN even still exist?)
#ifdef __GNUC__ #ifdef __GNUC__
// Use GNUC builtin bswap macros on big-endian machines if available // Use GNUC builtin bswap macros on big-endian machines if available
#define U8TO32_LITTLE(p) __builtin_bswap32(*((const uint32_t *)((const void *)(p)))) #define U8TO32_LITTLE(p) __builtin_bswap32(*((const uint32_t*)((const void*)(p))))
#define U32TO8_LITTLE(c,v) *((uint32_t *)((void *)(c))) = __builtin_bswap32((v)) #define U32TO8_LITTLE(c, v) *((uint32_t*)((void*)(c))) = __builtin_bswap32((v))
#else // no __GNUC__ #else // no __GNUC__
// Otherwise do it the slow, manual way on BE machines // Otherwise do it the slow, manual way on BE machines
#define U8TO32_LITTLE(p) ( ((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24) ) #define U8TO32_LITTLE(p) \
static ZT_INLINE void U32TO8_LITTLE(uint8_t *const c,const uint32_t v) { c[0] = (uint8_t)v; c[1] = (uint8_t)(v >> 8); c[2] = (uint8_t)(v >> 16); c[3] = (uint8_t)(v >> 24); } (((uint32_t)(p)[0]) | ((uint32_t)(p)[1] << 8) | ((uint32_t)(p)[2] << 16) | ((uint32_t)(p)[3] << 24))
static ZT_INLINE void U32TO8_LITTLE(uint8_t* const c, const uint32_t v)
{
c[0] = (uint8_t)v;
c[1] = (uint8_t)(v >> 8);
c[2] = (uint8_t)(v >> 16);
c[3] = (uint8_t)(v >> 24);
}
#endif // __GNUC__ or not #endif // __GNUC__ or not
#endif // __BYTE_ORDER little or big? #endif // __BYTE_ORDER little or big?
#endif // !ZT_SALSA20_SSE #endif // !ZT_SALSA20_SSE
#ifdef ZT_SALSA20_SSE #ifdef ZT_SALSA20_SSE
class _s20sseconsts class _s20sseconsts {
{ public:
public:
_s20sseconsts() noexcept _s20sseconsts() noexcept
{ {
maskLo32 = _mm_shuffle_epi32(_mm_cvtsi32_si128(-1), _MM_SHUFFLE(1, 0, 1, 0)); maskLo32 = _mm_shuffle_epi32(_mm_cvtsi32_si128(-1), _MM_SHUFFLE(1, 0, 1, 0));
@ -54,10 +68,10 @@ static const _s20sseconsts s_S20SSECONSTANTS;
namespace ZeroTier { namespace ZeroTier {
void Salsa20::init(const void *key, const void *iv) noexcept void Salsa20::init(const void* key, const void* iv) noexcept
{ {
#ifdef ZT_SALSA20_SSE #ifdef ZT_SALSA20_SSE
const uint32_t *const k = (const uint32_t *)key; const uint32_t* const k = (const uint32_t*)key;
_state.i[0] = 0x61707865; _state.i[0] = 0x61707865;
_state.i[1] = 0x3320646e; _state.i[1] = 0x3320646e;
_state.i[2] = 0x79622d32; _state.i[2] = 0x79622d32;
@ -69,22 +83,22 @@ void Salsa20::init(const void *key, const void *iv) noexcept
_state.i[8] = 0; _state.i[8] = 0;
_state.i[9] = k[6]; _state.i[9] = k[6];
_state.i[10] = k[1]; _state.i[10] = k[1];
_state.i[11] = ((const uint32_t *)iv)[1]; _state.i[11] = ((const uint32_t*)iv)[1];
_state.i[12] = k[5]; _state.i[12] = k[5];
_state.i[13] = k[0]; _state.i[13] = k[0];
_state.i[14] = ((const uint32_t *)iv)[0]; _state.i[14] = ((const uint32_t*)iv)[0];
_state.i[15] = k[4]; _state.i[15] = k[4];
#else #else
const char *const constants = "expand 32-byte k"; const char* const constants = "expand 32-byte k";
const uint8_t *const k = (const uint8_t *)key; const uint8_t* const k = (const uint8_t*)key;
_state.i[0] = U8TO32_LITTLE(constants + 0); _state.i[0] = U8TO32_LITTLE(constants + 0);
_state.i[1] = U8TO32_LITTLE(k + 0); _state.i[1] = U8TO32_LITTLE(k + 0);
_state.i[2] = U8TO32_LITTLE(k + 4); _state.i[2] = U8TO32_LITTLE(k + 4);
_state.i[3] = U8TO32_LITTLE(k + 8); _state.i[3] = U8TO32_LITTLE(k + 8);
_state.i[4] = U8TO32_LITTLE(k + 12); _state.i[4] = U8TO32_LITTLE(k + 12);
_state.i[5] = U8TO32_LITTLE(constants + 4); _state.i[5] = U8TO32_LITTLE(constants + 4);
_state.i[6] = U8TO32_LITTLE(((const uint8_t *)iv) + 0); _state.i[6] = U8TO32_LITTLE(((const uint8_t*)iv) + 0);
_state.i[7] = U8TO32_LITTLE(((const uint8_t *)iv) + 4); _state.i[7] = U8TO32_LITTLE(((const uint8_t*)iv) + 4);
_state.i[8] = 0; _state.i[8] = 0;
_state.i[9] = 0; _state.i[9] = 0;
_state.i[10] = U8TO32_LITTLE(constants + 8); _state.i[10] = U8TO32_LITTLE(constants + 8);
@ -96,22 +110,21 @@ void Salsa20::init(const void *key, const void *iv) noexcept
#endif #endif
} }
union p_SalsaState union p_SalsaState {
{
#ifdef ZT_SALSA20_SSE #ifdef ZT_SALSA20_SSE
__m128i v[4]; __m128i v[4];
#endif // ZT_SALSA20_SSE #endif // ZT_SALSA20_SSE
uint32_t i[16]; uint32_t i[16];
}; };
template< unsigned int R > template <unsigned int R>
static ZT_INLINE void p_salsaCrypt(p_SalsaState *const state, const uint8_t *m, uint8_t *c, unsigned int bytes) noexcept static ZT_INLINE void p_salsaCrypt(p_SalsaState* const state, const uint8_t* m, uint8_t* c, unsigned int bytes) noexcept
{ {
if (unlikely(bytes == 0)) if (unlikely(bytes == 0))
return; return;
uint8_t tmp[64]; uint8_t tmp[64];
uint8_t *ctarget = c; uint8_t* ctarget = c;
#ifdef ZT_SALSA20_SSE #ifdef ZT_SALSA20_SSE
__m128i X0 = state->v[0]; __m128i X0 = state->v[0];
@ -195,10 +208,18 @@ static ZT_INLINE void p_salsaCrypt(p_SalsaState *const state, const uint8_t *m,
k02 = _mm_shuffle_epi32(k02, _MM_SHUFFLE(0, 1, 2, 3)); k02 = _mm_shuffle_epi32(k02, _MM_SHUFFLE(0, 1, 2, 3));
k13 = _mm_shuffle_epi32(k13, _MM_SHUFFLE(0, 1, 2, 3)); k13 = _mm_shuffle_epi32(k13, _MM_SHUFFLE(0, 1, 2, 3));
_mm_storeu_si128(reinterpret_cast<__m128i *>(c), _mm_xor_si128(_mm_unpackhi_epi64(k02, k20), _mm_loadu_si128(reinterpret_cast<const __m128i *>(m)))); _mm_storeu_si128(
_mm_storeu_si128(reinterpret_cast<__m128i *>(c) + 1, _mm_xor_si128(_mm_unpackhi_epi64(k13, k31), _mm_loadu_si128(reinterpret_cast<const __m128i *>(m) + 1))); reinterpret_cast<__m128i*>(c),
_mm_storeu_si128(reinterpret_cast<__m128i *>(c) + 2, _mm_xor_si128(_mm_unpacklo_epi64(k20, k02), _mm_loadu_si128(reinterpret_cast<const __m128i *>(m) + 2))); _mm_xor_si128(_mm_unpackhi_epi64(k02, k20), _mm_loadu_si128(reinterpret_cast<const __m128i*>(m))));
_mm_storeu_si128(reinterpret_cast<__m128i *>(c) + 3, _mm_xor_si128(_mm_unpacklo_epi64(k31, k13), _mm_loadu_si128(reinterpret_cast<const __m128i *>(m) + 3))); _mm_storeu_si128(
reinterpret_cast<__m128i*>(c) + 1,
_mm_xor_si128(_mm_unpackhi_epi64(k13, k31), _mm_loadu_si128(reinterpret_cast<const __m128i*>(m) + 1)));
_mm_storeu_si128(
reinterpret_cast<__m128i*>(c) + 2,
_mm_xor_si128(_mm_unpacklo_epi64(k20, k02), _mm_loadu_si128(reinterpret_cast<const __m128i*>(m) + 2)));
_mm_storeu_si128(
reinterpret_cast<__m128i*>(c) + 3,
_mm_xor_si128(_mm_unpacklo_epi64(k31, k13), _mm_loadu_si128(reinterpret_cast<const __m128i*>(m) + 3)));
X0 = X0s; X0 = X0s;
X1 = X1s; X1 = X1s;
@ -224,74 +245,74 @@ static ZT_INLINE void p_salsaCrypt(p_SalsaState *const state, const uint8_t *m,
x14 = j14; x14 = j14;
x15 = j15; x15 = j15;
for(unsigned int rr=0;rr<(R/2);++rr) { for (unsigned int rr = 0; rr < (R / 2); ++rr) {
x4 = XOR( x4,ROTATE(PLUS( x0,x12), 7)); x4 = XOR(x4, ROTATE(PLUS(x0, x12), 7));
x8 = XOR( x8,ROTATE(PLUS( x4, x0), 9)); x8 = XOR(x8, ROTATE(PLUS(x4, x0), 9));
x12 = XOR(x12,ROTATE(PLUS( x8, x4),13)); x12 = XOR(x12, ROTATE(PLUS(x8, x4), 13));
x0 = XOR( x0,ROTATE(PLUS(x12, x8),18)); x0 = XOR(x0, ROTATE(PLUS(x12, x8), 18));
x9 = XOR( x9,ROTATE(PLUS( x5, x1), 7)); x9 = XOR(x9, ROTATE(PLUS(x5, x1), 7));
x13 = XOR(x13,ROTATE(PLUS( x9, x5), 9)); x13 = XOR(x13, ROTATE(PLUS(x9, x5), 9));
x1 = XOR( x1,ROTATE(PLUS(x13, x9),13)); x1 = XOR(x1, ROTATE(PLUS(x13, x9), 13));
x5 = XOR( x5,ROTATE(PLUS( x1,x13),18)); x5 = XOR(x5, ROTATE(PLUS(x1, x13), 18));
x14 = XOR(x14,ROTATE(PLUS(x10, x6), 7)); x14 = XOR(x14, ROTATE(PLUS(x10, x6), 7));
x2 = XOR( x2,ROTATE(PLUS(x14,x10), 9)); x2 = XOR(x2, ROTATE(PLUS(x14, x10), 9));
x6 = XOR( x6,ROTATE(PLUS( x2,x14),13)); x6 = XOR(x6, ROTATE(PLUS(x2, x14), 13));
x10 = XOR(x10,ROTATE(PLUS( x6, x2),18)); x10 = XOR(x10, ROTATE(PLUS(x6, x2), 18));
x3 = XOR( x3,ROTATE(PLUS(x15,x11), 7)); x3 = XOR(x3, ROTATE(PLUS(x15, x11), 7));
x7 = XOR( x7,ROTATE(PLUS( x3,x15), 9)); x7 = XOR(x7, ROTATE(PLUS(x3, x15), 9));
x11 = XOR(x11,ROTATE(PLUS( x7, x3),13)); x11 = XOR(x11, ROTATE(PLUS(x7, x3), 13));
x15 = XOR(x15,ROTATE(PLUS(x11, x7),18)); x15 = XOR(x15, ROTATE(PLUS(x11, x7), 18));
x1 = XOR( x1,ROTATE(PLUS( x0, x3), 7)); x1 = XOR(x1, ROTATE(PLUS(x0, x3), 7));
x2 = XOR( x2,ROTATE(PLUS( x1, x0), 9)); x2 = XOR(x2, ROTATE(PLUS(x1, x0), 9));
x3 = XOR( x3,ROTATE(PLUS( x2, x1),13)); x3 = XOR(x3, ROTATE(PLUS(x2, x1), 13));
x0 = XOR( x0,ROTATE(PLUS( x3, x2),18)); x0 = XOR(x0, ROTATE(PLUS(x3, x2), 18));
x6 = XOR( x6,ROTATE(PLUS( x5, x4), 7)); x6 = XOR(x6, ROTATE(PLUS(x5, x4), 7));
x7 = XOR( x7,ROTATE(PLUS( x6, x5), 9)); x7 = XOR(x7, ROTATE(PLUS(x6, x5), 9));
x4 = XOR( x4,ROTATE(PLUS( x7, x6),13)); x4 = XOR(x4, ROTATE(PLUS(x7, x6), 13));
x5 = XOR( x5,ROTATE(PLUS( x4, x7),18)); x5 = XOR(x5, ROTATE(PLUS(x4, x7), 18));
x11 = XOR(x11,ROTATE(PLUS(x10, x9), 7)); x11 = XOR(x11, ROTATE(PLUS(x10, x9), 7));
x8 = XOR( x8,ROTATE(PLUS(x11,x10), 9)); x8 = XOR(x8, ROTATE(PLUS(x11, x10), 9));
x9 = XOR( x9,ROTATE(PLUS( x8,x11),13)); x9 = XOR(x9, ROTATE(PLUS(x8, x11), 13));
x10 = XOR(x10,ROTATE(PLUS( x9, x8),18)); x10 = XOR(x10, ROTATE(PLUS(x9, x8), 18));
x12 = XOR(x12,ROTATE(PLUS(x15,x14), 7)); x12 = XOR(x12, ROTATE(PLUS(x15, x14), 7));
x13 = XOR(x13,ROTATE(PLUS(x12,x15), 9)); x13 = XOR(x13, ROTATE(PLUS(x12, x15), 9));
x14 = XOR(x14,ROTATE(PLUS(x13,x12),13)); x14 = XOR(x14, ROTATE(PLUS(x13, x12), 13));
x15 = XOR(x15,ROTATE(PLUS(x14,x13),18)); x15 = XOR(x15, ROTATE(PLUS(x14, x13), 18));
} }
x0 = PLUS(x0,j0); x0 = PLUS(x0, j0);
x1 = PLUS(x1,j1); x1 = PLUS(x1, j1);
x2 = PLUS(x2,j2); x2 = PLUS(x2, j2);
x3 = PLUS(x3,j3); x3 = PLUS(x3, j3);
x4 = PLUS(x4,j4); x4 = PLUS(x4, j4);
x5 = PLUS(x5,j5); x5 = PLUS(x5, j5);
x6 = PLUS(x6,j6); x6 = PLUS(x6, j6);
x7 = PLUS(x7,j7); x7 = PLUS(x7, j7);
x8 = PLUS(x8,j8); x8 = PLUS(x8, j8);
x9 = PLUS(x9,j9); x9 = PLUS(x9, j9);
x10 = PLUS(x10,j10); x10 = PLUS(x10, j10);
x11 = PLUS(x11,j11); x11 = PLUS(x11, j11);
x12 = PLUS(x12,j12); x12 = PLUS(x12, j12);
x13 = PLUS(x13,j13); x13 = PLUS(x13, j13);
x14 = PLUS(x14,j14); x14 = PLUS(x14, j14);
x15 = PLUS(x15,j15); x15 = PLUS(x15, j15);
U32TO8_LITTLE(c + 0,XOR(x0,U8TO32_LITTLE(m + 0))); U32TO8_LITTLE(c + 0, XOR(x0, U8TO32_LITTLE(m + 0)));
U32TO8_LITTLE(c + 4,XOR(x1,U8TO32_LITTLE(m + 4))); U32TO8_LITTLE(c + 4, XOR(x1, U8TO32_LITTLE(m + 4)));
U32TO8_LITTLE(c + 8,XOR(x2,U8TO32_LITTLE(m + 8))); U32TO8_LITTLE(c + 8, XOR(x2, U8TO32_LITTLE(m + 8)));
U32TO8_LITTLE(c + 12,XOR(x3,U8TO32_LITTLE(m + 12))); U32TO8_LITTLE(c + 12, XOR(x3, U8TO32_LITTLE(m + 12)));
U32TO8_LITTLE(c + 16,XOR(x4,U8TO32_LITTLE(m + 16))); U32TO8_LITTLE(c + 16, XOR(x4, U8TO32_LITTLE(m + 16)));
U32TO8_LITTLE(c + 20,XOR(x5,U8TO32_LITTLE(m + 20))); U32TO8_LITTLE(c + 20, XOR(x5, U8TO32_LITTLE(m + 20)));
U32TO8_LITTLE(c + 24,XOR(x6,U8TO32_LITTLE(m + 24))); U32TO8_LITTLE(c + 24, XOR(x6, U8TO32_LITTLE(m + 24)));
U32TO8_LITTLE(c + 28,XOR(x7,U8TO32_LITTLE(m + 28))); U32TO8_LITTLE(c + 28, XOR(x7, U8TO32_LITTLE(m + 28)));
U32TO8_LITTLE(c + 32,XOR(x8,U8TO32_LITTLE(m + 32))); U32TO8_LITTLE(c + 32, XOR(x8, U8TO32_LITTLE(m + 32)));
U32TO8_LITTLE(c + 36,XOR(x9,U8TO32_LITTLE(m + 36))); U32TO8_LITTLE(c + 36, XOR(x9, U8TO32_LITTLE(m + 36)));
U32TO8_LITTLE(c + 40,XOR(x10,U8TO32_LITTLE(m + 40))); U32TO8_LITTLE(c + 40, XOR(x10, U8TO32_LITTLE(m + 40)));
U32TO8_LITTLE(c + 44,XOR(x11,U8TO32_LITTLE(m + 44))); U32TO8_LITTLE(c + 44, XOR(x11, U8TO32_LITTLE(m + 44)));
U32TO8_LITTLE(c + 48,XOR(x12,U8TO32_LITTLE(m + 48))); U32TO8_LITTLE(c + 48, XOR(x12, U8TO32_LITTLE(m + 48)));
U32TO8_LITTLE(c + 52,XOR(x13,U8TO32_LITTLE(m + 52))); U32TO8_LITTLE(c + 52, XOR(x13, U8TO32_LITTLE(m + 52)));
U32TO8_LITTLE(c + 56,XOR(x14,U8TO32_LITTLE(m + 56))); U32TO8_LITTLE(c + 56, XOR(x14, U8TO32_LITTLE(m + 56)));
U32TO8_LITTLE(c + 60,XOR(x15,U8TO32_LITTLE(m + 60))); U32TO8_LITTLE(c + 60, XOR(x15, U8TO32_LITTLE(m + 60)));
++j8; ++j8;
@ -301,7 +322,8 @@ static ZT_INLINE void p_salsaCrypt(p_SalsaState *const state, const uint8_t *m,
bytes -= 64; bytes -= 64;
c += 64; c += 64;
m += 64; m += 64;
} else { }
else {
if (bytes < 64) { if (bytes < 64) {
for (unsigned int i = 0; i < bytes; ++i) for (unsigned int i = 0; i < bytes; ++i)
ctarget[i] = c[i]; ctarget[i] = c[i];
@ -316,14 +338,22 @@ static ZT_INLINE void p_salsaCrypt(p_SalsaState *const state, const uint8_t *m,
} }
} }
void Salsa20::crypt12(const void *in, void *out, unsigned int bytes) noexcept void Salsa20::crypt12(const void* in, void* out, unsigned int bytes) noexcept
{ {
p_salsaCrypt< 12 >(reinterpret_cast<p_SalsaState *>(&_state), reinterpret_cast<const uint8_t *>(in), reinterpret_cast<uint8_t *>(out), bytes); p_salsaCrypt<12>(
reinterpret_cast<p_SalsaState*>(&_state),
reinterpret_cast<const uint8_t*>(in),
reinterpret_cast<uint8_t*>(out),
bytes);
} }
void Salsa20::crypt20(const void *in, void *out, unsigned int bytes) noexcept void Salsa20::crypt20(const void* in, void* out, unsigned int bytes) noexcept
{ {
p_salsaCrypt< 20 >(reinterpret_cast<p_SalsaState *>(&_state), reinterpret_cast<const uint8_t *>(in), reinterpret_cast<uint8_t *>(out), bytes); p_salsaCrypt<20>(
reinterpret_cast<p_SalsaState*>(&_state),
reinterpret_cast<const uint8_t*>(in),
reinterpret_cast<uint8_t*>(out),
bytes);
} }
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -15,8 +15,8 @@
#define ZT_SALSA20_HPP #define ZT_SALSA20_HPP
#include "Constants.hpp" #include "Constants.hpp"
#include "Utils.hpp"
#include "TriviallyCopyable.hpp" #include "TriviallyCopyable.hpp"
#include "Utils.hpp"
#ifdef ZT_ARCH_X64 #ifdef ZT_ARCH_X64
#define ZT_SALSA20_SSE 1 #define ZT_SALSA20_SSE 1
@ -35,30 +35,39 @@ namespace ZeroTier {
* a minor optimization done here because ZeroTier messages are * a minor optimization done here because ZeroTier messages are
* nowhere near this large. * nowhere near this large.
*/ */
class Salsa20 : public TriviallyCopyable class Salsa20 : public TriviallyCopyable {
{ public:
public:
#ifdef ZT_SALSA20_SSE #ifdef ZT_SALSA20_SSE
static constexpr bool accelerated() noexcept static constexpr bool accelerated() noexcept
{ return true; } {
return true;
}
#else #else
static constexpr bool accelerated() noexcept { return false; } static constexpr bool accelerated() noexcept
{
return false;
}
#endif #endif
ZT_INLINE Salsa20() noexcept ZT_INLINE Salsa20() noexcept
{} {
}
ZT_INLINE ~Salsa20() noexcept ZT_INLINE ~Salsa20() noexcept
{ Utils::burn(&_state, sizeof(_state)); } {
Utils::burn(&_state, sizeof(_state));
}
/** /**
* @param key 256-bit (32 byte) key * @param key 256-bit (32 byte) key
* @param iv 64-bit initialization vector * @param iv 64-bit initialization vector
*/ */
ZT_INLINE Salsa20(const void *key, const void *iv) noexcept ZT_INLINE Salsa20(const void* key, const void* iv) noexcept
{ init(key, iv); } {
init(key, iv);
}
/** /**
* Initialize cipher * Initialize cipher
@ -66,7 +75,7 @@ public:
* @param key Key bits * @param key Key bits
* @param iv 64-bit initialization vector * @param iv 64-bit initialization vector
*/ */
void init(const void *key, const void *iv) noexcept; void init(const void* key, const void* iv) noexcept;
/** /**
* Encrypt/decrypt data using Salsa20/12 * Encrypt/decrypt data using Salsa20/12
@ -75,7 +84,7 @@ public:
* @param out Output buffer * @param out Output buffer
* @param bytes Length of data * @param bytes Length of data
*/ */
void crypt12(const void *in, void *out, unsigned int bytes) noexcept; void crypt12(const void* in, void* out, unsigned int bytes) noexcept;
/** /**
* Encrypt/decrypt data using Salsa20/20 * Encrypt/decrypt data using Salsa20/20
@ -84,11 +93,10 @@ public:
* @param out Output buffer * @param out Output buffer
* @param bytes Length of data * @param bytes Length of data
*/ */
void crypt20(const void *in, void *out, unsigned int bytes) noexcept; void crypt20(const void* in, void* out, unsigned int bytes) noexcept;
private: private:
union union {
{
#ifdef ZT_SALSA20_SSE #ifdef ZT_SALSA20_SSE
__m128i v[4]; __m128i v[4];
#endif // ZT_SALSA20_SSE #endif // ZT_SALSA20_SSE

View file

@ -24,66 +24,88 @@ namespace ZeroTier {
* *
* This is used in the core to avoid requiring C++11 and because auto_ptr is weird. * This is used in the core to avoid requiring C++11 and because auto_ptr is weird.
*/ */
template< typename T > template <typename T> class ScopedPtr : public TriviallyCopyable {
class ScopedPtr : public TriviallyCopyable public:
{ explicit ZT_INLINE ScopedPtr(T* const p) noexcept : m_ptr(p)
public: {
explicit ZT_INLINE ScopedPtr(T *const p) noexcept: m_ptr(p) }
{}
ZT_INLINE ~ScopedPtr() ZT_INLINE ~ScopedPtr()
{ delete m_ptr; }
ZT_INLINE T *operator->() const noexcept
{ return m_ptr; }
ZT_INLINE T &operator*() const noexcept
{ return *m_ptr; }
ZT_INLINE T *ptr() const noexcept
{ return m_ptr; }
ZT_INLINE void swap(const ScopedPtr &p) noexcept
{ {
T *const tmp = m_ptr; delete m_ptr;
}
ZT_INLINE T* operator->() const noexcept
{
return m_ptr;
}
ZT_INLINE T& operator*() const noexcept
{
return *m_ptr;
}
ZT_INLINE T* ptr() const noexcept
{
return m_ptr;
}
ZT_INLINE void swap(const ScopedPtr& p) noexcept
{
T* const tmp = m_ptr;
m_ptr = p.m_ptr; m_ptr = p.m_ptr;
p.m_ptr = tmp; p.m_ptr = tmp;
} }
explicit ZT_INLINE operator bool() const noexcept explicit ZT_INLINE operator bool() const noexcept
{ return (m_ptr != (T *)0); } {
return (m_ptr != (T*)0);
}
ZT_INLINE bool operator==(const ScopedPtr &p) const noexcept ZT_INLINE bool operator==(const ScopedPtr& p) const noexcept
{ return (m_ptr == p.m_ptr); } {
return (m_ptr == p.m_ptr);
}
ZT_INLINE bool operator!=(const ScopedPtr &p) const noexcept ZT_INLINE bool operator!=(const ScopedPtr& p) const noexcept
{ return (m_ptr != p.m_ptr); } {
return (m_ptr != p.m_ptr);
}
ZT_INLINE bool operator==(T *const p) const noexcept ZT_INLINE bool operator==(T* const p) const noexcept
{ return (m_ptr == p); } {
return (m_ptr == p);
}
ZT_INLINE bool operator!=(T *const p) const noexcept ZT_INLINE bool operator!=(T* const p) const noexcept
{ return (m_ptr != p); } {
return (m_ptr != p);
}
private: private:
ZT_INLINE ScopedPtr() noexcept ZT_INLINE ScopedPtr() noexcept
{} {
}
ZT_INLINE ScopedPtr(const ScopedPtr &p) noexcept: m_ptr(nullptr) ZT_INLINE ScopedPtr(const ScopedPtr& p) noexcept : m_ptr(nullptr)
{} {
}
ZT_INLINE ScopedPtr &operator=(const ScopedPtr &p) noexcept ZT_INLINE ScopedPtr& operator=(const ScopedPtr& p) noexcept
{ return *this; } {
return *this;
}
T *const m_ptr; T* const m_ptr;
}; };
} // namespace ZeroTier } // namespace ZeroTier
namespace std { namespace std {
template< typename T > template <typename T> ZT_INLINE void swap(ZeroTier::ScopedPtr<T>& a, ZeroTier::ScopedPtr<T>& b) noexcept
ZT_INLINE void swap(ZeroTier::ScopedPtr< T > &a, ZeroTier::ScopedPtr< T > &b) noexcept {
{ a.swap(b); } a.swap(b);
}
} // namespace std } // namespace std
#endif #endif

View file

@ -11,34 +11,44 @@
*/ */
/****/ /****/
#include "Constants.hpp"
#include "SelfAwareness.hpp" #include "SelfAwareness.hpp"
#include "Context.hpp"
#include "Topology.hpp" #include "Constants.hpp"
#include "Peer.hpp"
#include "Trace.hpp"
#include "Containers.hpp" #include "Containers.hpp"
#include "Context.hpp"
#include "Peer.hpp"
#include "Topology.hpp"
#include "Trace.hpp"
// Entry timeout -- make it fairly long since this is just to prevent stale buildup // Entry timeout -- make it fairly long since this is just to prevent stale buildup
#define ZT_SELFAWARENESS_ENTRY_TIMEOUT 300000 #define ZT_SELFAWARENESS_ENTRY_TIMEOUT 300000
namespace ZeroTier { namespace ZeroTier {
SelfAwareness::SelfAwareness(const Context &ctx) : SelfAwareness::SelfAwareness(const Context& ctx) : m_ctx(ctx)
m_ctx(ctx) {
{} }
void SelfAwareness::iam(const CallContext &cc, const Identity &reporter, const int64_t receivedOnLocalSocket, const InetAddress &reporterPhysicalAddress, const InetAddress &myPhysicalAddress, bool trusted) void SelfAwareness::iam(
const CallContext& cc,
const Identity& reporter,
const int64_t receivedOnLocalSocket,
const InetAddress& reporterPhysicalAddress,
const InetAddress& myPhysicalAddress,
bool trusted)
{ {
const InetAddress::IpScope scope = myPhysicalAddress.ipScope(); const InetAddress::IpScope scope = myPhysicalAddress.ipScope();
if ((scope != reporterPhysicalAddress.ipScope()) || (scope == ZT_IP_SCOPE_NONE) || (scope == ZT_IP_SCOPE_LOOPBACK) || (scope == ZT_IP_SCOPE_MULTICAST)) if ((scope != reporterPhysicalAddress.ipScope()) || (scope == ZT_IP_SCOPE_NONE) || (scope == ZT_IP_SCOPE_LOOPBACK)
|| (scope == ZT_IP_SCOPE_MULTICAST))
return; return;
Mutex::Lock l(m_phy_l); Mutex::Lock l(m_phy_l);
p_PhySurfaceEntry &entry = m_phy[p_PhySurfaceKey(reporter.address(), receivedOnLocalSocket, reporterPhysicalAddress, scope)]; p_PhySurfaceEntry& entry =
m_phy[p_PhySurfaceKey(reporter.address(), receivedOnLocalSocket, reporterPhysicalAddress, scope)];
if ((trusted) && ((cc.ticks - entry.timestampTicks) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) && (!entry.mySurface.ipsEqual(myPhysicalAddress))) { if ((trusted) && ((cc.ticks - entry.timestampTicks) < ZT_SELFAWARENESS_ENTRY_TIMEOUT)
&& (! entry.mySurface.ipsEqual(myPhysicalAddress))) {
// Changes to external surface reported by trusted peers causes path reset in this scope // Changes to external surface reported by trusted peers causes path reset in this scope
entry.mySurface = myPhysicalAddress; entry.mySurface = myPhysicalAddress;
entry.timestampTicks = cc.ticks; entry.timestampTicks = cc.ticks;
@ -47,20 +57,29 @@ void SelfAwareness::iam(const CallContext &cc, const Identity &reporter, const i
// Erase all entries in this scope that were not reported from this remote address to prevent 'thrashing' // Erase all entries in this scope that were not reported from this remote address to prevent 'thrashing'
// due to multiple reports of endpoint change. // due to multiple reports of endpoint change.
// Don't use 'entry' after this since hash table gets modified. // 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();) { for (Map<p_PhySurfaceKey, p_PhySurfaceEntry>::iterator i(m_phy.begin()); i != m_phy.end();) {
if ((i->first.scope == scope) && (i->first.reporterPhysicalAddress != reporterPhysicalAddress)) if ((i->first.scope == scope) && (i->first.reporterPhysicalAddress != reporterPhysicalAddress))
m_phy.erase(i++); m_phy.erase(i++);
else ++i; else
++i;
} }
// Reset all paths within this scope and address family // Reset all paths within this scope and address family
Vector< SharedPtr< Peer > > peers, rootPeers; Vector<SharedPtr<Peer> > peers, rootPeers;
m_ctx.topology->allPeers(peers, rootPeers); m_ctx.topology->allPeers(peers, rootPeers);
for(Vector< SharedPtr< Peer > >::const_iterator p(peers.begin());p!=peers.end();++p) for (Vector<SharedPtr<Peer> >::const_iterator p(peers.begin()); p != peers.end(); ++p)
(*p)->resetWithinScope(m_ctx, cc, (InetAddress::IpScope)scope, myPhysicalAddress.as.sa.sa_family); (*p)->resetWithinScope(m_ctx, cc, (InetAddress::IpScope)scope, myPhysicalAddress.as.sa.sa_family);
m_ctx.t->resettingPathsInScope(cc, 0x9afff100, reporter, reporterPhysicalAddress, entry.mySurface, myPhysicalAddress, scope); m_ctx.t->resettingPathsInScope(
} else { cc,
0x9afff100,
reporter,
reporterPhysicalAddress,
entry.mySurface,
myPhysicalAddress,
scope);
}
else {
// Otherwise just update DB to use to determine external surface info // Otherwise just update DB to use to determine external surface info
entry.mySurface = myPhysicalAddress; entry.mySurface = myPhysicalAddress;
entry.timestampTicks = cc.ticks; entry.timestampTicks = cc.ticks;
@ -68,33 +87,34 @@ void SelfAwareness::iam(const CallContext &cc, const Identity &reporter, const i
} }
} }
void SelfAwareness::clean(const CallContext &cc) void SelfAwareness::clean(const CallContext& cc)
{ {
Mutex::Lock l(m_phy_l); Mutex::Lock l(m_phy_l);
for (Map< p_PhySurfaceKey, p_PhySurfaceEntry >::iterator i(m_phy.begin()); i != m_phy.end();) { for (Map<p_PhySurfaceKey, p_PhySurfaceEntry>::iterator i(m_phy.begin()); i != m_phy.end();) {
if ((cc.ticks - i->second.timestampTicks) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT) if ((cc.ticks - i->second.timestampTicks) >= ZT_SELFAWARENESS_ENTRY_TIMEOUT)
m_phy.erase(i++); m_phy.erase(i++);
else ++i; else
++i;
} }
} }
MultiMap< unsigned int, InetAddress > SelfAwareness::externalAddresses(CallContext &cc) const MultiMap<unsigned int, InetAddress> SelfAwareness::externalAddresses(CallContext& cc) const
{ {
MultiMap< unsigned int, InetAddress > r; MultiMap<unsigned int, InetAddress> r;
// Count endpoints reporting each IP/port combo // Count endpoints reporting each IP/port combo
Map< InetAddress, unsigned long > counts; Map<InetAddress, unsigned long> counts;
{ {
Mutex::Lock l(m_phy_l); Mutex::Lock l(m_phy_l);
for (Map< p_PhySurfaceKey, p_PhySurfaceEntry >::const_iterator i(m_phy.begin()); i != m_phy.end(); ++i) { for (Map<p_PhySurfaceKey, p_PhySurfaceEntry>::const_iterator i(m_phy.begin()); i != m_phy.end(); ++i) {
if ((cc.ticks - i->second.timestampTicks) < ZT_SELFAWARENESS_ENTRY_TIMEOUT) if ((cc.ticks - i->second.timestampTicks) < ZT_SELFAWARENESS_ENTRY_TIMEOUT)
++counts[i->second.mySurface]; ++counts[i->second.mySurface];
} }
} }
// Invert to create a map from count to address // Invert to create a map from count to address
for (Map< InetAddress, unsigned long >::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)); r.insert(std::pair<unsigned long, InetAddress>(i->second, i->first));
return r; return r;
} }

View file

@ -14,12 +14,12 @@
#ifndef ZT_SELFAWARENESS_HPP #ifndef ZT_SELFAWARENESS_HPP
#define ZT_SELFAWARENESS_HPP #define ZT_SELFAWARENESS_HPP
#include "Constants.hpp"
#include "InetAddress.hpp"
#include "Containers.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Mutex.hpp"
#include "CallContext.hpp" #include "CallContext.hpp"
#include "Constants.hpp"
#include "Containers.hpp"
#include "InetAddress.hpp"
#include "Mutex.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -31,10 +31,9 @@ class Context;
* *
* Name aside, it shouldn't be capable of achieving sentience. * Name aside, it shouldn't be capable of achieving sentience.
*/ */
class SelfAwareness class SelfAwareness {
{ public:
public: explicit SelfAwareness(const Context& ctx);
explicit SelfAwareness(const Context &ctx);
/** /**
* Called when a remote peer informs us of our external network address * Called when a remote peer informs us of our external network address
@ -45,54 +44,77 @@ public:
* @param myPhysicalAddress Physical address that peer says we have * @param myPhysicalAddress Physical address that peer says we have
* @param trusted True if this peer is trusted as an authority to inform us of external address changes * @param trusted True if this peer is trusted as an authority to inform us of external address changes
*/ */
void iam(const CallContext &cc, const Identity &reporter, int64_t receivedOnLocalSocket, const InetAddress &reporterPhysicalAddress, const InetAddress &myPhysicalAddress, bool trusted); void
iam(const CallContext& cc,
const Identity& reporter,
int64_t receivedOnLocalSocket,
const InetAddress& reporterPhysicalAddress,
const InetAddress& myPhysicalAddress,
bool trusted);
/** /**
* Clean up database periodically * Clean up database periodically
*/ */
void clean(const CallContext &cc); void clean(const CallContext& cc);
/** /**
* Get external address consensus, which is the statistical "mode" of external addresses. * Get external address consensus, which is the statistical "mode" of external addresses.
* *
* @return Map of count to IP/port representing how many endpoints reported each address * @return Map of count to IP/port representing how many endpoints reported each address
*/ */
MultiMap< unsigned int, InetAddress > externalAddresses(CallContext &cc) const; MultiMap<unsigned int, InetAddress> externalAddresses(CallContext& cc) const;
private: private:
struct p_PhySurfaceKey struct p_PhySurfaceKey {
{
Address reporter; Address reporter;
int64_t receivedOnLocalSocket; int64_t receivedOnLocalSocket;
InetAddress reporterPhysicalAddress; InetAddress reporterPhysicalAddress;
InetAddress::IpScope scope; InetAddress::IpScope scope;
ZT_INLINE p_PhySurfaceKey() noexcept ZT_INLINE p_PhySurfaceKey() noexcept
{} {
}
ZT_INLINE p_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
{} p_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 noexcept ZT_INLINE unsigned long hashCode() const noexcept
{ return ((unsigned long)reporter.toInt() + (unsigned long)receivedOnLocalSocket + (unsigned long)scope); } {
return ((unsigned long)reporter.toInt() + (unsigned long)receivedOnLocalSocket + (unsigned long)scope);
}
ZT_INLINE bool operator==(const p_PhySurfaceKey &k) const noexcept ZT_INLINE bool operator==(const p_PhySurfaceKey& k) const noexcept
{ return ((reporter == k.reporter) && (receivedOnLocalSocket == k.receivedOnLocalSocket) && (reporterPhysicalAddress == k.reporterPhysicalAddress) && (scope == k.scope)); } {
return (
(reporter == k.reporter) && (receivedOnLocalSocket == k.receivedOnLocalSocket)
&& (reporterPhysicalAddress == k.reporterPhysicalAddress) && (scope == k.scope));
}
ZT_INLINE bool operator!=(const p_PhySurfaceKey &k) const noexcept ZT_INLINE bool operator!=(const p_PhySurfaceKey& k) const noexcept
{ return (!(*this == k)); } {
return (! (*this == k));
}
ZT_INLINE bool operator<(const p_PhySurfaceKey &k) const noexcept ZT_INLINE bool operator<(const p_PhySurfaceKey& k) const noexcept
{ {
if (reporter < k.reporter) { if (reporter < k.reporter) {
return true; return true;
} else if (reporter == k.reporter) { }
else if (reporter == k.reporter) {
if (receivedOnLocalSocket < k.receivedOnLocalSocket) { if (receivedOnLocalSocket < k.receivedOnLocalSocket) {
return true; return true;
} else if (receivedOnLocalSocket == k.receivedOnLocalSocket) { }
else if (receivedOnLocalSocket == k.receivedOnLocalSocket) {
if (reporterPhysicalAddress < k.reporterPhysicalAddress) { if (reporterPhysicalAddress < k.reporterPhysicalAddress) {
return true; return true;
} else if (reporterPhysicalAddress == k.reporterPhysicalAddress) { }
else if (reporterPhysicalAddress == k.reporterPhysicalAddress) {
return scope < k.scope; return scope < k.scope;
} }
} }
@ -101,21 +123,28 @@ private:
} }
}; };
struct p_PhySurfaceEntry struct p_PhySurfaceEntry {
{
InetAddress mySurface; InetAddress mySurface;
int64_t timestampTicks; int64_t timestampTicks;
bool trusted; bool trusted;
ZT_INLINE p_PhySurfaceEntry() noexcept: mySurface(), timestampTicks(0), trusted(false) ZT_INLINE p_PhySurfaceEntry() noexcept
{} : mySurface()
, timestampTicks(0)
, trusted(false)
{
}
ZT_INLINE p_PhySurfaceEntry(const InetAddress &a, const int64_t t) noexcept: mySurface(a), timestampTicks(t), trusted(false) ZT_INLINE p_PhySurfaceEntry(const InetAddress& a, const int64_t t) noexcept
{} : mySurface(a)
, timestampTicks(t)
, trusted(false)
{
}
}; };
const Context &m_ctx; const Context& m_ctx;
Map< p_PhySurfaceKey, p_PhySurfaceEntry > m_phy; Map<p_PhySurfaceKey, p_PhySurfaceEntry> m_phy;
Mutex m_phy_l; Mutex m_phy_l;
}; };

View file

@ -25,37 +25,42 @@ namespace ZeroTier {
* Classes must have an atomic<int> field called __refCount and set this class * Classes must have an atomic<int> field called __refCount and set this class
* as a friend to be used with this. * as a friend to be used with this.
*/ */
template< typename T > template <typename T> class SharedPtr : public TriviallyCopyable {
class SharedPtr : public TriviallyCopyable public:
{ ZT_INLINE SharedPtr() noexcept : m_ptr(nullptr)
public: {
ZT_INLINE SharedPtr() noexcept: m_ptr(nullptr) }
{}
explicit ZT_INLINE SharedPtr(T *obj) noexcept: m_ptr(obj) explicit ZT_INLINE SharedPtr(T* obj) noexcept : m_ptr(obj)
{ if (likely(obj != nullptr)) const_cast<std::atomic< int > *>(&(obj->__refCount))->fetch_add(1, std::memory_order_acquire); } {
if (likely(obj != nullptr))
const_cast<std::atomic<int>*>(&(obj->__refCount))->fetch_add(1, std::memory_order_acquire);
}
ZT_INLINE SharedPtr(const SharedPtr &sp) noexcept: m_ptr(sp.m_acquire()) ZT_INLINE SharedPtr(const SharedPtr& sp) noexcept : m_ptr(sp.m_acquire())
{} {
}
ZT_INLINE ~SharedPtr() ZT_INLINE ~SharedPtr()
{ m_release(); } {
m_release();
}
ZT_INLINE SharedPtr &operator=(const SharedPtr &sp) ZT_INLINE SharedPtr& operator=(const SharedPtr& sp)
{ {
if (likely(m_ptr != sp.m_ptr)) { if (likely(m_ptr != sp.m_ptr)) {
T *const p = sp.m_acquire(); T* const p = sp.m_acquire();
m_release(); m_release();
m_ptr = p; m_ptr = p;
} }
return *this; return *this;
} }
ZT_INLINE void set(T *ptr) noexcept ZT_INLINE void set(T* ptr) noexcept
{ {
m_release(); m_release();
m_ptr = ptr; m_ptr = ptr;
const_cast<std::atomic< int > *>(&(ptr->__refCount))->fetch_add(1, std::memory_order_acquire); const_cast<std::atomic<int>*>(&(ptr->__refCount))->fetch_add(1, std::memory_order_acquire);
} }
/** /**
@ -66,9 +71,9 @@ public:
* *
* @param with Pointer to swap with * @param with Pointer to swap with
*/ */
ZT_INLINE void swap(SharedPtr &with) noexcept ZT_INLINE void swap(SharedPtr& with) noexcept
{ {
T *const tmp = m_ptr; T* const tmp = m_ptr;
m_ptr = with.m_ptr; m_ptr = with.m_ptr;
with.m_ptr = tmp; with.m_ptr = tmp;
} }
@ -82,7 +87,7 @@ public:
* *
* @param from Source pointer; will be changed to NULL * @param from Source pointer; will be changed to NULL
*/ */
ZT_INLINE void move(SharedPtr &from) ZT_INLINE void move(SharedPtr& from)
{ {
m_release(); m_release();
m_ptr = from.m_ptr; m_ptr = from.m_ptr;
@ -90,19 +95,27 @@ public:
} }
ZT_INLINE operator bool() const noexcept ZT_INLINE operator bool() const noexcept
{ return (m_ptr != nullptr); } {
return (m_ptr != nullptr);
}
ZT_INLINE T &operator*() const noexcept ZT_INLINE T& operator*() const noexcept
{ return *m_ptr; } {
return *m_ptr;
}
ZT_INLINE T *operator->() const noexcept ZT_INLINE T* operator->() const noexcept
{ return m_ptr; } {
return m_ptr;
}
/** /**
* @return Raw pointer to held object * @return Raw pointer to held object
*/ */
ZT_INLINE T *ptr() const noexcept ZT_INLINE T* ptr() const noexcept
{ return m_ptr; } {
return m_ptr;
}
/** /**
* Set this pointer to NULL * Set this pointer to NULL
@ -123,60 +136,77 @@ public:
* *
* @return Pointer or NULL if more than one reference * @return Pointer or NULL if more than one reference
*/ */
ZT_INLINE T *weakGC() ZT_INLINE T* weakGC()
{ {
if (likely(m_ptr != nullptr)) { if (likely(m_ptr != nullptr)) {
int one = 1; int one = 1;
if (const_cast<std::atomic< int > *>(&(m_ptr->__refCount))->compare_exchange_strong(one, (int)0)) { if (const_cast<std::atomic<int>*>(&(m_ptr->__refCount))->compare_exchange_strong(one, (int)0)) {
T *const ptr = m_ptr; T* const ptr = m_ptr;
m_ptr = nullptr; m_ptr = nullptr;
return ptr; return ptr;
} else { }
else {
return nullptr; return nullptr;
} }
} else { }
else {
return nullptr; return nullptr;
} }
} }
ZT_INLINE unsigned long hashCode() const noexcept ZT_INLINE unsigned long hashCode() const noexcept
{ return (unsigned long)((uintptr_t)m_ptr + (uintptr_t)Utils::hash32((uint32_t)m_ptr)); } {
return (unsigned long)((uintptr_t)m_ptr + (uintptr_t)Utils::hash32((uint32_t)m_ptr));
}
ZT_INLINE bool operator==(const SharedPtr &sp) const noexcept ZT_INLINE bool operator==(const SharedPtr& sp) const noexcept
{ return (m_ptr == sp.m_ptr); } {
return (m_ptr == sp.m_ptr);
}
ZT_INLINE bool operator!=(const SharedPtr &sp) const noexcept ZT_INLINE bool operator!=(const SharedPtr& sp) const noexcept
{ return (m_ptr != sp.m_ptr); } {
return (m_ptr != sp.m_ptr);
}
ZT_INLINE bool operator>(const SharedPtr &sp) const noexcept ZT_INLINE bool operator>(const SharedPtr& sp) const noexcept
{ return (reinterpret_cast<const uint8_t *>(m_ptr) > reinterpret_cast<const uint8_t *>(sp.m_ptr)); } {
return (reinterpret_cast<const uint8_t*>(m_ptr) > reinterpret_cast<const uint8_t*>(sp.m_ptr));
}
ZT_INLINE bool operator<(const SharedPtr &sp) const noexcept ZT_INLINE bool operator<(const SharedPtr& sp) const noexcept
{ return (reinterpret_cast<const uint8_t *>(m_ptr) < reinterpret_cast<const uint8_t *>(sp.m_ptr)); } {
return (reinterpret_cast<const uint8_t*>(m_ptr) < reinterpret_cast<const uint8_t*>(sp.m_ptr));
}
ZT_INLINE bool operator>=(const SharedPtr &sp) const noexcept ZT_INLINE bool operator>=(const SharedPtr& sp) const noexcept
{ return (reinterpret_cast<const uint8_t *>(m_ptr) >= reinterpret_cast<const uint8_t *>(sp.m_ptr)); } {
return (reinterpret_cast<const uint8_t*>(m_ptr) >= reinterpret_cast<const uint8_t*>(sp.m_ptr));
}
ZT_INLINE bool operator<=(const SharedPtr &sp) const noexcept ZT_INLINE bool operator<=(const SharedPtr& sp) const noexcept
{ return (reinterpret_cast<const uint8_t *>(m_ptr) <= reinterpret_cast<const uint8_t *>(sp.m_ptr)); } {
return (reinterpret_cast<const uint8_t*>(m_ptr) <= reinterpret_cast<const uint8_t*>(sp.m_ptr));
}
private: private:
ZT_INLINE T *m_acquire() const noexcept ZT_INLINE T* m_acquire() const noexcept
{ {
if (likely(m_ptr != nullptr)) if (likely(m_ptr != nullptr))
const_cast<std::atomic< int > *>(&(m_ptr->__refCount))->fetch_add(1, std::memory_order_acquire); const_cast<std::atomic<int>*>(&(m_ptr->__refCount))->fetch_add(1, std::memory_order_acquire);
return m_ptr; return m_ptr;
} }
ZT_INLINE void m_release() const noexcept ZT_INLINE void m_release() const noexcept
{ {
if (likely(m_ptr != nullptr)) { if (likely(m_ptr != nullptr)) {
if (unlikely(const_cast<std::atomic< int > *>(&(m_ptr->__refCount))->fetch_sub(1, std::memory_order_release) <= 1)) if (unlikely(
const_cast<std::atomic<int>*>(&(m_ptr->__refCount))->fetch_sub(1, std::memory_order_release) <= 1))
delete m_ptr; delete m_ptr;
} }
} }
T *m_ptr; T* m_ptr;
}; };
} // namespace ZeroTier } // namespace ZeroTier
@ -184,13 +214,15 @@ private:
// Augment std::swap to speed up some operations with SharedPtr. // Augment std::swap to speed up some operations with SharedPtr.
namespace std { namespace std {
template< typename T > template <typename T> ZT_MAYBE_UNUSED ZT_INLINE void swap(ZeroTier::SharedPtr<T>& a, ZeroTier::SharedPtr<T>& b) noexcept
ZT_MAYBE_UNUSED ZT_INLINE void swap(ZeroTier::SharedPtr< T > &a, ZeroTier::SharedPtr< T > &b) noexcept {
{ a.swap(b); } a.swap(b);
}
template< typename T > template <typename T> ZT_MAYBE_UNUSED ZT_INLINE void move(ZeroTier::SharedPtr<T>& a, ZeroTier::SharedPtr<T>& b) noexcept
ZT_MAYBE_UNUSED ZT_INLINE void move(ZeroTier::SharedPtr< T > &a, ZeroTier::SharedPtr< T > &b) noexcept {
{ a.move(b); } a.move(b);
}
} // namespace std } // namespace std

View file

@ -29,9 +29,8 @@
* This can be used in place of Mutex to lock things that are extremely fast * This can be used in place of Mutex to lock things that are extremely fast
* to access. It should be used very sparingly. * to access. It should be used very sparingly.
*/ */
class Spinlock class Spinlock {
{ public:
public:
/** /**
* Pause current thread using whatever methods might be available * Pause current thread using whatever methods might be available
* *
@ -50,8 +49,9 @@ public:
#endif #endif
} }
ZT_INLINE Spinlock() noexcept: m_locked(false) ZT_INLINE Spinlock() noexcept : m_locked(false)
{} {
}
ZT_INLINE void lock() noexcept ZT_INLINE void lock() noexcept
{ {
@ -63,11 +63,18 @@ public:
} }
ZT_INLINE void unlock() noexcept ZT_INLINE void unlock() noexcept
{ m_locked.clear(std::memory_order_release); } {
m_locked.clear(std::memory_order_release);
}
private: private:
ZT_INLINE Spinlock(const Spinlock &) noexcept {} ZT_INLINE Spinlock(const Spinlock&) noexcept
ZT_INLINE const Spinlock &operator=(const Spinlock &) noexcept { return *this; } {
}
ZT_INLINE const Spinlock& operator=(const Spinlock&) noexcept
{
return *this;
}
std::atomic_flag m_locked; std::atomic_flag m_locked;
}; };

View file

@ -14,21 +14,21 @@
#ifndef ZT_STORE_HPP #ifndef ZT_STORE_HPP
#define ZT_STORE_HPP #define ZT_STORE_HPP
#include "CallContext.hpp"
#include "Constants.hpp" #include "Constants.hpp"
#include "Containers.hpp" #include "Containers.hpp"
#include "Context.hpp" #include "Context.hpp"
#include "CallContext.hpp"
namespace ZeroTier { namespace ZeroTier {
/** /**
* Wrapper around API callbacks for data store * Wrapper around API callbacks for data store
*/ */
class Store class Store {
{ public:
public: ZT_INLINE Store(const Context& ctx) : m_ctx(ctx)
ZT_INLINE Store(const Context &ctx): m_ctx(ctx) {
{} }
/** /**
* Get a state object * Get a state object
@ -38,14 +38,23 @@ public:
* @param idSize Size of object ID in qwords * @param idSize Size of object ID in qwords
* @return Data or empty vector if not found * @return Data or empty vector if not found
*/ */
ZT_INLINE Vector< uint8_t > get(const CallContext &cc, ZT_StateObjectType type, const uint64_t *const id, unsigned int idSize) const ZT_INLINE Vector<uint8_t>
get(const CallContext& cc, ZT_StateObjectType type, const uint64_t* const id, unsigned int idSize) const
{ {
Vector< uint8_t > dv; Vector<uint8_t> dv;
void *data = nullptr; void* data = nullptr;
void (*freeFunc)(void *) = nullptr; void (*freeFunc)(void*) = nullptr;
const int r = m_ctx.cb.stateGetFunction(reinterpret_cast<ZT_Node *>(m_ctx.node), m_ctx.uPtr, cc.tPtr, type, id, idSize, &data, &freeFunc); const int r = m_ctx.cb.stateGetFunction(
reinterpret_cast<ZT_Node*>(m_ctx.node),
m_ctx.uPtr,
cc.tPtr,
type,
id,
idSize,
&data,
&freeFunc);
if (r > 0) if (r > 0)
dv.assign(reinterpret_cast<const uint8_t *>(data), reinterpret_cast<const uint8_t *>(data) + r); dv.assign(reinterpret_cast<const uint8_t*>(data), reinterpret_cast<const uint8_t*>(data) + r);
if ((data) && (freeFunc)) if ((data) && (freeFunc))
freeFunc(data); freeFunc(data);
return dv; return dv;
@ -60,8 +69,17 @@ public:
* @param data Data to store * @param data Data to store
* @param len Length of data * @param len Length of data
*/ */
ZT_INLINE void put(const CallContext &cc, ZT_StateObjectType type, const uint64_t *const id, const unsigned int idSize, const void *const data, const unsigned int len) noexcept ZT_INLINE void
{ m_ctx.cb.statePutFunction(reinterpret_cast<ZT_Node *>(this), m_ctx.uPtr, cc.tPtr, type, id, idSize, data, (int)len); } put(const CallContext& cc,
ZT_StateObjectType type,
const uint64_t* const id,
const unsigned int idSize,
const void* const data,
const unsigned int len) noexcept
{
m_ctx.cb
.statePutFunction(reinterpret_cast<ZT_Node*>(this), m_ctx.uPtr, cc.tPtr, type, id, idSize, data, (int)len);
}
/** /**
* Erase a state object from the object store * Erase a state object from the object store
@ -70,11 +88,14 @@ public:
* @param id Object ID * @param id Object ID
* @param idSize Size of object ID in qwords * @param idSize Size of object ID in qwords
*/ */
ZT_INLINE void erase(const CallContext &cc, ZT_StateObjectType type, const uint64_t *const id, const unsigned int idSize) noexcept ZT_INLINE void
{ m_ctx.cb.statePutFunction(reinterpret_cast<ZT_Node *>(this), m_ctx.uPtr, cc.tPtr, type, id, idSize, nullptr, -1); } erase(const CallContext& cc, ZT_StateObjectType type, const uint64_t* const id, const unsigned int idSize) noexcept
{
m_ctx.cb.statePutFunction(reinterpret_cast<ZT_Node*>(this), m_ctx.uPtr, cc.tPtr, type, id, idSize, nullptr, -1);
}
private: private:
const Context &m_ctx; const Context& m_ctx;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -14,29 +14,24 @@
#ifndef ZT_SYMMETRICKEY_HPP #ifndef ZT_SYMMETRICKEY_HPP
#define ZT_SYMMETRICKEY_HPP #define ZT_SYMMETRICKEY_HPP
#include "Constants.hpp"
#include "Utils.hpp"
#include "AES.hpp" #include "AES.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Constants.hpp"
#include "Utils.hpp"
namespace ZeroTier { namespace ZeroTier {
/** /**
* Container for symmetric keys and ciphers initialized with them. * Container for symmetric keys and ciphers initialized with them.
*/ */
class SymmetricKey class SymmetricKey {
{ public:
public:
/** /**
* Construct an uninitialized key (init() must be called) * Construct an uninitialized key (init() must be called)
*/ */
ZT_INLINE SymmetricKey(): ZT_INLINE SymmetricKey() : m_secret(), m_ts(-1), m_initialNonce(0), m_cipher(), m_nonce(0)
m_secret(), {
m_ts(-1), }
m_initialNonce(0),
m_cipher(),
m_nonce(0)
{}
/** /**
* Construct a new symmetric key * Construct a new symmetric key
@ -47,26 +42,30 @@ public:
* @param ts Key timestamp * @param ts Key timestamp
* @param key Key (must be 48 bytes / 384 bits) * @param key Key (must be 48 bytes / 384 bits)
*/ */
ZT_INLINE SymmetricKey(const int64_t ts, const void *const key) noexcept: ZT_INLINE SymmetricKey(const int64_t ts, const void* const key) noexcept
m_secret(key), : m_secret(key)
m_ts(ts), , m_ts(ts)
m_initialNonce(Utils::getSecureRandomU64() >> 1U), , m_initialNonce(Utils::getSecureRandomU64() >> 1U)
m_cipher(key), , m_cipher(key)
m_nonce(m_initialNonce) , m_nonce(m_initialNonce)
{} {
}
ZT_INLINE SymmetricKey(const SymmetricKey &k) noexcept: ZT_INLINE SymmetricKey(const SymmetricKey& k) noexcept
m_secret(k.m_secret), : m_secret(k.m_secret)
m_ts(k.m_ts), , m_ts(k.m_ts)
m_initialNonce(k.m_initialNonce), , m_initialNonce(k.m_initialNonce)
m_cipher(k.m_secret.data), , m_cipher(k.m_secret.data)
m_nonce(k.m_nonce.load(std::memory_order_relaxed)) , m_nonce(k.m_nonce.load(std::memory_order_relaxed))
{} {
}
ZT_INLINE ~SymmetricKey() noexcept ZT_INLINE ~SymmetricKey() noexcept
{ Utils::burn(m_secret.data, ZT_SYMMETRIC_KEY_SIZE); } {
Utils::burn(m_secret.data, ZT_SYMMETRIC_KEY_SIZE);
}
ZT_INLINE SymmetricKey &operator=(const SymmetricKey &k) noexcept ZT_INLINE SymmetricKey& operator=(const SymmetricKey& k) noexcept
{ {
m_secret = k.m_secret; m_secret = k.m_secret;
m_ts = k.m_ts; m_ts = k.m_ts;
@ -82,9 +81,9 @@ public:
* @param ts Key timestamp * @param ts Key timestamp
* @param key Key (must be 48 bytes / 384 bits) * @param key Key (must be 48 bytes / 384 bits)
*/ */
ZT_INLINE void init(const int64_t ts, const void *const key) noexcept ZT_INLINE void init(const int64_t ts, const void* const key) noexcept
{ {
Utils::copy< ZT_SYMMETRIC_KEY_SIZE >(m_secret.data, key); Utils::copy<ZT_SYMMETRIC_KEY_SIZE>(m_secret.data, key);
m_ts = ts; m_ts = ts;
m_initialNonce = Utils::getSecureRandomU64() >> 1U; m_initialNonce = Utils::getSecureRandomU64() >> 1U;
m_cipher.init(key); m_cipher.init(key);
@ -99,7 +98,9 @@ public:
* @return Next unique IV for next message * @return Next unique IV for next message
*/ */
ZT_INLINE uint64_t nextMessage(const Address sender, const Address receiver) noexcept ZT_INLINE uint64_t nextMessage(const Address sender, const Address receiver) noexcept
{ return m_nonce.fetch_add(1, std::memory_order_relaxed) ^ (((uint64_t)(sender > receiver)) << 63U); } {
return m_nonce.fetch_add(1, std::memory_order_relaxed) ^ (((uint64_t)(sender > receiver)) << 63U);
}
/** /**
* Get the number of times this key has been used. * Get the number of times this key has been used.
@ -110,32 +111,40 @@ public:
* @return Number of times nextMessage() has been called since object creation * @return Number of times nextMessage() has been called since object creation
*/ */
ZT_INLINE uint64_t odometer() const noexcept ZT_INLINE uint64_t odometer() const noexcept
{ return m_nonce.load(std::memory_order_relaxed) - m_initialNonce; } {
return m_nonce.load(std::memory_order_relaxed) - m_initialNonce;
}
/** /**
* @return Key creation timestamp or -1 if this is a long-lived key * @return Key creation timestamp or -1 if this is a long-lived key
*/ */
ZT_INLINE int64_t timestamp() const noexcept ZT_INLINE int64_t timestamp() const noexcept
{ return m_ts; } {
return m_ts;
}
/** /**
* @return 48-byte / 384-bit secret key * @return 48-byte / 384-bit secret key
*/ */
ZT_INLINE const uint8_t *key() const noexcept ZT_INLINE const uint8_t* key() const noexcept
{ return m_secret.data; } {
return m_secret.data;
}
/** /**
* @return AES cipher (already initialized with secret key) * @return AES cipher (already initialized with secret key)
*/ */
ZT_INLINE const AES &aes() const noexcept ZT_INLINE const AES& aes() const noexcept
{ return m_cipher; } {
return m_cipher;
}
private: private:
Blob< ZT_SYMMETRIC_KEY_SIZE > m_secret; Blob<ZT_SYMMETRIC_KEY_SIZE> m_secret;
int64_t m_ts; int64_t m_ts;
uint64_t m_initialNonce; uint64_t m_initialNonce;
AES m_cipher; AES m_cipher;
std::atomic< uint64_t > m_nonce; std::atomic<uint64_t> m_nonce;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -15,7 +15,7 @@
namespace ZeroTier { namespace ZeroTier {
bool TagCredential::sign(const Identity &signer) noexcept bool TagCredential::sign(const Identity& signer) noexcept
{ {
uint8_t buf[ZT_TAG_MARSHAL_SIZE_MAX]; uint8_t buf[ZT_TAG_MARSHAL_SIZE_MAX];
if (signer.hasPrivate()) { if (signer.hasPrivate()) {
@ -33,18 +33,18 @@ int TagCredential::marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX], bool forSign)
for (int k = 0; k < 8; ++k) for (int k = 0; k < 8; ++k)
data[p++] = 0x7f; data[p++] = 0x7f;
} }
Utils::storeBigEndian< uint64_t >(data + p, m_networkId); Utils::storeBigEndian<uint64_t>(data + p, m_networkId);
Utils::storeBigEndian< uint64_t >(data + p + 8, (uint64_t)m_ts); Utils::storeBigEndian<uint64_t>(data + p + 8, (uint64_t)m_ts);
Utils::storeBigEndian< uint32_t >(data + p + 16, m_id); Utils::storeBigEndian<uint32_t>(data + p + 16, m_id);
Utils::storeBigEndian< uint32_t >(data + p + 20, m_value); Utils::storeBigEndian<uint32_t>(data + p + 20, m_value);
p += 24; p += 24;
m_issuedTo.copyTo(data + p); m_issuedTo.copyTo(data + p);
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
m_signedBy.copyTo(data + p); m_signedBy.copyTo(data + p);
p += ZT_ADDRESS_LENGTH; p += ZT_ADDRESS_LENGTH;
if (!forSign) { if (! forSign) {
data[p++] = 1; data[p++] = 1;
Utils::storeBigEndian< uint16_t >(data + p, (uint16_t)m_signatureLength); Utils::storeBigEndian<uint16_t>(data + p, (uint16_t)m_signatureLength);
p += 2; p += 2;
Utils::copy(data + p, m_signature, m_signatureLength); Utils::copy(data + p, m_signature, m_signatureLength);
p += (int)m_signatureLength; p += (int)m_signatureLength;
@ -58,25 +58,25 @@ int TagCredential::marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX], bool forSign)
return p; return p;
} }
int TagCredential::unmarshal(const uint8_t *data, int len) noexcept int TagCredential::unmarshal(const uint8_t* data, int len) noexcept
{ {
if (len < 37) if (len < 37)
return -1; return -1;
m_networkId = Utils::loadBigEndian< uint64_t >(data); m_networkId = Utils::loadBigEndian<uint64_t>(data);
m_ts = (int64_t)Utils::loadBigEndian< uint64_t >(data + 8); m_ts = (int64_t)Utils::loadBigEndian<uint64_t>(data + 8);
m_id = Utils::loadBigEndian< uint32_t >(data + 16); m_id = Utils::loadBigEndian<uint32_t>(data + 16);
m_value = Utils::loadBigEndian< uint32_t >(data + 20); m_value = Utils::loadBigEndian<uint32_t>(data + 20);
m_issuedTo.setTo(data + 24); m_issuedTo.setTo(data + 24);
m_signedBy.setTo(data + 29); m_signedBy.setTo(data + 29);
// 1 byte reserved // 1 byte reserved
m_signatureLength = Utils::loadBigEndian< uint16_t >(data + 35); m_signatureLength = Utils::loadBigEndian<uint16_t>(data + 35);
int p = 37 + (int)m_signatureLength; int p = 37 + (int)m_signatureLength;
if ((m_signatureLength > ZT_SIGNATURE_BUFFER_SIZE) || (p > len)) if ((m_signatureLength > ZT_SIGNATURE_BUFFER_SIZE) || (p > len))
return -1; return -1;
Utils::copy(m_signature, data + p, m_signatureLength); Utils::copy(m_signature, data + p, m_signatureLength);
if ((p + 2) > len) if ((p + 2) > len)
return -1; return -1;
p += 2 + Utils::loadBigEndian< uint16_t >(data + p); p += 2 + Utils::loadBigEndian<uint16_t>(data + p);
if (p > len) if (p > len)
return -1; return -1;
return p; return p;

View file

@ -14,10 +14,10 @@
#ifndef ZT_TAG_HPP #ifndef ZT_TAG_HPP
#define ZT_TAG_HPP #define ZT_TAG_HPP
#include "Address.hpp"
#include "C25519.hpp"
#include "Constants.hpp" #include "Constants.hpp"
#include "Credential.hpp" #include "Credential.hpp"
#include "C25519.hpp"
#include "Address.hpp"
#include "Identity.hpp" #include "Identity.hpp"
#define ZT_TAG_MARSHAL_SIZE_MAX (8 + 8 + 4 + 4 + 5 + 5 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE + 2) #define ZT_TAG_MARSHAL_SIZE_MAX (8 + 8 + 4 + 4 + 5 + 5 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE + 2)
@ -43,16 +43,19 @@ class Context;
* Unlike capabilities tags are signed only by the issuer and are never * Unlike capabilities tags are signed only by the issuer and are never
* transferable. * transferable.
*/ */
class TagCredential : public Credential class TagCredential : public Credential {
{
friend class Credential; friend class Credential;
public: public:
static constexpr ZT_CredentialType credentialType() noexcept static constexpr ZT_CredentialType credentialType() noexcept
{ return ZT_CREDENTIAL_TYPE_TAG; } {
return ZT_CREDENTIAL_TYPE_TAG;
}
ZT_INLINE TagCredential() noexcept ZT_INLINE TagCredential() noexcept
{ memoryZero(this); } {
memoryZero(this);
}
/** /**
* @param nwid Network ID * @param nwid Network ID
@ -61,42 +64,66 @@ public:
* @param id Tag ID * @param id Tag ID
* @param value Tag value * @param value Tag value
*/ */
ZT_INLINE TagCredential(const uint64_t nwid, const int64_t ts, const Address &issuedTo, const uint32_t id, const uint32_t value) noexcept: ZT_INLINE TagCredential(
m_id(id), const uint64_t nwid,
m_value(value), const int64_t ts,
m_networkId(nwid), const Address& issuedTo,
m_ts(ts), const uint32_t id,
m_issuedTo(issuedTo), const uint32_t value) noexcept
m_signedBy(), : m_id(id)
m_signatureLength(0) , m_value(value)
{} , m_networkId(nwid)
, m_ts(ts)
, m_issuedTo(issuedTo)
, m_signedBy()
, m_signatureLength(0)
{
}
ZT_INLINE uint32_t id() const noexcept ZT_INLINE uint32_t id() const noexcept
{ return m_id; } {
return m_id;
}
ZT_INLINE const uint32_t &value() const noexcept ZT_INLINE const uint32_t& value() const noexcept
{ return m_value; } {
return m_value;
}
ZT_INLINE uint64_t networkId() const noexcept ZT_INLINE uint64_t networkId() const noexcept
{ return m_networkId; } {
return m_networkId;
}
ZT_INLINE int64_t timestamp() const noexcept ZT_INLINE int64_t timestamp() const noexcept
{ return m_ts; } {
return m_ts;
}
ZT_INLINE int64_t revision() const noexcept ZT_INLINE int64_t revision() const noexcept
{ return m_ts; } {
return m_ts;
}
ZT_INLINE const Address &issuedTo() const noexcept ZT_INLINE const Address& issuedTo() const noexcept
{ return m_issuedTo; } {
return m_issuedTo;
}
ZT_INLINE const Address &signer() const noexcept ZT_INLINE const Address& signer() const noexcept
{ return m_signedBy; } {
return m_signedBy;
}
ZT_INLINE const uint8_t *signature() const noexcept ZT_INLINE const uint8_t* signature() const noexcept
{ return m_signature; } {
return m_signature;
}
ZT_INLINE unsigned int signatureLength() const noexcept ZT_INLINE unsigned int signatureLength() const noexcept
{ return m_signatureLength; } {
return m_signatureLength;
}
/** /**
* Sign this tag * Sign this tag
@ -104,7 +131,7 @@ public:
* @param signer Signing identity, must have private key * @param signer Signing identity, must have private key
* @return True if signature was successful * @return True if signature was successful
*/ */
bool sign(const Identity &signer) noexcept; bool sign(const Identity& signer) noexcept;
/** /**
* Check this tag's signature * Check this tag's signature
@ -112,58 +139,85 @@ public:
* @param RR Runtime environment to allow identity lookup for signedBy * @param RR Runtime environment to allow identity lookup for signedBy
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
*/ */
ZT_INLINE Credential::VerifyResult verify(const Context &ctx, const CallContext &cc) const noexcept ZT_INLINE Credential::VerifyResult verify(const Context& ctx, const CallContext& cc) const noexcept
{ return s_verify(ctx, cc, *this); } {
return s_verify(ctx, cc, *this);
}
static constexpr int marshalSizeMax() noexcept static constexpr int marshalSizeMax() noexcept
{ return ZT_TAG_MARSHAL_SIZE_MAX; } {
return ZT_TAG_MARSHAL_SIZE_MAX;
}
int marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX], bool forSign = false) const noexcept; int marshal(uint8_t data[ZT_TAG_MARSHAL_SIZE_MAX], bool forSign = false) const noexcept;
int unmarshal(const uint8_t *data, int len) noexcept; int unmarshal(const uint8_t* data, int len) noexcept;
// Provides natural sort order by ID // Provides natural sort order by ID
ZT_INLINE bool operator<(const TagCredential &t) const noexcept ZT_INLINE bool operator<(const TagCredential& t) const noexcept
{ return (m_id < t.m_id); } {
return (m_id < t.m_id);
}
ZT_INLINE bool operator==(const TagCredential &t) const noexcept ZT_INLINE bool operator==(const TagCredential& t) const noexcept
{ return (memcmp(this, &t, sizeof(TagCredential)) == 0); } {
return (memcmp(this, &t, sizeof(TagCredential)) == 0);
}
ZT_INLINE bool operator!=(const TagCredential &t) const noexcept ZT_INLINE bool operator!=(const TagCredential& t) const noexcept
{ return (memcmp(this, &t, sizeof(TagCredential)) != 0); } {
return (memcmp(this, &t, sizeof(TagCredential)) != 0);
}
// For searching sorted arrays or lists of Tags by ID // For searching sorted arrays or lists of Tags by ID
struct IdComparePredicate struct IdComparePredicate {
ZT_INLINE bool operator()(const TagCredential& a, const TagCredential& b) const noexcept
{ {
ZT_INLINE bool operator()(const TagCredential &a, const TagCredential &b) const noexcept return (a.id() < b.id());
{ return (a.id() < b.id()); } }
ZT_INLINE bool operator()(const uint32_t a, const TagCredential &b) const noexcept ZT_INLINE bool operator()(const uint32_t a, const TagCredential& b) const noexcept
{ return (a < b.id()); } {
return (a < b.id());
}
ZT_INLINE bool operator()(const TagCredential &a, const uint32_t b) const noexcept ZT_INLINE bool operator()(const TagCredential& a, const uint32_t b) const noexcept
{ return (a.id() < b); } {
return (a.id() < b);
}
ZT_INLINE bool operator()(const TagCredential *a, const TagCredential *b) const noexcept ZT_INLINE bool operator()(const TagCredential* a, const TagCredential* b) const noexcept
{ return (a->id() < b->id()); } {
return (a->id() < b->id());
}
ZT_INLINE bool operator()(const TagCredential *a, const TagCredential &b) const noexcept ZT_INLINE bool operator()(const TagCredential* a, const TagCredential& b) const noexcept
{ return (a->id() < b.id()); } {
return (a->id() < b.id());
}
ZT_INLINE bool operator()(const TagCredential &a, const TagCredential *b) const noexcept ZT_INLINE bool operator()(const TagCredential& a, const TagCredential* b) const noexcept
{ return (a.id() < b->id()); } {
return (a.id() < b->id());
}
ZT_INLINE bool operator()(const uint32_t a, const TagCredential *b) const noexcept ZT_INLINE bool operator()(const uint32_t a, const TagCredential* b) const noexcept
{ return (a < b->id()); } {
return (a < b->id());
}
ZT_INLINE bool operator()(const TagCredential *a, const uint32_t b) const noexcept ZT_INLINE bool operator()(const TagCredential* a, const uint32_t b) const noexcept
{ return (a->id() < b); } {
return (a->id() < b);
}
ZT_INLINE bool operator()(const uint32_t a, const uint32_t b) const noexcept ZT_INLINE bool operator()(const uint32_t a, const uint32_t b) const noexcept
{ return (a < b); } {
return (a < b);
}
}; };
private: private:
uint32_t m_id; uint32_t m_id;
uint32_t m_value; uint32_t m_value;
uint64_t m_networkId; uint64_t m_networkId;

File diff suppressed because it is too large Load diff

View file

@ -47,7 +47,7 @@
#include <stdio.h> #include <stdio.h>
#ifndef ZT_T_PRINTF #ifndef ZT_T_PRINTF
#define ZT_T_PRINTF(fmt,...) printf((fmt),##__VA_ARGS__),fflush(stdout) #define ZT_T_PRINTF(fmt, ...) printf((fmt), ##__VA_ARGS__), fflush(stdout)
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus
@ -57,7 +57,7 @@ extern "C" {
/** /**
* Test platform, compiler behavior, utility functions, and core classes * Test platform, compiler behavior, utility functions, and core classes
*/ */
const char *ZTT_general(); const char* ZTT_general();
/** /**
* Test crypto using test vectors and simple scenarios * Test crypto using test vectors and simple scenarios
@ -65,12 +65,12 @@ const char *ZTT_general();
* This is not an absolutely exhaustive test, just a sanity check to make sure * This is not an absolutely exhaustive test, just a sanity check to make sure
* crypto routines are basically working. * crypto routines are basically working.
*/ */
const char *ZTT_crypto(); const char* ZTT_crypto();
/** /**
* Run benchmarks of cryptographic routines and common constructions * Run benchmarks of cryptographic routines and common constructions
*/ */
const char *ZTT_benchmarkCrypto(); const char* ZTT_benchmarkCrypto();
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -16,8 +16,8 @@
#include "Constants.hpp" #include "Constants.hpp"
#include "Containers.hpp" #include "Containers.hpp"
#include "SharedPtr.hpp"
#include "Network.hpp" #include "Network.hpp"
#include "SharedPtr.hpp"
#include "Spinlock.hpp" #include "Spinlock.hpp"
// The number of buckets must be a power of two. // The number of buckets must be a power of two.
@ -36,30 +36,32 @@ namespace ZeroTier {
* fast lookup, with lookups sometimes requiring only a few instructions. It * fast lookup, with lookups sometimes requiring only a few instructions. It
* uses a "lock free" (actually pointer-as-spinlock) design. * uses a "lock free" (actually pointer-as-spinlock) design.
*/ */
template< typename V > template <typename V> class TinyMap {
class TinyMap private:
{ typedef Vector<std::pair<uint64_t, V> > EV;
private:
typedef Vector< std::pair< uint64_t, V > > EV;
public: public:
ZT_INLINE TinyMap() ZT_INLINE TinyMap()
{} {
}
ZT_INLINE ~TinyMap() ZT_INLINE ~TinyMap()
{ this->clear(); } {
this->clear();
}
ZT_INLINE void clear() ZT_INLINE void clear()
{ {
for(unsigned int i=0; i < ZT_TINYMAP_BUCKETS; ++i) { for (unsigned int i = 0; i < ZT_TINYMAP_BUCKETS; ++i) {
for(;;) { for (;;) {
const uintptr_t vptr = m_buckets[i].exchange(ZT_TINYMAP_LOCKED_POINTER, std::memory_order_acquire); const uintptr_t vptr = m_buckets[i].exchange(ZT_TINYMAP_LOCKED_POINTER, std::memory_order_acquire);
if (likely(vptr != ZT_TINYMAP_LOCKED_POINTER)) { if (likely(vptr != ZT_TINYMAP_LOCKED_POINTER)) {
if (vptr != 0) if (vptr != 0)
delete reinterpret_cast<EV *>(vptr); delete reinterpret_cast<EV*>(vptr);
m_buckets[i].store(0, std::memory_order_release); m_buckets[i].store(0, std::memory_order_release);
break; break;
} else { }
else {
Spinlock::pause(); Spinlock::pause();
} }
} }
@ -69,12 +71,14 @@ public:
ZT_INLINE V get(const uint64_t key) noexcept ZT_INLINE V get(const uint64_t key) noexcept
{ {
V tmp; V tmp;
std::atomic<uintptr_t> &bucket = m_buckets[(key ^ (key >> 32)) & ZT_TINYMAP_BUCKETS_MASK]; std::atomic<uintptr_t>& bucket = m_buckets[(key ^ (key >> 32)) & ZT_TINYMAP_BUCKETS_MASK];
for(;;) { for (;;) {
const uintptr_t vptr = bucket.exchange(ZT_TINYMAP_LOCKED_POINTER, std::memory_order_acquire); const uintptr_t vptr = bucket.exchange(ZT_TINYMAP_LOCKED_POINTER, std::memory_order_acquire);
if (likely(vptr != ZT_TINYMAP_LOCKED_POINTER)) { if (likely(vptr != ZT_TINYMAP_LOCKED_POINTER)) {
if (likely(vptr != 0)) { if (likely(vptr != 0)) {
for(typename EV::const_iterator n(reinterpret_cast<const EV *>(vptr)->begin()); n != reinterpret_cast<const EV *>(vptr)->end(); ++n) { for (typename EV::const_iterator n(reinterpret_cast<const EV*>(vptr)->begin());
n != reinterpret_cast<const EV*>(vptr)->end();
++n) {
if (likely(n->first == key)) { if (likely(n->first == key)) {
tmp = n->second; tmp = n->second;
break; break;
@ -83,22 +87,26 @@ public:
} }
bucket.store(vptr, std::memory_order_release); bucket.store(vptr, std::memory_order_release);
return tmp; return tmp;
} else { }
else {
Spinlock::pause(); Spinlock::pause();
} }
} }
} }
ZT_INLINE void set(const uint64_t key, const V &value) ZT_INLINE void set(const uint64_t key, const V& value)
{ {
std::atomic<uintptr_t> &bucket = m_buckets[(key ^ (key >> 32)) & ZT_TINYMAP_BUCKETS_MASK]; std::atomic<uintptr_t>& bucket = m_buckets[(key ^ (key >> 32)) & ZT_TINYMAP_BUCKETS_MASK];
for(;;) { for (;;) {
uintptr_t vptr = bucket.exchange(ZT_TINYMAP_LOCKED_POINTER, std::memory_order_acquire); uintptr_t vptr = bucket.exchange(ZT_TINYMAP_LOCKED_POINTER, std::memory_order_acquire);
if (likely(vptr != ZT_TINYMAP_LOCKED_POINTER)) { if (likely(vptr != ZT_TINYMAP_LOCKED_POINTER)) {
if (vptr == 0) { if (vptr == 0) {
vptr = reinterpret_cast<uintptr_t>(new EV()); vptr = reinterpret_cast<uintptr_t>(new EV());
} else { }
for (typename EV::iterator n(reinterpret_cast<EV *>(vptr)->begin()); n != reinterpret_cast<EV *>(vptr)->end(); ++n) { else {
for (typename EV::iterator n(reinterpret_cast<EV*>(vptr)->begin());
n != reinterpret_cast<EV*>(vptr)->end();
++n) {
if (n->first == key) { if (n->first == key) {
n->second = value; n->second = value;
bucket.store(vptr, std::memory_order_release); bucket.store(vptr, std::memory_order_release);
@ -106,10 +114,11 @@ public:
} }
} }
} }
reinterpret_cast<EV *>(vptr)->push_back(std::pair< uint64_t, V >(key, value)); reinterpret_cast<EV*>(vptr)->push_back(std::pair<uint64_t, V>(key, value));
bucket.store(vptr, std::memory_order_release); bucket.store(vptr, std::memory_order_release);
return; return;
} else { }
else {
Spinlock::pause(); Spinlock::pause();
} }
} }
@ -117,31 +126,34 @@ public:
ZT_INLINE void erase(const uint64_t key) ZT_INLINE void erase(const uint64_t key)
{ {
std::atomic<uintptr_t> &bucket = m_buckets[(key ^ (key >> 32)) & ZT_TINYMAP_BUCKETS_MASK]; std::atomic<uintptr_t>& bucket = m_buckets[(key ^ (key >> 32)) & ZT_TINYMAP_BUCKETS_MASK];
for(;;) { for (;;) {
uintptr_t vptr = bucket.exchange(ZT_TINYMAP_LOCKED_POINTER, std::memory_order_acquire); uintptr_t vptr = bucket.exchange(ZT_TINYMAP_LOCKED_POINTER, std::memory_order_acquire);
if (likely(vptr != ZT_TINYMAP_LOCKED_POINTER)) { if (likely(vptr != ZT_TINYMAP_LOCKED_POINTER)) {
if (likely(vptr != 0)) { if (likely(vptr != 0)) {
for (typename EV::iterator n(reinterpret_cast<EV *>(vptr)->begin()); n != reinterpret_cast<EV *>(vptr)->end(); ++n) { for (typename EV::iterator n(reinterpret_cast<EV*>(vptr)->begin());
n != reinterpret_cast<EV*>(vptr)->end();
++n) {
if (n->first == key) { if (n->first == key) {
reinterpret_cast<EV *>(vptr)->erase(n); reinterpret_cast<EV*>(vptr)->erase(n);
break; break;
} }
} }
if (reinterpret_cast<EV *>(vptr)->empty()) { if (reinterpret_cast<EV*>(vptr)->empty()) {
delete reinterpret_cast<EV *>(vptr); delete reinterpret_cast<EV*>(vptr);
vptr = 0; vptr = 0;
} }
} }
bucket.store(vptr, std::memory_order_release); bucket.store(vptr, std::memory_order_release);
return; return;
} else { }
else {
Spinlock::pause(); Spinlock::pause();
} }
} }
} }
private: private:
std::atomic<uintptr_t> m_buckets[ZT_TINYMAP_BUCKETS]; std::atomic<uintptr_t> m_buckets[ZT_TINYMAP_BUCKETS];
}; };

View file

@ -12,20 +12,21 @@
/****/ /****/
#include "Topology.hpp" #include "Topology.hpp"
#include "Defaults.hpp" #include "Defaults.hpp"
#include "TrustStore.hpp"
#include "Locator.hpp" #include "Locator.hpp"
#include "TrustStore.hpp"
namespace ZeroTier { namespace ZeroTier {
Topology::Topology(const Context &ctx, const CallContext &cc) : Topology::Topology(const Context& ctx, const CallContext& cc) : m_ctx(ctx)
m_ctx(ctx) {
{} }
SharedPtr< Peer > Topology::add(const CallContext &cc, const SharedPtr< Peer > &peer) SharedPtr<Peer> Topology::add(const CallContext& cc, const SharedPtr<Peer>& peer)
{ {
RWMutex::Lock _l(m_peers_l); RWMutex::Lock _l(m_peers_l);
SharedPtr< Peer > &hp = m_peers[peer->address()]; SharedPtr<Peer>& hp = m_peers[peer->address()];
if (hp) if (hp)
return hp; return hp;
m_loadCached(cc, peer->address(), hp); m_loadCached(cc, peer->address(), hp);
@ -35,13 +36,13 @@ SharedPtr< Peer > Topology::add(const CallContext &cc, const SharedPtr< Peer > &
return peer; return peer;
} }
void Topology::allPeers(Vector< SharedPtr< Peer > > &allPeers, Vector< SharedPtr< Peer > > &rootPeers) const void Topology::allPeers(Vector<SharedPtr<Peer> >& allPeers, Vector<SharedPtr<Peer> >& rootPeers) const
{ {
allPeers.clear(); allPeers.clear();
{ {
RWMutex::RLock l(m_peers_l); RWMutex::RLock l(m_peers_l);
allPeers.reserve(m_peers.size()); allPeers.reserve(m_peers.size());
for (Map< Address, SharedPtr< Peer > >::const_iterator i(m_peers.begin()); i != m_peers.end(); ++i) for (Map<Address, SharedPtr<Peer> >::const_iterator i(m_peers.begin()); i != m_peers.end(); ++i)
allPeers.push_back(i->second); allPeers.push_back(i->second);
} }
{ {
@ -50,15 +51,15 @@ void Topology::allPeers(Vector< SharedPtr< Peer > > &allPeers, Vector< SharedPtr
} }
} }
void Topology::doPeriodicTasks(const CallContext &cc) void Topology::doPeriodicTasks(const CallContext& cc)
{ {
// Get a list of root peer pointer addresses for filtering during peer cleanup. // Get a list of root peer pointer addresses for filtering during peer cleanup.
Vector< uintptr_t > rootLookup; Vector<uintptr_t> rootLookup;
{ {
Mutex::Lock l(m_roots_l); Mutex::Lock l(m_roots_l);
m_rankRoots(); m_rankRoots();
rootLookup.reserve(m_roots.size()); rootLookup.reserve(m_roots.size());
for (Vector< SharedPtr< Peer > >::const_iterator r(m_roots.begin()); r != m_roots.end(); ++r) for (Vector<SharedPtr<Peer> >::const_iterator r(m_roots.begin()); r != m_roots.end(); ++r)
rootLookup.push_back((uintptr_t)r->ptr()); rootLookup.push_back((uintptr_t)r->ptr());
} }
std::sort(rootLookup.begin(), rootLookup.end()); std::sort(rootLookup.begin(), rootLookup.end());
@ -67,22 +68,27 @@ void Topology::doPeriodicTasks(const CallContext &cc)
// m_peers or m_paths for any significant amount of time. This avoids pauses // m_peers or m_paths for any significant amount of time. This avoids pauses
// on nodes with large numbers of peers or paths. // on nodes with large numbers of peers or paths.
{ {
Vector< Address > toDelete; Vector<Address> toDelete;
{ {
RWMutex::RLock l1(m_peers_l); RWMutex::RLock l1(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) {
// TODO: also delete if the peer has not exchanged meaningful communication in a while, such as a network frame or non-trivial control packet. // TODO: also delete if the peer has not exchanged meaningful communication in a while, such as a
if (((cc.ticks - i->second->lastReceive()) > ZT_PEER_ALIVE_TIMEOUT) && (!std::binary_search(rootLookup.begin(), rootLookup.end(), reinterpret_cast<uintptr_t>(i->second.ptr())))) // network frame or non-trivial control packet.
if (((cc.ticks - i->second->lastReceive()) > ZT_PEER_ALIVE_TIMEOUT)
&& (! std::binary_search(
rootLookup.begin(),
rootLookup.end(),
reinterpret_cast<uintptr_t>(i->second.ptr()))))
toDelete.push_back(i->first); toDelete.push_back(i->first);
} }
} }
if (!toDelete.empty()) { if (! toDelete.empty()) {
ZT_SPEW("garbage collecting %u offline or stale peer objects", (unsigned int)toDelete.size()); ZT_SPEW("garbage collecting %u offline or stale peer objects", (unsigned int)toDelete.size());
for (Vector< Address >::iterator i(toDelete.begin()); i != toDelete.end(); ++i) { for (Vector<Address>::iterator i(toDelete.begin()); i != toDelete.end(); ++i) {
SharedPtr< Peer > toSave; SharedPtr<Peer> toSave;
{ {
RWMutex::Lock l1(m_peers_l); RWMutex::Lock l1(m_peers_l);
const Map< Address, SharedPtr< Peer > >::iterator p(m_peers.find(*i)); const Map<Address, SharedPtr<Peer> >::iterator p(m_peers.find(*i));
if (p != m_peers.end()) { if (p != m_peers.end()) {
p->second.swap(toSave); p->second.swap(toSave);
m_peers.erase(p); m_peers.erase(p);
@ -95,45 +101,48 @@ void Topology::doPeriodicTasks(const CallContext &cc)
} }
{ {
Vector< Path * > toDelete; Vector<Path*> toDelete;
{ {
RWMutex::Lock l1(m_paths_l); RWMutex::Lock l1(m_paths_l);
for (Map< Path::Key, SharedPtr< Path > >::iterator i(m_paths.begin()); i != m_paths.end();) { for (Map<Path::Key, SharedPtr<Path> >::iterator i(m_paths.begin()); i != m_paths.end();) {
Path *const d = i->second.weakGC(); Path* const d = i->second.weakGC();
if (likely(d == nullptr)) { if (likely(d == nullptr)) {
++i; ++i;
} else { }
else {
m_paths.erase(i++); m_paths.erase(i++);
try { try {
toDelete.push_back(d); toDelete.push_back(d);
} catch (...) { }
catch (...) {
delete d; delete d;
} }
} }
} }
} }
if (!toDelete.empty()) { if (! toDelete.empty()) {
for (Vector< Path * >::iterator i(toDelete.begin()); i != toDelete.end(); ++i) for (Vector<Path*>::iterator i(toDelete.begin()); i != toDelete.end(); ++i)
delete *i; delete *i;
ZT_SPEW("garbage collected %u orphaned paths", (unsigned int)toDelete.size()); ZT_SPEW("garbage collected %u orphaned paths", (unsigned int)toDelete.size());
} }
} }
} }
void Topology::trustStoreChanged(const CallContext &cc) void Topology::trustStoreChanged(const CallContext& cc)
{ {
Map< Identity, SharedPtr< const Locator > > roots(m_ctx.ts->roots()); Map<Identity, SharedPtr<const Locator> > roots(m_ctx.ts->roots());
Vector< SharedPtr< Peer > > newRootList; Vector<SharedPtr<Peer> > newRootList;
newRootList.reserve(roots.size()); newRootList.reserve(roots.size());
for (Map< Identity, SharedPtr< const Locator > >::const_iterator r(roots.begin()); r != roots.end(); ++r) { for (Map<Identity, SharedPtr<const Locator> >::const_iterator r(roots.begin()); r != roots.end(); ++r) {
SharedPtr< Peer > root(this->peer(cc, r->first.address(), true)); SharedPtr<Peer> root(this->peer(cc, r->first.address(), true));
if (!root) { if (! root) {
root.set(new Peer()); root.set(new Peer());
if (root->init(m_ctx, cc, r->first)) { if (root->init(m_ctx, cc, r->first)) {
root = this->add(cc, root); root = this->add(cc, root);
} else { }
else {
root.zero(); root.zero();
} }
} }
@ -151,16 +160,15 @@ void Topology::trustStoreChanged(const CallContext &cc)
} }
} }
void Topology::saveAll(const CallContext &cc) void Topology::saveAll(const CallContext& cc)
{ {
RWMutex::RLock l(m_peers_l); 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(m_ctx, cc); i->second->save(m_ctx, cc);
} }
struct p_RootRankingComparisonOperator struct p_RootRankingComparisonOperator {
{ ZT_INLINE bool operator()(const SharedPtr<Peer>& a, const SharedPtr<Peer>& b) const noexcept
ZT_INLINE bool operator()(const SharedPtr< Peer > &a, const SharedPtr< Peer > &b) const noexcept
{ {
// Sort roots first in order of which root has spoken most recently, but // Sort roots first in order of which root has spoken most recently, but
// only at a resolution of ZT_PATH_KEEPALIVE_PERIOD/2 units of time. This // only at a resolution of ZT_PATH_KEEPALIVE_PERIOD/2 units of time. This
@ -171,7 +179,8 @@ struct p_RootRankingComparisonOperator
const int64_t blr = b->lastReceive() / (ZT_PATH_KEEPALIVE_PERIOD / 2); const int64_t blr = b->lastReceive() / (ZT_PATH_KEEPALIVE_PERIOD / 2);
if (alr < blr) { if (alr < blr) {
return true; return true;
} else if (blr == alr) { }
else if (blr == alr) {
const int bb = b->latency(); const int bb = b->latency();
if (bb < 0) if (bb < 0)
return true; return true;
@ -188,7 +197,8 @@ void Topology::m_rankRoots()
l_bestRoot.lock(); l_bestRoot.lock();
m_bestRoot.zero(); m_bestRoot.zero();
l_bestRoot.unlock(); l_bestRoot.unlock();
} else { }
else {
std::sort(m_roots.begin(), m_roots.end(), p_RootRankingComparisonOperator()); std::sort(m_roots.begin(), m_roots.end(), p_RootRankingComparisonOperator());
l_bestRoot.lock(); l_bestRoot.lock();
m_bestRoot = m_roots.front(); m_bestRoot = m_roots.front();
@ -196,7 +206,7 @@ void Topology::m_rankRoots()
} }
} }
void Topology::m_loadCached(const CallContext &cc, const Address &zta, SharedPtr< Peer > &peer) void Topology::m_loadCached(const CallContext& cc, const Address& zta, SharedPtr<Peer>& peer)
{ {
// does not require any locks to be held // does not require any locks to be held
@ -204,13 +214,13 @@ void Topology::m_loadCached(const CallContext &cc, const Address &zta, SharedPtr
uint64_t id[2]; uint64_t id[2];
id[0] = zta.toInt(); id[0] = zta.toInt();
id[1] = 0; id[1] = 0;
Vector< uint8_t > data(m_ctx.store->get(cc, ZT_STATE_OBJECT_PEER, id, 1)); Vector<uint8_t> data(m_ctx.store->get(cc, ZT_STATE_OBJECT_PEER, id, 1));
if (data.size() > 8) { if (data.size() > 8) {
const uint8_t *d = data.data(); const uint8_t* d = data.data();
int dl = (int)data.size(); int dl = (int)data.size();
const int64_t ts = (int64_t)Utils::loadBigEndian< uint64_t >(d); const int64_t ts = (int64_t)Utils::loadBigEndian<uint64_t>(d);
Peer *const p = new Peer(); Peer* const p = new Peer();
int n = p->unmarshal(m_ctx, cc.ticks, d + 8, dl - 8); int n = p->unmarshal(m_ctx, cc.ticks, d + 8, dl - 8);
if (n < 0) { if (n < 0) {
delete p; delete p;
@ -222,18 +232,19 @@ void Topology::m_loadCached(const CallContext &cc, const Address &zta, SharedPtr
return; return;
} }
} }
} catch (...) { }
catch (...) {
peer.zero(); peer.zero();
} }
} }
SharedPtr< Peer > Topology::m_peerFromCached(const CallContext &cc, const Address &zta) SharedPtr<Peer> Topology::m_peerFromCached(const CallContext& cc, const Address& zta)
{ {
SharedPtr< Peer > p; SharedPtr<Peer> p;
m_loadCached(cc, zta, p); m_loadCached(cc, zta, p);
if (p) { if (p) {
RWMutex::Lock l(m_peers_l); RWMutex::Lock l(m_peers_l);
SharedPtr< Peer > &hp = m_peers[zta]; SharedPtr<Peer>& hp = m_peers[zta];
if (hp) if (hp)
return hp; return hp;
hp = p; hp = p;
@ -241,11 +252,11 @@ SharedPtr< Peer > Topology::m_peerFromCached(const CallContext &cc, const Addres
return p; return p;
} }
SharedPtr< Path > Topology::m_newPath(const int64_t l, const InetAddress &r, const Path::Key &k) SharedPtr<Path> Topology::m_newPath(const int64_t l, const InetAddress& r, const Path::Key& k)
{ {
SharedPtr< Path > p(new Path(l, r)); SharedPtr<Path> p(new Path(l, r));
RWMutex::Lock lck(m_paths_l); RWMutex::Lock lck(m_paths_l);
SharedPtr< Path > &p2 = m_paths[k]; SharedPtr<Path>& p2 = m_paths[k];
if (p2) if (p2)
return p2; return p2;
p2 = p; p2 = p;

View file

@ -14,21 +14,21 @@
#ifndef ZT_TOPOLOGY_HPP #ifndef ZT_TOPOLOGY_HPP
#define ZT_TOPOLOGY_HPP #define ZT_TOPOLOGY_HPP
#include "Constants.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Identity.hpp"
#include "Peer.hpp"
#include "Path.hpp"
#include "Mutex.hpp"
#include "InetAddress.hpp"
#include "SharedPtr.hpp"
#include "ScopedPtr.hpp"
#include "Fingerprint.hpp"
#include "FCV.hpp"
#include "Certificate.hpp"
#include "Containers.hpp"
#include "Spinlock.hpp"
#include "CallContext.hpp" #include "CallContext.hpp"
#include "Certificate.hpp"
#include "Constants.hpp"
#include "Containers.hpp"
#include "FCV.hpp"
#include "Fingerprint.hpp"
#include "Identity.hpp"
#include "InetAddress.hpp"
#include "Mutex.hpp"
#include "Path.hpp"
#include "Peer.hpp"
#include "ScopedPtr.hpp"
#include "SharedPtr.hpp"
#include "Spinlock.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -37,10 +37,9 @@ class Context;
/** /**
* Database of network topology * Database of network topology
*/ */
class Topology class Topology {
{ public:
public: Topology(const Context& ctx, const CallContext& cc);
Topology(const Context &ctx, const CallContext &cc);
/** /**
* Add peer to database * Add peer to database
@ -51,7 +50,7 @@ public:
* @param peer Peer to add * @param peer Peer to add
* @return New or existing peer * @return New or existing peer
*/ */
SharedPtr< Peer > add(const CallContext &cc, const SharedPtr< Peer > &peer); SharedPtr<Peer> add(const CallContext& cc, const SharedPtr<Peer>& peer);
/** /**
* Get a peer from its address * Get a peer from its address
@ -60,17 +59,17 @@ public:
* @param loadFromCached If false do not load from cache if not in memory (default: true) * @param loadFromCached If false do not load from cache if not in memory (default: true)
* @return Peer or NULL if not found * @return Peer or NULL if not found
*/ */
ZT_INLINE SharedPtr< Peer > peer(const CallContext &cc, const Address &zta, const bool loadFromCached = true) ZT_INLINE SharedPtr<Peer> peer(const CallContext& cc, const Address& zta, const bool loadFromCached = true)
{ {
{ {
RWMutex::RLock l(m_peers_l); RWMutex::RLock l(m_peers_l);
Map< Address, SharedPtr< Peer > >::const_iterator ap(m_peers.find(zta)); Map<Address, SharedPtr<Peer> >::const_iterator ap(m_peers.find(zta));
if (likely(ap != m_peers.end())) if (likely(ap != m_peers.end()))
return ap->second; return ap->second;
} }
if (loadFromCached) if (loadFromCached)
return m_peerFromCached(cc, zta); return m_peerFromCached(cc, zta);
return SharedPtr< Peer >(); return SharedPtr<Peer>();
} }
/** /**
@ -80,12 +79,12 @@ public:
* @param r Remote address * @param r Remote address
* @return Pointer to canonicalized Path object or NULL on error * @return Pointer to canonicalized Path object or NULL on error
*/ */
ZT_INLINE SharedPtr< Path > path(const int64_t l, const InetAddress &r) ZT_INLINE SharedPtr<Path> path(const int64_t l, const InetAddress& r)
{ {
const Path::Key k(r); const Path::Key k(r);
{ {
RWMutex::RLock lck(m_paths_l); RWMutex::RLock lck(m_paths_l);
Map< Path::Key, SharedPtr< Path > >::const_iterator p(m_paths.find(k)); Map<Path::Key, SharedPtr<Path> >::const_iterator p(m_paths.find(k));
if (likely(p != m_paths.end())) if (likely(p != m_paths.end()))
return p->second; return p->second;
} }
@ -97,10 +96,10 @@ public:
* *
* @return Root peer or nullptr if none * @return Root peer or nullptr if none
*/ */
ZT_INLINE SharedPtr< Peer > root() ZT_INLINE SharedPtr<Peer> root()
{ {
l_bestRoot.lock(); // spinlock l_bestRoot.lock(); // spinlock
SharedPtr< Peer > r(m_bestRoot); SharedPtr<Peer> r(m_bestRoot);
l_bestRoot.unlock(); l_bestRoot.unlock();
return r; return r;
} }
@ -110,7 +109,7 @@ public:
* *
* @param root Set to best root or nullptr if none * @param root Set to best root or nullptr if none
*/ */
ZT_INLINE void root(SharedPtr< Peer > &root) ZT_INLINE void root(SharedPtr<Peer>& root)
{ {
l_bestRoot.lock(); // spinlock l_bestRoot.lock(); // spinlock
root = m_bestRoot; root = m_bestRoot;
@ -121,17 +120,17 @@ public:
* @param allPeers Vector to fill with all current peers * @param allPeers Vector to fill with all current peers
* @param rootPeers Vector to fill with peers that are roots * @param rootPeers Vector to fill with peers that are roots
*/ */
void allPeers(Vector< SharedPtr< Peer > > &allPeers, Vector< SharedPtr< Peer > > &rootPeers) const; void allPeers(Vector<SharedPtr<Peer> >& allPeers, Vector<SharedPtr<Peer> >& rootPeers) const;
/** /**
* Do periodic tasks such as database cleanup, cert cleanup, root ranking, etc. * Do periodic tasks such as database cleanup, cert cleanup, root ranking, etc.
*/ */
void doPeriodicTasks(const CallContext &cc); void doPeriodicTasks(const CallContext& cc);
/** /**
* Rank root servers in descending order of quality * Rank root servers in descending order of quality
*/ */
ZT_INLINE void rankRoots(const CallContext &cc) ZT_INLINE void rankRoots(const CallContext& cc)
{ {
Mutex::Lock l(m_roots_l); Mutex::Lock l(m_roots_l);
m_rankRoots(); m_rankRoots();
@ -140,30 +139,30 @@ public:
/** /**
* Perform internal updates based on changes in the trust store * Perform internal updates based on changes in the trust store
*/ */
void trustStoreChanged(const CallContext &cc); void trustStoreChanged(const CallContext& cc);
/** /**
* Save all currently known peers to data store * Save all currently known peers to data store
*/ */
void saveAll(const CallContext &cc); void saveAll(const CallContext& cc);
private: private:
void m_rankRoots(); void m_rankRoots();
void m_loadCached(const CallContext &cc, const Address &zta, SharedPtr< Peer > &peer); void m_loadCached(const CallContext& cc, const Address& zta, SharedPtr<Peer>& peer);
SharedPtr< Peer > m_peerFromCached(const CallContext &cc, const Address &zta); SharedPtr<Peer> m_peerFromCached(const CallContext& cc, const Address& zta);
SharedPtr< Path > m_newPath(int64_t l, const InetAddress &r, const Path::Key &k); SharedPtr<Path> m_newPath(int64_t l, const InetAddress& r, const Path::Key& k);
const Context &m_ctx; const Context& m_ctx;
Vector< SharedPtr< Peer > > m_roots; Vector<SharedPtr<Peer> > m_roots;
Map< Address, SharedPtr< Peer > > m_peers; Map<Address, SharedPtr<Peer> > m_peers;
Map< Path::Key, SharedPtr< Path > > m_paths; Map<Path::Key, SharedPtr<Path> > m_paths;
RWMutex m_peers_l; // m_peers RWMutex m_peers_l; // m_peers
RWMutex m_paths_l; // m_paths RWMutex m_paths_l; // m_paths
Mutex m_roots_l; // m_roots Mutex m_roots_l; // m_roots
SharedPtr< Peer > m_bestRoot; SharedPtr<Peer> m_bestRoot;
Spinlock l_bestRoot; Spinlock l_bestRoot;
}; };

View file

@ -12,28 +12,24 @@
/****/ /****/
#include "Trace.hpp" #include "Trace.hpp"
#include "Context.hpp" #include "Context.hpp"
#include "FCV.hpp"
#include "InetAddress.hpp"
#include "Node.hpp" #include "Node.hpp"
#include "Peer.hpp" #include "Peer.hpp"
#include "InetAddress.hpp"
#include "FCV.hpp"
// NOTE: packet IDs are always handled in network byte order, so no need to convert them. // NOTE: packet IDs are always handled in network byte order, so no need to convert them.
namespace ZeroTier { namespace ZeroTier {
Trace::Trace(const Context &ctx) : Trace::Trace(const Context& ctx) : m_ctx(ctx), m_traceFlags(0)
m_ctx(ctx),
m_traceFlags(0)
{}
void Trace::unexpectedError(
const CallContext &cc,
uint32_t codeLocation,
const char *message,
...)
{ {
FCV< uint8_t, 4096 > buf; }
void Trace::unexpectedError(const CallContext& cc, uint32_t codeLocation, const char* message, ...)
{
FCV<uint8_t, 4096> buf;
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_UNEXPECTED_ERROR); Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_UNEXPECTED_ERROR);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::append(buf, ZT_TRACE_FIELD_MESSAGE, message); Dictionary::append(buf, ZT_TRACE_FIELD_MESSAGE, message);
@ -42,15 +38,15 @@ void Trace::unexpectedError(
} }
void Trace::m_resettingPathsInScope( void Trace::m_resettingPathsInScope(
void *tPtr, void* tPtr,
uint32_t codeLocation, uint32_t codeLocation,
const Identity &reporter, const Identity& reporter,
const InetAddress &from, const InetAddress& from,
const InetAddress &oldExternal, const InetAddress& oldExternal,
const InetAddress &newExternal, const InetAddress& newExternal,
ZT_InetAddress_IpScope scope) ZT_InetAddress_IpScope scope)
{ {
FCV< uint8_t, 4096 > buf; FCV<uint8_t, 4096> buf;
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE); Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_RESETTING_PATHS_IN_SCOPE);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
if (reporter) if (reporter)
@ -67,17 +63,17 @@ void Trace::m_resettingPathsInScope(
} }
void Trace::m_tryingNewPath( void Trace::m_tryingNewPath(
void *tPtr, void* tPtr,
uint32_t codeLocation, uint32_t codeLocation,
const Identity &trying, const Identity& trying,
const InetAddress &physicalAddress, const InetAddress& physicalAddress,
const InetAddress &triggerAddress, const InetAddress& triggerAddress,
uint64_t triggeringPacketId, uint64_t triggeringPacketId,
uint8_t triggeringPacketVerb, uint8_t triggeringPacketVerb,
const Identity &triggeringPeer) const Identity& triggeringPeer)
{ {
if ((trying)&&(physicalAddress)) { if ((trying) && (physicalAddress)) {
FCV< uint8_t, 4096 > buf; FCV<uint8_t, 4096> buf;
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_TRYING_NEW_PATH); Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_TRYING_NEW_PATH);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, trying.fingerprint()); Dictionary::appendObject(buf, ZT_TRACE_FIELD_IDENTITY_FINGERPRINT, trying.fingerprint());
@ -94,15 +90,15 @@ void Trace::m_tryingNewPath(
} }
void Trace::m_learnedNewPath( void Trace::m_learnedNewPath(
void *tPtr, void* tPtr,
uint32_t codeLocation, uint32_t codeLocation,
uint64_t packetId, uint64_t packetId,
const Identity &peerIdentity, const Identity& peerIdentity,
const InetAddress &physicalAddress, const InetAddress& physicalAddress,
const InetAddress &replaced) const InetAddress& replaced)
{ {
if (peerIdentity) { if (peerIdentity) {
FCV< uint8_t, 4096 > buf; FCV<uint8_t, 4096> buf;
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_LEARNED_NEW_PATH); Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_LEARNED_NEW_PATH);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_PACKET_ID, packetId); Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_PACKET_ID, packetId);
@ -117,17 +113,17 @@ void Trace::m_learnedNewPath(
} }
void Trace::m_incomingPacketDropped( void Trace::m_incomingPacketDropped(
void *tPtr, void* tPtr,
uint32_t codeLocation, uint32_t codeLocation,
uint64_t packetId, uint64_t packetId,
uint64_t networkId, uint64_t networkId,
const Identity &peerIdentity, const Identity& peerIdentity,
const InetAddress &physicalAddress, const InetAddress& physicalAddress,
uint8_t hops, uint8_t hops,
uint8_t verb, uint8_t verb,
ZT_TracePacketDropReason reason) ZT_TracePacketDropReason reason)
{ {
FCV< uint8_t, 4096 > buf; FCV<uint8_t, 4096> buf;
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_INCOMING_PACKET_DROPPED); Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_INCOMING_PACKET_DROPPED);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_PACKET_ID, packetId); Dictionary::appendPacketId(buf, ZT_TRACE_FIELD_PACKET_ID, packetId);
@ -144,17 +140,17 @@ void Trace::m_incomingPacketDropped(
} }
void Trace::m_outgoingNetworkFrameDropped( void Trace::m_outgoingNetworkFrameDropped(
void *tPtr, void* tPtr,
uint32_t codeLocation, uint32_t codeLocation,
uint64_t networkId, uint64_t networkId,
const MAC &sourceMac, const MAC& sourceMac,
const MAC &destMac, const MAC& destMac,
uint16_t etherType, uint16_t etherType,
uint16_t frameLength, uint16_t frameLength,
const uint8_t *frameData, const uint8_t* frameData,
ZT_TraceFrameDropReason reason) ZT_TraceFrameDropReason reason)
{ {
FCV< uint8_t, 4096 > buf; FCV<uint8_t, 4096> buf;
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_INCOMING_PACKET_DROPPED); Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL1_INCOMING_PACKET_DROPPED);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId);
@ -163,29 +159,33 @@ void Trace::m_outgoingNetworkFrameDropped(
Dictionary::append(buf, ZT_TRACE_FIELD_ETHERTYPE, etherType); Dictionary::append(buf, ZT_TRACE_FIELD_ETHERTYPE, etherType);
Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_LENGTH, frameLength); Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_LENGTH, frameLength);
if (frameData) if (frameData)
Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_DATA, frameData, std::min((unsigned int)64, (unsigned int)frameLength)); Dictionary::append(
buf,
ZT_TRACE_FIELD_FRAME_DATA,
frameData,
std::min((unsigned int)64, (unsigned int)frameLength));
Dictionary::append(buf, ZT_TRACE_FIELD_REASON, reason); Dictionary::append(buf, ZT_TRACE_FIELD_REASON, reason);
buf.push_back(0); buf.push_back(0);
m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data());
} }
void Trace::m_incomingNetworkFrameDropped( void Trace::m_incomingNetworkFrameDropped(
void *tPtr, void* tPtr,
uint32_t codeLocation, uint32_t codeLocation,
uint64_t networkId, uint64_t networkId,
const MAC &sourceMac, const MAC& sourceMac,
const MAC &destMac, const MAC& destMac,
const uint16_t etherType, const uint16_t etherType,
const Identity &peerIdentity, const Identity& peerIdentity,
const InetAddress &physicalAddress, const InetAddress& physicalAddress,
uint8_t hops, uint8_t hops,
uint16_t frameLength, uint16_t frameLength,
const uint8_t *frameData, const uint8_t* frameData,
uint8_t verb, uint8_t verb,
bool credentialRequestSent, bool credentialRequestSent,
ZT_TraceFrameDropReason reason) ZT_TraceFrameDropReason reason)
{ {
FCV< uint8_t, 4096 > buf; FCV<uint8_t, 4096> buf;
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_INCOMING_FRAME_DROPPED); Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_INCOMING_FRAME_DROPPED);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId);
@ -199,19 +199,20 @@ void Trace::m_incomingNetworkFrameDropped(
Dictionary::append(buf, ZT_TRACE_FIELD_PACKET_VERB, verb); Dictionary::append(buf, ZT_TRACE_FIELD_PACKET_VERB, verb);
Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_LENGTH, frameLength); Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_LENGTH, frameLength);
if (frameData) if (frameData)
Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_DATA, frameData, std::min((unsigned int)64, (unsigned int)frameLength)); Dictionary::append(
buf,
ZT_TRACE_FIELD_FRAME_DATA,
frameData,
std::min((unsigned int)64, (unsigned int)frameLength));
Dictionary::append(buf, ZT_TRACE_FIELD_FLAG_CREDENTIAL_REQUEST_SENT, credentialRequestSent); Dictionary::append(buf, ZT_TRACE_FIELD_FLAG_CREDENTIAL_REQUEST_SENT, credentialRequestSent);
Dictionary::append(buf, ZT_TRACE_FIELD_REASON, reason); Dictionary::append(buf, ZT_TRACE_FIELD_REASON, reason);
buf.push_back(0); buf.push_back(0);
m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data()); m_ctx.node->postEvent(tPtr, ZT_EVENT_TRACE, buf.data());
} }
void Trace::m_networkConfigRequestSent( void Trace::m_networkConfigRequestSent(void* tPtr, uint32_t codeLocation, uint64_t networkId)
void *tPtr,
uint32_t codeLocation,
uint64_t networkId)
{ {
FCV< uint8_t, 4096 > buf; FCV<uint8_t, 4096> buf;
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED); Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_NETWORK_CONFIG_REQUESTED);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId);
@ -220,32 +221,32 @@ void Trace::m_networkConfigRequestSent(
} }
void Trace::m_networkFilter( void Trace::m_networkFilter(
void *tPtr, void* tPtr,
uint32_t codeLocation, uint32_t codeLocation,
uint64_t networkId, uint64_t networkId,
const uint8_t *primaryRuleSetLog, const uint8_t* primaryRuleSetLog,
const uint8_t *matchingCapabilityRuleSetLog, const uint8_t* matchingCapabilityRuleSetLog,
uint32_t matchingCapabilityId, uint32_t matchingCapabilityId,
int64_t matchingCapabilityTimestamp, int64_t matchingCapabilityTimestamp,
const Address &source, const Address& source,
const Address &dest, const Address& dest,
const MAC &sourceMac, const MAC& sourceMac,
const MAC &destMac, const MAC& destMac,
uint16_t frameLength, uint16_t frameLength,
const uint8_t *frameData, const uint8_t* frameData,
uint16_t etherType, uint16_t etherType,
uint16_t vlanId, uint16_t vlanId,
bool noTee, bool noTee,
bool inbound, bool inbound,
int accept) int accept)
{ {
FCV< uint8_t, 4096 > buf; FCV<uint8_t, 4096> buf;
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_NETWORK_FILTER); Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_NETWORK_FILTER);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId);
if ((primaryRuleSetLog) && (!Utils::allZero(primaryRuleSetLog, 512))) if ((primaryRuleSetLog) && (! Utils::allZero(primaryRuleSetLog, 512)))
Dictionary::append(buf, ZT_TRACE_FIELD_PRIMARY_RULE_SET_LOG, primaryRuleSetLog, 512); Dictionary::append(buf, ZT_TRACE_FIELD_PRIMARY_RULE_SET_LOG, primaryRuleSetLog, 512);
if ((matchingCapabilityRuleSetLog) && (!Utils::allZero(matchingCapabilityRuleSetLog, 512))) if ((matchingCapabilityRuleSetLog) && (! Utils::allZero(matchingCapabilityRuleSetLog, 512)))
Dictionary::append(buf, ZT_TRACE_FIELD_MATCHING_CAPABILITY_RULE_SET_LOG, matchingCapabilityRuleSetLog, 512); Dictionary::append(buf, ZT_TRACE_FIELD_MATCHING_CAPABILITY_RULE_SET_LOG, matchingCapabilityRuleSetLog, 512);
Dictionary::append(buf, ZT_TRACE_FIELD_MATCHING_CAPABILITY_ID, matchingCapabilityId); Dictionary::append(buf, ZT_TRACE_FIELD_MATCHING_CAPABILITY_ID, matchingCapabilityId);
Dictionary::append(buf, ZT_TRACE_FIELD_MATCHING_CAPABILITY_TIMESTAMP, matchingCapabilityTimestamp); Dictionary::append(buf, ZT_TRACE_FIELD_MATCHING_CAPABILITY_TIMESTAMP, matchingCapabilityTimestamp);
@ -255,7 +256,11 @@ void Trace::m_networkFilter(
Dictionary::append(buf, ZT_TRACE_FIELD_DEST_MAC, destMac.toInt()); Dictionary::append(buf, ZT_TRACE_FIELD_DEST_MAC, destMac.toInt());
Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_LENGTH, frameLength); Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_LENGTH, frameLength);
if (frameData) if (frameData)
Dictionary::append(buf, ZT_TRACE_FIELD_FRAME_DATA, frameData, std::min((unsigned int)64, (unsigned int)frameLength)); Dictionary::append(
buf,
ZT_TRACE_FIELD_FRAME_DATA,
frameData,
std::min((unsigned int)64, (unsigned int)frameLength));
Dictionary::append(buf, ZT_TRACE_FIELD_ETHERTYPE, etherType); Dictionary::append(buf, ZT_TRACE_FIELD_ETHERTYPE, etherType);
Dictionary::append(buf, ZT_TRACE_FIELD_VLAN_ID, vlanId); Dictionary::append(buf, ZT_TRACE_FIELD_VLAN_ID, vlanId);
Dictionary::append(buf, ZT_TRACE_FIELD_RULE_FLAG_NOTEE, noTee); Dictionary::append(buf, ZT_TRACE_FIELD_RULE_FLAG_NOTEE, noTee);
@ -266,16 +271,16 @@ void Trace::m_networkFilter(
} }
void Trace::m_credentialRejected( void Trace::m_credentialRejected(
void *tPtr, void* tPtr,
uint32_t codeLocation, uint32_t codeLocation,
uint64_t networkId, uint64_t networkId,
const Identity &identity, const Identity& identity,
uint32_t credentialId, uint32_t credentialId,
int64_t credentialTimestamp, int64_t credentialTimestamp,
uint8_t credentialType, uint8_t credentialType,
ZT_TraceCredentialRejectionReason reason) ZT_TraceCredentialRejectionReason reason)
{ {
FCV< uint8_t, 4096 > buf; FCV<uint8_t, 4096> buf;
Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_NETWORK_CREDENTIAL_REJECTED); Dictionary::append(buf, ZT_TRACE_FIELD_TYPE, ZT_TRACE_VL2_NETWORK_CREDENTIAL_REJECTED);
Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation); Dictionary::append(buf, ZT_TRACE_FIELD_CODE_LOCATION, codeLocation);
Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId); Dictionary::append(buf, ZT_TRACE_FIELD_NETWORK_ID, networkId);

View file

@ -14,15 +14,15 @@
#ifndef ZT_TRACE_HPP #ifndef ZT_TRACE_HPP
#define ZT_TRACE_HPP #define ZT_TRACE_HPP
#include "Constants.hpp"
#include "SharedPtr.hpp"
#include "Mutex.hpp"
#include "InetAddress.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "MAC.hpp"
#include "Containers.hpp"
#include "Utils.hpp"
#include "CallContext.hpp" #include "CallContext.hpp"
#include "Constants.hpp"
#include "Containers.hpp"
#include "InetAddress.hpp"
#include "MAC.hpp"
#include "Mutex.hpp"
#include "SharedPtr.hpp"
#include "Utils.hpp"
#define ZT_TRACE_F_VL1 0x01U #define ZT_TRACE_F_VL1 0x01U
#define ZT_TRACE_F_VL2 0x02U #define ZT_TRACE_F_VL2 0x02U
@ -56,38 +56,38 @@ struct NetworkConfig;
* turned into constants that are semi-official and stored in a database to * turned into constants that are semi-official and stored in a database to
* provide extra debug context. * provide extra debug context.
*/ */
class Trace class Trace {
{ public:
public: struct RuleResultLog : public TriviallyCopyable {
struct RuleResultLog : public TriviallyCopyable
{
uint8_t l[ZT_MAX_NETWORK_RULES / 2]; // ZT_MAX_NETWORK_RULES 4-bit fields uint8_t l[ZT_MAX_NETWORK_RULES / 2]; // ZT_MAX_NETWORK_RULES 4-bit fields
ZT_INLINE void log(const unsigned int rn, const uint8_t thisRuleMatches, const uint8_t thisSetMatches) noexcept ZT_INLINE void log(const unsigned int rn, const uint8_t thisRuleMatches, const uint8_t thisSetMatches) noexcept
{ l[rn >> 1U] |= (((thisRuleMatches + 1U) << 2U) | (thisSetMatches + 1U)) << ((rn & 1U) << 2U); } {
l[rn >> 1U] |= (((thisRuleMatches + 1U) << 2U) | (thisSetMatches + 1U)) << ((rn & 1U) << 2U);
}
ZT_INLINE void logSkipped(const unsigned int rn, const uint8_t thisSetMatches) noexcept ZT_INLINE void logSkipped(const unsigned int rn, const uint8_t thisSetMatches) noexcept
{ l[rn >> 1U] |= (thisSetMatches + 1U) << ((rn & 1U) << 2U); } {
l[rn >> 1U] |= (thisSetMatches + 1U) << ((rn & 1U) << 2U);
}
ZT_INLINE void clear() noexcept ZT_INLINE void clear() noexcept
{ memoryZero(this); } {
memoryZero(this);
}
}; };
explicit Trace(const Context &ctx); explicit Trace(const Context& ctx);
void unexpectedError( void unexpectedError(const CallContext& cc, uint32_t codeLocation, const char* message, ...);
const CallContext &cc,
uint32_t codeLocation,
const char *message,
...);
ZT_INLINE void resettingPathsInScope( ZT_INLINE void resettingPathsInScope(
const CallContext &cc, const CallContext& cc,
const uint32_t codeLocation, const uint32_t codeLocation,
const Identity &reporter, const Identity& reporter,
const InetAddress &from, const InetAddress& from,
const InetAddress &oldExternal, const InetAddress& oldExternal,
const InetAddress &newExternal, const InetAddress& newExternal,
const InetAddress::IpScope scope) const InetAddress::IpScope scope)
{ {
if (unlikely((m_traceFlags & ZT_TRACE_F_VL1) != 0)) if (unlikely((m_traceFlags & ZT_TRACE_F_VL1) != 0))
@ -95,104 +95,141 @@ public:
} }
ZT_INLINE void tryingNewPath( ZT_INLINE void tryingNewPath(
const CallContext &cc, const CallContext& cc,
const uint32_t codeLocation, const uint32_t codeLocation,
const Identity &trying, const Identity& trying,
const InetAddress &physicalAddress, const InetAddress& physicalAddress,
const InetAddress &triggerAddress, const InetAddress& triggerAddress,
uint64_t triggeringPacketId, uint64_t triggeringPacketId,
uint8_t triggeringPacketVerb, uint8_t triggeringPacketVerb,
const Identity &triggeringPeer) const Identity& triggeringPeer)
{ {
if (unlikely((m_traceFlags & ZT_TRACE_F_VL1) != 0)) if (unlikely((m_traceFlags & ZT_TRACE_F_VL1) != 0))
m_tryingNewPath(cc.tPtr, codeLocation, trying, physicalAddress, triggerAddress, triggeringPacketId, triggeringPacketVerb, triggeringPeer); m_tryingNewPath(
cc.tPtr,
codeLocation,
trying,
physicalAddress,
triggerAddress,
triggeringPacketId,
triggeringPacketVerb,
triggeringPeer);
} }
ZT_INLINE void learnedNewPath( ZT_INLINE void learnedNewPath(
const CallContext &cc, const CallContext& cc,
const uint32_t codeLocation, const uint32_t codeLocation,
uint64_t packetId, uint64_t packetId,
const Identity &peerIdentity, const Identity& peerIdentity,
const InetAddress &physicalAddress, const InetAddress& physicalAddress,
const InetAddress &replaced) const InetAddress& replaced)
{ {
if (unlikely((m_traceFlags & ZT_TRACE_F_VL1) != 0)) if (unlikely((m_traceFlags & ZT_TRACE_F_VL1) != 0))
m_learnedNewPath(cc.tPtr, codeLocation, packetId, peerIdentity, physicalAddress, replaced); m_learnedNewPath(cc.tPtr, codeLocation, packetId, peerIdentity, physicalAddress, replaced);
} }
ZT_INLINE void incomingPacketDropped( ZT_INLINE void incomingPacketDropped(
const CallContext &cc, const CallContext& cc,
const uint32_t codeLocation, const uint32_t codeLocation,
uint64_t packetId, uint64_t packetId,
uint64_t networkId, uint64_t networkId,
const Identity &peerIdentity, const Identity& peerIdentity,
const InetAddress &physicalAddress, const InetAddress& physicalAddress,
uint8_t hops, uint8_t hops,
uint8_t verb, uint8_t verb,
const ZT_TracePacketDropReason reason) const ZT_TracePacketDropReason reason)
{ {
if (unlikely((m_traceFlags & ZT_TRACE_F_VL1) != 0)) if (unlikely((m_traceFlags & ZT_TRACE_F_VL1) != 0))
m_incomingPacketDropped(cc.tPtr, codeLocation, packetId, networkId, peerIdentity, physicalAddress, hops, verb, reason); m_incomingPacketDropped(
cc.tPtr,
codeLocation,
packetId,
networkId,
peerIdentity,
physicalAddress,
hops,
verb,
reason);
} }
ZT_INLINE void outgoingNetworkFrameDropped( ZT_INLINE void outgoingNetworkFrameDropped(
const CallContext &cc, const CallContext& cc,
const uint32_t codeLocation, const uint32_t codeLocation,
uint64_t networkId, uint64_t networkId,
const MAC &sourceMac, const MAC& sourceMac,
const MAC &destMac, const MAC& destMac,
uint16_t etherType, uint16_t etherType,
uint16_t frameLength, uint16_t frameLength,
const uint8_t *frameData, const uint8_t* frameData,
ZT_TraceFrameDropReason reason) ZT_TraceFrameDropReason reason)
{ {
if (unlikely((m_traceFlags & ZT_TRACE_F_VL2) != 0)) if (unlikely((m_traceFlags & ZT_TRACE_F_VL2) != 0))
m_outgoingNetworkFrameDropped(cc.tPtr, codeLocation, networkId, sourceMac, destMac, etherType, frameLength, frameData, reason); m_outgoingNetworkFrameDropped(
cc.tPtr,
codeLocation,
networkId,
sourceMac,
destMac,
etherType,
frameLength,
frameData,
reason);
} }
ZT_INLINE void incomingNetworkFrameDropped( ZT_INLINE void incomingNetworkFrameDropped(
const CallContext &cc, const CallContext& cc,
const uint32_t codeLocation, const uint32_t codeLocation,
uint64_t networkId, uint64_t networkId,
const MAC &sourceMac, const MAC& sourceMac,
const MAC &destMac, const MAC& destMac,
const uint16_t etherType, const uint16_t etherType,
const Identity &peerIdentity, const Identity& peerIdentity,
const InetAddress &physicalAddress, const InetAddress& physicalAddress,
uint8_t hops, uint8_t hops,
uint16_t frameLength, uint16_t frameLength,
const uint8_t *frameData, const uint8_t* frameData,
uint8_t verb, uint8_t verb,
bool credentialRequestSent, bool credentialRequestSent,
ZT_TraceFrameDropReason reason) ZT_TraceFrameDropReason reason)
{ {
if (unlikely((m_traceFlags & ZT_TRACE_F_VL2) != 0)) if (unlikely((m_traceFlags & ZT_TRACE_F_VL2) != 0))
m_incomingNetworkFrameDropped(cc.tPtr, codeLocation, networkId, sourceMac, destMac, etherType, peerIdentity, physicalAddress, hops, frameLength, frameData, verb, credentialRequestSent, reason); m_incomingNetworkFrameDropped(
cc.tPtr,
codeLocation,
networkId,
sourceMac,
destMac,
etherType,
peerIdentity,
physicalAddress,
hops,
frameLength,
frameData,
verb,
credentialRequestSent,
reason);
} }
ZT_INLINE void networkConfigRequestSent( ZT_INLINE void networkConfigRequestSent(const CallContext& cc, const uint32_t codeLocation, uint64_t networkId)
const CallContext &cc,
const uint32_t codeLocation,
uint64_t networkId)
{ {
if (unlikely((m_traceFlags & ZT_TRACE_F_VL2) != 0)) if (unlikely((m_traceFlags & ZT_TRACE_F_VL2) != 0))
m_networkConfigRequestSent(cc.tPtr, codeLocation, networkId); m_networkConfigRequestSent(cc.tPtr, codeLocation, networkId);
} }
ZT_INLINE void networkFilter( ZT_INLINE void networkFilter(
const CallContext &cc, const CallContext& cc,
const uint32_t codeLocation, const uint32_t codeLocation,
uint64_t networkId, uint64_t networkId,
const uint8_t primaryRuleSetLog[512], const uint8_t primaryRuleSetLog[512],
const uint8_t matchingCapabilityRuleSetLog[512], const uint8_t matchingCapabilityRuleSetLog[512],
uint32_t matchingCapabilityId, uint32_t matchingCapabilityId,
int64_t matchingCapabilityTimestamp, int64_t matchingCapabilityTimestamp,
const Address &source, const Address& source,
const Address &dest, const Address& dest,
const MAC &sourceMac, const MAC& sourceMac,
const MAC &destMac, const MAC& destMac,
uint16_t frameLength, uint16_t frameLength,
const uint8_t *frameData, const uint8_t* frameData,
uint16_t etherType, uint16_t etherType,
uint16_t vlanId, uint16_t vlanId,
bool noTee, bool noTee,
@ -223,104 +260,109 @@ public:
} }
ZT_INLINE void credentialRejected( ZT_INLINE void credentialRejected(
const CallContext &cc, const CallContext& cc,
const uint32_t codeLocation, const uint32_t codeLocation,
uint64_t networkId, uint64_t networkId,
const Identity &identity, const Identity& identity,
uint32_t credentialId, uint32_t credentialId,
int64_t credentialTimestamp, int64_t credentialTimestamp,
uint8_t credentialType, uint8_t credentialType,
ZT_TraceCredentialRejectionReason reason) ZT_TraceCredentialRejectionReason reason)
{ {
if (unlikely((m_traceFlags & ZT_TRACE_F_VL2) != 0)) if (unlikely((m_traceFlags & ZT_TRACE_F_VL2) != 0))
m_credentialRejected(cc.tPtr, codeLocation, networkId, identity, credentialId, credentialTimestamp, credentialType, reason); m_credentialRejected(
cc.tPtr,
codeLocation,
networkId,
identity,
credentialId,
credentialTimestamp,
credentialType,
reason);
} }
private: private:
void m_resettingPathsInScope( void m_resettingPathsInScope(
void *tPtr, void* tPtr,
uint32_t codeLocation, uint32_t codeLocation,
const Identity &reporter, const Identity& reporter,
const InetAddress &from, const InetAddress& from,
const InetAddress &oldExternal, const InetAddress& oldExternal,
const InetAddress &newExternal, const InetAddress& newExternal,
InetAddress::IpScope scope); InetAddress::IpScope scope);
void m_tryingNewPath( void m_tryingNewPath(
void *tPtr, void* tPtr,
uint32_t codeLocation, uint32_t codeLocation,
const Identity &trying, const Identity& trying,
const InetAddress &physicalAddress, const InetAddress& physicalAddress,
const InetAddress &triggerAddress, const InetAddress& triggerAddress,
uint64_t triggeringPacketId, uint64_t triggeringPacketId,
uint8_t triggeringPacketVerb, uint8_t triggeringPacketVerb,
const Identity &triggeringPeer); const Identity& triggeringPeer);
void m_learnedNewPath( void m_learnedNewPath(
void *tPtr, void* tPtr,
uint32_t codeLocation, uint32_t codeLocation,
uint64_t packetId, uint64_t packetId,
const Identity &peerIdentity, const Identity& peerIdentity,
const InetAddress &physicalAddress, const InetAddress& physicalAddress,
const InetAddress &replaced); const InetAddress& replaced);
void m_incomingPacketDropped( void m_incomingPacketDropped(
void *tPtr, void* tPtr,
uint32_t codeLocation, uint32_t codeLocation,
uint64_t packetId, uint64_t packetId,
uint64_t networkId, uint64_t networkId,
const Identity &peerIdentity, const Identity& peerIdentity,
const InetAddress &physicalAddress, const InetAddress& physicalAddress,
uint8_t hops, uint8_t hops,
uint8_t verb, uint8_t verb,
ZT_TracePacketDropReason reason); ZT_TracePacketDropReason reason);
void m_outgoingNetworkFrameDropped( void m_outgoingNetworkFrameDropped(
void *tPtr, void* tPtr,
uint32_t codeLocation, uint32_t codeLocation,
uint64_t networkId, uint64_t networkId,
const MAC &sourceMac, const MAC& sourceMac,
const MAC &destMac, const MAC& destMac,
uint16_t etherType, uint16_t etherType,
uint16_t frameLength, uint16_t frameLength,
const uint8_t *frameData, const uint8_t* frameData,
ZT_TraceFrameDropReason reason); ZT_TraceFrameDropReason reason);
void m_incomingNetworkFrameDropped( void m_incomingNetworkFrameDropped(
void *tPtr, void* tPtr,
uint32_t codeLocation, uint32_t codeLocation,
uint64_t networkId, uint64_t networkId,
const MAC &sourceMac, const MAC& sourceMac,
const MAC &destMac, const MAC& destMac,
const uint16_t etherType, const uint16_t etherType,
const Identity &peerIdentity, const Identity& peerIdentity,
const InetAddress &physicalAddress, const InetAddress& physicalAddress,
uint8_t hops, uint8_t hops,
uint16_t frameLength, uint16_t frameLength,
const uint8_t *frameData, const uint8_t* frameData,
uint8_t verb, uint8_t verb,
bool credentialRequestSent, bool credentialRequestSent,
ZT_TraceFrameDropReason reason); ZT_TraceFrameDropReason reason);
void m_networkConfigRequestSent( void m_networkConfigRequestSent(void* tPtr, uint32_t codeLocation, uint64_t networkId);
void *tPtr,
uint32_t codeLocation,
uint64_t networkId);
void m_networkFilter( void m_networkFilter(
void *tPtr, void* tPtr,
uint32_t codeLocation, uint32_t codeLocation,
uint64_t networkId, uint64_t networkId,
const uint8_t *primaryRuleSetLog, const uint8_t* primaryRuleSetLog,
const uint8_t *matchingCapabilityRuleSetLog, const uint8_t* matchingCapabilityRuleSetLog,
uint32_t matchingCapabilityId, uint32_t matchingCapabilityId,
int64_t matchingCapabilityTimestamp, int64_t matchingCapabilityTimestamp,
const Address &source, const Address& source,
const Address &dest, const Address& dest,
const MAC &sourceMac, const MAC& sourceMac,
const MAC &destMac, const MAC& destMac,
uint16_t frameLength, uint16_t frameLength,
const uint8_t *frameData, const uint8_t* frameData,
uint16_t etherType, uint16_t etherType,
uint16_t vlanId, uint16_t vlanId,
bool noTee, bool noTee,
@ -328,16 +370,16 @@ private:
int accept); int accept);
void m_credentialRejected( void m_credentialRejected(
void *tPtr, void* tPtr,
uint32_t codeLocation, uint32_t codeLocation,
uint64_t networkId, uint64_t networkId,
const Identity &identity, const Identity& identity,
uint32_t credentialId, uint32_t credentialId,
int64_t credentialTimestamp, int64_t credentialTimestamp,
uint8_t credentialType, uint8_t credentialType,
ZT_TraceCredentialRejectionReason reason); ZT_TraceCredentialRejectionReason reason);
const Context &m_ctx; const Context& m_ctx;
volatile unsigned int m_traceFlags; // faster than atomic, but may not "instantly" change... should be okay volatile unsigned int m_traceFlags; // faster than atomic, but may not "instantly" change... should be okay
}; };

View file

@ -24,17 +24,15 @@ namespace ZeroTier {
* *
* It also includes some static methods to do this conveniently. * It also includes some static methods to do this conveniently.
*/ */
struct TriviallyCopyable struct TriviallyCopyable {
{ public:
public:
/** /**
* Zero a TriviallyCopyable object * Zero a TriviallyCopyable object
* *
* @tparam T Automatically inferred type of object * @tparam T Automatically inferred type of object
* @param obj Any TriviallyCopyable object * @param obj Any TriviallyCopyable object
*/ */
template<typename T> template <typename T> static ZT_INLINE void memoryZero(T* obj) noexcept
static ZT_INLINE void memoryZero(T *obj) noexcept
{ {
mustBeTriviallyCopyable(obj); mustBeTriviallyCopyable(obj);
Utils::zero<sizeof(T)>(obj); Utils::zero<sizeof(T)>(obj);
@ -46,16 +44,19 @@ public:
* @tparam T Automatically inferred type of object * @tparam T Automatically inferred type of object
* @param obj Any TriviallyCopyable object * @param obj Any TriviallyCopyable object
*/ */
template<typename T> template <typename T> static ZT_INLINE void memoryZero(T& obj) noexcept
static ZT_INLINE void memoryZero(T &obj) noexcept
{ {
mustBeTriviallyCopyable(obj); mustBeTriviallyCopyable(obj);
Utils::zero<sizeof(T)>(&obj); Utils::zero<sizeof(T)>(&obj);
} }
private: private:
static ZT_INLINE void mustBeTriviallyCopyable(const TriviallyCopyable &) noexcept {} static ZT_INLINE void mustBeTriviallyCopyable(const TriviallyCopyable&) noexcept
static ZT_INLINE void mustBeTriviallyCopyable(const TriviallyCopyable *) noexcept {} {
}
static ZT_INLINE void mustBeTriviallyCopyable(const TriviallyCopyable*) noexcept
{
}
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -12,93 +12,98 @@
/****/ /****/
#include "TrustStore.hpp" #include "TrustStore.hpp"
#include "LZ4.hpp" #include "LZ4.hpp"
namespace ZeroTier { namespace ZeroTier {
TrustStore::TrustStore() TrustStore::TrustStore()
{}
TrustStore::~TrustStore()
{}
SharedPtr< TrustStore::Entry > TrustStore::get(const H384 &serial) const
{ {
RWMutex::RLock l(m_lock);
Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.find(serial));
return (c != m_bySerial.end()) ? c->second : SharedPtr< TrustStore::Entry >();
} }
Map< Identity, SharedPtr< const Locator > > TrustStore::roots() TrustStore::~TrustStore()
{
}
SharedPtr<TrustStore::Entry> TrustStore::get(const H384& serial) const
{ {
RWMutex::RLock l(m_lock); RWMutex::RLock l(m_lock);
Map< Identity, SharedPtr< const Locator > > r; Map<H384, SharedPtr<Entry> >::const_iterator c(m_bySerial.find(serial));
return (c != m_bySerial.end()) ? c->second : SharedPtr<TrustStore::Entry>();
}
Map<Identity, SharedPtr<const Locator> > TrustStore::roots()
{
RWMutex::RLock l(m_lock);
Map<Identity, SharedPtr<const Locator> > r;
// Iterate using m_bySubjectIdentity to only scan certificates with subject identities. // Iterate using m_bySubjectIdentity to only scan certificates with subject identities.
// This map also does not contian error or deprecated certificates. // This map also does not contian error or deprecated certificates.
for (Map< Fingerprint, Vector< SharedPtr< Entry > > >::const_iterator cv(m_bySubjectIdentity.begin()); cv != m_bySubjectIdentity.end(); ++cv) { for (Map<Fingerprint, Vector<SharedPtr<Entry> > >::const_iterator cv(m_bySubjectIdentity.begin());
for (Vector< SharedPtr< Entry > >::const_iterator c(cv->second.begin()); c != cv->second.end(); ++c) { cv != m_bySubjectIdentity.end();
++cv) {
for (Vector<SharedPtr<Entry> >::const_iterator c(cv->second.begin()); c != cv->second.end(); ++c) {
// A root set cert must be marked for this use and authorized to influence this node's config. // A root set cert must be marked for this use and authorized to influence this node's config.
if ((((*c)->m_certificate.usageFlags & ZT_CERTIFICATE_USAGE_ZEROTIER_ROOT_SET) != 0) && (((*c)->m_localTrust & ZT_CERTIFICATE_LOCAL_TRUST_FLAG_CONFIG) != 0)) { if ((((*c)->m_certificate.usageFlags & ZT_CERTIFICATE_USAGE_ZEROTIER_ROOT_SET) != 0)
&& (((*c)->m_localTrust & ZT_CERTIFICATE_LOCAL_TRUST_FLAG_CONFIG) != 0)) {
// Add all identities to the root set, and for each entry in the set make sure we have the latest locator if there's more than one cert with one. // Add all identities to the root set, and for each entry in the set make sure we have the latest
// locator if there's more than one cert with one.
for (unsigned int j = 0; j < (*c)->certificate().subject.identityCount; ++j) { for (unsigned int j = 0; j < (*c)->certificate().subject.identityCount; ++j) {
const Identity *const id = reinterpret_cast<const Identity *>((*c)->certificate().subject.identities[j].identity); const Identity* const id =
reinterpret_cast<const Identity*>((*c)->certificate().subject.identities[j].identity);
if ((id) && (*id)) { // sanity check if ((id) && (*id)) { // sanity check
SharedPtr< const Locator > &existingLoc = r[*id]; SharedPtr<const Locator>& existingLoc = r[*id];
const Locator *const loc = reinterpret_cast<const Locator *>((*c)->certificate().subject.identities[j].locator); const Locator* const loc =
reinterpret_cast<const Locator*>((*c)->certificate().subject.identities[j].locator);
if (loc) { if (loc) {
if ((!existingLoc) || (existingLoc->revision() < loc->revision())) if ((! existingLoc) || (existingLoc->revision() < loc->revision()))
existingLoc.set(new Locator(*loc)); existingLoc.set(new Locator(*loc));
} }
} }
} }
} }
} }
} }
return r; return r;
} }
Vector< SharedPtr< TrustStore::Entry > > TrustStore::all(const bool includeRejectedCertificates) const Vector<SharedPtr<TrustStore::Entry> > TrustStore::all(const bool includeRejectedCertificates) const
{ {
RWMutex::RLock l(m_lock); RWMutex::RLock l(m_lock);
Vector< SharedPtr< Entry > > r; Vector<SharedPtr<Entry> > r;
r.reserve(m_bySerial.size()); r.reserve(m_bySerial.size());
for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { for (Map<H384, SharedPtr<Entry> >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) {
if ((includeRejectedCertificates) || (c->second->error() == ZT_CERTIFICATE_ERROR_NONE)) if ((includeRejectedCertificates) || (c->second->error() == ZT_CERTIFICATE_ERROR_NONE))
r.push_back(c->second); r.push_back(c->second);
} }
return r; return r;
} }
void TrustStore::add(const Certificate &cert, const unsigned int localTrust) void TrustStore::add(const Certificate& cert, const unsigned int localTrust)
{ {
RWMutex::Lock l(m_lock); RWMutex::Lock l(m_lock);
m_addQueue.push_front(SharedPtr< Entry >(new Entry(this->m_lock, cert, localTrust))); m_addQueue.push_front(SharedPtr<Entry>(new Entry(this->m_lock, cert, localTrust)));
} }
void TrustStore::erase(const H384 &serial) void TrustStore::erase(const H384& serial)
{ {
RWMutex::Lock l(m_lock); RWMutex::Lock l(m_lock);
m_deleteQueue.push_front(serial); m_deleteQueue.push_front(serial);
} }
bool TrustStore::update(const int64_t clock, Vector< SharedPtr< Entry > > *const purge) bool TrustStore::update(const int64_t clock, Vector<SharedPtr<Entry> >* const purge)
{ {
RWMutex::Lock l(m_lock); RWMutex::Lock l(m_lock);
// Check for certificate time validity status changes. If any of these occur then // Check for certificate time validity status changes. If any of these occur then
// full re-validation is required. // full re-validation is required.
bool errorStateModified = false; bool errorStateModified = false;
for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { for (Map<H384, SharedPtr<Entry> >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) {
const bool timeValid = c->second->m_certificate.verifyTimeWindow(clock); const bool timeValid = c->second->m_certificate.verifyTimeWindow(clock);
switch (c->second->m_error) { switch (c->second->m_error) {
case ZT_CERTIFICATE_ERROR_NONE: case ZT_CERTIFICATE_ERROR_NONE:
case ZT_CERTIFICATE_ERROR_INVALID_CHAIN: case ZT_CERTIFICATE_ERROR_INVALID_CHAIN:
if (!timeValid) { if (! timeValid) {
c->second->m_error = ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW; c->second->m_error = ZT_CERTIFICATE_ERROR_OUT_OF_VALID_TIME_WINDOW;
errorStateModified = true; errorStateModified = true;
} }
@ -116,28 +121,28 @@ bool TrustStore::update(const int64_t clock, Vector< SharedPtr< Entry > > *const
// If there were not any such changes and if the add and delete queues are empty, // If there were not any such changes and if the add and delete queues are empty,
// there is nothing more to be done. // there is nothing more to be done.
if ((!errorStateModified) && (m_addQueue.empty()) && (m_deleteQueue.empty())) if ((! errorStateModified) && (m_addQueue.empty()) && (m_deleteQueue.empty()))
return false; return false;
// Add new certificates to m_bySerial, which is the master certificate set. They still // Add new certificates to m_bySerial, which is the master certificate set. They still
// have yet to have their full certificate chains validated. Full signature checking is // have yet to have their full certificate chains validated. Full signature checking is
// performed here. // performed here.
while (!m_addQueue.empty()) { while (! m_addQueue.empty()) {
SharedPtr< Entry > &qi = m_addQueue.front(); SharedPtr<Entry>& qi = m_addQueue.front();
qi->m_error = qi->m_certificate.verify(clock, true); qi->m_error = qi->m_certificate.verify(clock, true);
m_bySerial[H384(qi->m_certificate.serialNo)].move(qi); m_bySerial[H384(qi->m_certificate.serialNo)].move(qi);
m_addQueue.pop_front(); m_addQueue.pop_front();
} }
// Delete any certificates enqueued to be deleted. // Delete any certificates enqueued to be deleted.
while (!m_deleteQueue.empty()) { while (! m_deleteQueue.empty()) {
m_bySerial.erase(m_deleteQueue.front()); m_bySerial.erase(m_deleteQueue.front());
m_deleteQueue.pop_front(); m_deleteQueue.pop_front();
} }
// Reset flags for deprecation and a cert being on a trust path, which are // Reset flags for deprecation and a cert being on a trust path, which are
// recomputed when chain and subjects are checked below. // recomputed when chain and subjects are checked below.
for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { for (Map<H384, SharedPtr<Entry> >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) {
if (c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) { if (c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) {
c->second->m_subjectDeprecated = false; c->second->m_subjectDeprecated = false;
c->second->m_onTrustPath = false; c->second->m_onTrustPath = false;
@ -146,44 +151,51 @@ bool TrustStore::update(const int64_t clock, Vector< SharedPtr< Entry > > *const
// Validate certificate trust paths. // Validate certificate trust paths.
{ {
Vector< Entry * > visited; Vector<Entry*> visited;
visited.reserve(8); visited.reserve(8);
for (Map< H384, SharedPtr< Entry > >::iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { for (Map<H384, SharedPtr<Entry> >::iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) {
if ((c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) && (!c->second->m_onTrustPath) && ((c->second->m_localTrust & ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA) == 0)) { if ((c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) && (! c->second->m_onTrustPath)
&& ((c->second->m_localTrust & ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA) == 0)) {
// Trace the path of each certificate all the way back to a trusted CA. // Trace the path of each certificate all the way back to a trusted CA.
unsigned int pathLength = 0; unsigned int pathLength = 0;
Map< H384, SharedPtr< Entry > >::const_iterator current(c); Map<H384, SharedPtr<Entry> >::const_iterator current(c);
visited.clear(); visited.clear();
for (;;) { for (;;) {
if (pathLength <= current->second->m_certificate.maxPathLength) { if (pathLength <= current->second->m_certificate.maxPathLength) {
// Check if this cert isn't a CA or already part of a valid trust path. If so then step upward
// Check if this cert isn't a CA or already part of a valid trust path. If so then step upward toward CA. // toward CA.
if (((current->second->m_localTrust & ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA) == 0) && (!current->second->m_onTrustPath)) { if (((current->second->m_localTrust & ZT_CERTIFICATE_LOCAL_TRUST_FLAG_ROOT_CA) == 0)
// If the issuer (parent) certificiate is (1) valid, (2) not already visited (to prevent loops), && (! current->second->m_onTrustPath)) {
// and (3) has a public key that matches this cert's issuer public key (sanity check), proceed // If the issuer (parent) certificiate is (1) valid, (2) not already visited (to prevent
// up the certificate graph toward a potential CA. // loops), and (3) has a public key that matches this cert's issuer public key (sanity
// check), proceed up the certificate graph toward a potential CA.
visited.push_back(current->second.ptr()); visited.push_back(current->second.ptr());
const Map< H384, SharedPtr< Entry > >::const_iterator prevChild(current); const Map<H384, SharedPtr<Entry> >::const_iterator prevChild(current);
current = m_bySerial.find(H384(current->second->m_certificate.issuer)); current = m_bySerial.find(H384(current->second->m_certificate.issuer));
if ((current != m_bySerial.end()) && if ((current != m_bySerial.end())
(std::find(visited.begin(), visited.end(), current->second.ptr()) == visited.end()) && && (std::find(visited.begin(), visited.end(), current->second.ptr()) == visited.end())
(current->second->m_error == ZT_CERTIFICATE_ERROR_NONE) && && (current->second->m_error == ZT_CERTIFICATE_ERROR_NONE)
(current->second->m_certificate.publicKeySize == prevChild->second->m_certificate.issuerPublicKeySize) && && (current->second->m_certificate.publicKeySize
(memcmp(current->second->m_certificate.publicKey, prevChild->second->m_certificate.issuerPublicKey, current->second->m_certificate.publicKeySize) == 0)) { == prevChild->second->m_certificate.issuerPublicKeySize)
&& (memcmp(
current->second->m_certificate.publicKey,
prevChild->second->m_certificate.issuerPublicKey,
current->second->m_certificate.publicKeySize)
== 0)) {
++pathLength; ++pathLength;
continue; continue;
} }
} else { }
else {
// If we've traced this to a root CA, flag its parents as also being on a trust path. Then // If we've traced this to a root CA, flag its parents as also being on a trust path. Then
// break the loop without setting an error. We don't flag the current cert as being on a // break the loop without setting an error. We don't flag the current cert as being on a
// trust path since no other certificates depend on it. // trust path since no other certificates depend on it.
for (Vector< Entry * >::const_iterator v(visited.begin()); v != visited.end(); ++v) { for (Vector<Entry*>::const_iterator v(visited.begin()); v != visited.end(); ++v) {
if (*v != c->second.ptr()) if (*v != c->second.ptr())
(*v)->m_onTrustPath = true; (*v)->m_onTrustPath = true;
} }
break; break;
} }
} }
// If we made it here without breaking or continuing, no path to a // If we made it here without breaking or continuing, no path to a
@ -199,60 +211,67 @@ bool TrustStore::update(const int64_t clock, Vector< SharedPtr< Entry > > *const
// certificates for the same subject as deprecated. A deprecated certificate is not invalid // certificates for the same subject as deprecated. A deprecated certificate is not invalid
// but will be purged if it is also not part of a trust path. Error certificates are ignored. // but will be purged if it is also not part of a trust path. Error certificates are ignored.
m_bySubjectUniqueId.clear(); m_bySubjectUniqueId.clear();
for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end();) { for (Map<H384, SharedPtr<Entry> >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end();) {
if (c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) { if (c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) {
const unsigned int uniqueIdSize = c->second->m_certificate.subject.uniqueIdSize; const unsigned int uniqueIdSize = c->second->m_certificate.subject.uniqueIdSize;
if ((uniqueIdSize > 0) && (uniqueIdSize <= ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE)) { if ((uniqueIdSize > 0) && (uniqueIdSize <= ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE)) {
SharedPtr< Entry > &entry = m_bySubjectUniqueId[Blob< ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE >(c->second->m_certificate.subject.uniqueId, uniqueIdSize)]; SharedPtr<Entry>& entry = m_bySubjectUniqueId[Blob<ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE>(
c->second->m_certificate.subject.uniqueId,
uniqueIdSize)];
if (entry) { if (entry) {
// If there's already an entry, see if there's a newer certificate for this subject. // If there's already an entry, see if there's a newer certificate for this subject.
if (c->second->m_certificate.subject.timestamp > entry->m_certificate.subject.timestamp) { if (c->second->m_certificate.subject.timestamp > entry->m_certificate.subject.timestamp) {
entry->m_subjectDeprecated = true; entry->m_subjectDeprecated = true;
entry = c->second; entry = c->second;
} else if (c->second->m_certificate.subject.timestamp < entry->m_certificate.subject.timestamp) { }
else if (c->second->m_certificate.subject.timestamp < entry->m_certificate.subject.timestamp) {
c->second->m_subjectDeprecated = true; c->second->m_subjectDeprecated = true;
} else { }
else {
// Equal timestamps should never happen, but handle it anyway by comparing serials. // Equal timestamps should never happen, but handle it anyway by comparing serials.
if (memcmp(c->second->m_certificate.serialNo, entry->m_certificate.serialNo, ZT_CERTIFICATE_HASH_SIZE) > 0) { if (memcmp(
c->second->m_certificate.serialNo,
entry->m_certificate.serialNo,
ZT_CERTIFICATE_HASH_SIZE)
> 0) {
entry->m_subjectDeprecated = true; entry->m_subjectDeprecated = true;
entry = c->second; entry = c->second;
} else { }
else {
c->second->m_subjectDeprecated = true; c->second->m_subjectDeprecated = true;
} }
} }
}
} else { else {
entry = c->second; entry = c->second;
} }
} }
} }
} }
// Populate mapping of identities to certificates whose subjects reference them, ignoring // Populate mapping of identities to certificates whose subjects reference them, ignoring
// error or deprecated certificates. // error or deprecated certificates.
m_bySubjectIdentity.clear(); m_bySubjectIdentity.clear();
for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { for (Map<H384, SharedPtr<Entry> >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) {
if ((c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) && (!c->second->m_subjectDeprecated)) { if ((c->second->m_error == ZT_CERTIFICATE_ERROR_NONE) && (! c->second->m_subjectDeprecated)) {
for (unsigned int i = 0; i < c->second->m_certificate.subject.identityCount; ++i) { for (unsigned int i = 0; i < c->second->m_certificate.subject.identityCount; ++i) {
const Identity *const id = reinterpret_cast<const Identity *>(c->second->m_certificate.subject.identities[i].identity); const Identity* const id =
reinterpret_cast<const Identity*>(c->second->m_certificate.subject.identities[i].identity);
if ((id) && (*id)) // sanity check if ((id) && (*id)) // sanity check
m_bySubjectIdentity[id->fingerprint()].push_back(c->second); m_bySubjectIdentity[id->fingerprint()].push_back(c->second);
} }
} }
} }
// If purge is set, erase and return error and deprecated certs (that are not on a trust path). // If purge is set, erase and return error and deprecated certs (that are not on a trust path).
if (purge) { if (purge) {
for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end();) { for (Map<H384, SharedPtr<Entry> >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end();) {
if ( (c->second->error() != ZT_CERTIFICATE_ERROR_NONE) || ((c->second->m_subjectDeprecated) && (!c->second->m_onTrustPath)) ) { if ((c->second->error() != ZT_CERTIFICATE_ERROR_NONE)
|| ((c->second->m_subjectDeprecated) && (! c->second->m_onTrustPath))) {
purge->push_back(c->second); purge->push_back(c->second);
m_bySerial.erase(c++); m_bySerial.erase(c++);
} else { }
else {
++c; ++c;
} }
} }
@ -261,23 +280,23 @@ bool TrustStore::update(const int64_t clock, Vector< SharedPtr< Entry > > *const
return true; return true;
} }
Vector< uint8_t > TrustStore::save() const Vector<uint8_t> TrustStore::save() const
{ {
Vector< uint8_t > comp; Vector<uint8_t> comp;
int compSize; int compSize;
{ {
RWMutex::RLock l(m_lock); RWMutex::RLock l(m_lock);
Vector< uint8_t > b; Vector<uint8_t> b;
b.reserve(4096); b.reserve(4096);
// A version byte. // A version byte.
b.push_back(0); b.push_back(0);
// <size[2]> <certificate[...]> <trust[2]> tuples terminated by a 0 size. // <size[2]> <certificate[...]> <trust[2]> tuples terminated by a 0 size.
for (Map< H384, SharedPtr< Entry > >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) { for (Map<H384, SharedPtr<Entry> >::const_iterator c(m_bySerial.begin()); c != m_bySerial.end(); ++c) {
const Vector< uint8_t > cdata(c->second->certificate().encode()); const Vector<uint8_t> cdata(c->second->certificate().encode());
const unsigned long size = (uint32_t)cdata.size(); const unsigned long size = (uint32_t)cdata.size();
if ((size > 0) && (size <= 0xffff)) { if ((size > 0) && (size <= 0xffff)) {
b.push_back((uint8_t)(size >> 8U)); b.push_back((uint8_t)(size >> 8U));
@ -292,9 +311,13 @@ Vector< uint8_t > TrustStore::save() const
b.push_back(0); b.push_back(0);
comp.resize((unsigned long)LZ4_COMPRESSBOUND(b.size()) + 8); comp.resize((unsigned long)LZ4_COMPRESSBOUND(b.size()) + 8);
compSize = LZ4_compress_fast(reinterpret_cast<const char *>(b.data()), reinterpret_cast<char *>(comp.data() + 8), (int)b.size(), (int)(comp.size() - 8)); compSize = LZ4_compress_fast(
reinterpret_cast<const char*>(b.data()),
reinterpret_cast<char*>(comp.data() + 8),
(int)b.size(),
(int)(comp.size() - 8));
if (unlikely(compSize <= 0)) // shouldn't be possible if (unlikely(compSize <= 0)) // shouldn't be possible
return Vector< uint8_t >(); return Vector<uint8_t>();
const uint32_t uncompSize = (uint32_t)b.size(); const uint32_t uncompSize = (uint32_t)b.size();
Utils::storeBigEndian(comp.data(), uncompSize); Utils::storeBigEndian(comp.data(), uncompSize);
@ -308,24 +331,29 @@ Vector< uint8_t > TrustStore::save() const
return comp; return comp;
} }
int TrustStore::load(const Vector< uint8_t > &data) int TrustStore::load(const Vector<uint8_t>& data)
{ {
if (data.size() < 8) if (data.size() < 8)
return -1; return -1;
const unsigned int uncompSize = Utils::loadBigEndian< uint32_t >(data.data()); const unsigned int uncompSize = Utils::loadBigEndian<uint32_t>(data.data());
if ((uncompSize == 0) || (uncompSize > (unsigned int)(data.size() * 128))) if ((uncompSize == 0) || (uncompSize > (unsigned int)(data.size() * 128)))
return -1; return -1;
Vector< uint8_t > uncomp; Vector<uint8_t> uncomp;
uncomp.resize(uncompSize); uncomp.resize(uncompSize);
if (LZ4_decompress_safe(reinterpret_cast<const char *>(data.data() + 8), reinterpret_cast<char *>(uncomp.data()), (int)(data.size() - 8), (int)uncompSize) != (int)uncompSize) if (LZ4_decompress_safe(
reinterpret_cast<const char*>(data.data() + 8),
reinterpret_cast<char*>(uncomp.data()),
(int)(data.size() - 8),
(int)uncompSize)
!= (int)uncompSize)
return -1; return -1;
const uint8_t *b = uncomp.data(); const uint8_t* b = uncomp.data();
if (Utils::fnv1a32(b, (unsigned int)uncompSize) != Utils::loadBigEndian< uint32_t >(data.data() + 4)) if (Utils::fnv1a32(b, (unsigned int)uncompSize) != Utils::loadBigEndian<uint32_t>(data.data() + 4))
return -1; return -1;
const uint8_t *const eof = b + uncompSize; const uint8_t* const eof = b + uncompSize;
if (*(b++) != 0) // unrecognized version if (*(b++) != 0) // unrecognized version
return -1; return -1;
@ -335,7 +363,7 @@ int TrustStore::load(const Vector< uint8_t > &data)
for (;;) { for (;;) {
if ((b + 2) > eof) if ((b + 2) > eof)
break; break;
const uint32_t certDataSize = Utils::loadBigEndian< uint16_t >(b); const uint32_t certDataSize = Utils::loadBigEndian<uint16_t>(b);
b += 2; b += 2;
if (certDataSize == 0) if (certDataSize == 0)
@ -346,7 +374,7 @@ int TrustStore::load(const Vector< uint8_t > &data)
Certificate c; Certificate c;
if (c.decode(b, (unsigned int)certDataSize)) { if (c.decode(b, (unsigned int)certDataSize)) {
b += certDataSize; b += certDataSize;
this->add(c, Utils::loadBigEndian< uint16_t >(b)); this->add(c, Utils::loadBigEndian<uint16_t>(b));
b += 2; b += 2;
++readCount; ++readCount;

View file

@ -14,16 +14,16 @@
#ifndef ZT_TRUSTSTORE_HPP #ifndef ZT_TRUSTSTORE_HPP
#define ZT_TRUSTSTORE_HPP #define ZT_TRUSTSTORE_HPP
#include "Constants.hpp"
#include "Context.hpp"
#include "Containers.hpp"
#include "Certificate.hpp" #include "Certificate.hpp"
#include "SHA512.hpp" #include "Constants.hpp"
#include "SharedPtr.hpp" #include "Containers.hpp"
#include "Identity.hpp" #include "Context.hpp"
#include "Fingerprint.hpp" #include "Fingerprint.hpp"
#include "Identity.hpp"
#include "Mutex.hpp" #include "Mutex.hpp"
#include "Peer.hpp" #include "Peer.hpp"
#include "SHA512.hpp"
#include "SharedPtr.hpp"
namespace ZeroTier { namespace ZeroTier {
@ -43,24 +43,24 @@ namespace ZeroTier {
* hence there are no methods for doing that. There's only one instance in a * hence there are no methods for doing that. There's only one instance in a
* node anyway. * node anyway.
*/ */
class TrustStore class TrustStore {
{ public:
public:
/** /**
* An entry in the node certificate trust store * An entry in the node certificate trust store
*/ */
class Entry class Entry {
{ friend class SharedPtr<TrustStore::Entry>;
friend class SharedPtr< TrustStore::Entry >; friend class SharedPtr<const TrustStore::Entry>;
friend class SharedPtr< const TrustStore::Entry >;
friend class TrustStore; friend class TrustStore;
public: public:
/** /**
* @return Reference to held certificate * @return Reference to held certificate
*/ */
ZT_INLINE const Certificate &certificate() const noexcept ZT_INLINE const Certificate& certificate() const noexcept
{ return m_certificate; } {
return m_certificate;
}
/** /**
* Get the local trust for this certificate * Get the local trust for this certificate
@ -98,21 +98,25 @@ public:
} }
private: private:
Entry &operator=(const Entry &) { return *this; } Entry& operator=(const Entry&)
{
return *this;
}
ZT_INLINE Entry(RWMutex &l, const Certificate &cert, const unsigned int lt) noexcept: ZT_INLINE Entry(RWMutex& l, const Certificate& cert, const unsigned int lt) noexcept
__refCount(0), : __refCount(0)
m_lock(l), , m_lock(l)
m_certificate(cert), , m_certificate(cert)
m_localTrust(lt), , m_localTrust(lt)
m_error(ZT_CERTIFICATE_ERROR_NONE), , m_error(ZT_CERTIFICATE_ERROR_NONE)
m_subjectDeprecated(false), , m_subjectDeprecated(false)
m_onTrustPath(false) , m_onTrustPath(false)
{} {
}
std::atomic< int > __refCount; std::atomic<int> __refCount;
RWMutex &m_lock; RWMutex& m_lock;
const Certificate m_certificate; const Certificate m_certificate;
unsigned int m_localTrust; unsigned int m_localTrust;
ZT_CertificateError m_error; ZT_CertificateError m_error;
@ -133,7 +137,7 @@ public:
* @param serial SHA384 hash of certificate * @param serial SHA384 hash of certificate
* @return Entry or empty/nil if not found * @return Entry or empty/nil if not found
*/ */
SharedPtr< Entry > get(const H384 &serial) const; SharedPtr<Entry> get(const H384& serial) const;
/** /**
* Get roots specified by root set certificates in the local store. * Get roots specified by root set certificates in the local store.
@ -144,13 +148,13 @@ public:
* *
* @return Roots and the latest locator specified for each (if any) * @return Roots and the latest locator specified for each (if any)
*/ */
Map< Identity, SharedPtr< const Locator > > roots(); Map<Identity, SharedPtr<const Locator> > roots();
/** /**
* @param includeRejectedCertificates If true, also include certificates with error codes * @param includeRejectedCertificates If true, also include certificates with error codes
* @return All certificates in asecending sort order by serial * @return All certificates in asecending sort order by serial
*/ */
Vector< SharedPtr< Entry > > all(bool includeRejectedCertificates) const; Vector<SharedPtr<Entry> > all(bool includeRejectedCertificates) const;
/** /**
* Add a certificate * Add a certificate
@ -164,7 +168,7 @@ public:
* *
* @param cert Certificate to add * @param cert Certificate to add
*/ */
void add(const Certificate &cert, unsigned int localTrust); void add(const Certificate& cert, unsigned int localTrust);
/** /**
* Queue a certificate to be deleted * Queue a certificate to be deleted
@ -173,7 +177,7 @@ public:
* *
* @param serial Serial of certificate to delete * @param serial Serial of certificate to delete
*/ */
void erase(const H384 &serial); void erase(const H384& serial);
/** /**
* Validate all certificates and their certificate chains * Validate all certificates and their certificate chains
@ -184,14 +188,14 @@ public:
* @param purge If non-NULL, purge rejected certificates and return them in this vector (vector should be empty) * @param purge If non-NULL, purge rejected certificates and return them in this vector (vector should be empty)
* @return True if there were changes * @return True if there were changes
*/ */
bool update(int64_t clock, Vector< SharedPtr< Entry > > *purge); bool update(int64_t clock, Vector<SharedPtr<Entry> >* purge);
/** /**
* Create a compressed binary version of certificates and their local trust * Create a compressed binary version of certificates and their local trust
* *
* @return Binary compressed certificates and local trust info * @return Binary compressed certificates and local trust info
*/ */
Vector< uint8_t > save() const; Vector<uint8_t> save() const;
/** /**
* Decode a saved trust store * Decode a saved trust store
@ -202,14 +206,15 @@ public:
* @param data Data to decode * @param data Data to decode
* @return Number of certificates or -1 if input is invalid * @return Number of certificates or -1 if input is invalid
*/ */
int load(const Vector< uint8_t > &data); int load(const Vector<uint8_t>& data);
private: private:
Map< H384, SharedPtr< Entry > > m_bySerial; // all certificates Map<H384, SharedPtr<Entry> > m_bySerial; // all certificates
Map< Blob< ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE >, SharedPtr< Entry > > m_bySubjectUniqueId; // non-rejected certificates only Map<Blob<ZT_CERTIFICATE_MAX_PUBLIC_KEY_SIZE>, SharedPtr<Entry> >
Map< Fingerprint, Vector< SharedPtr< Entry > > > m_bySubjectIdentity; // non-rejected certificates only m_bySubjectUniqueId; // non-rejected certificates only
ForwardList< SharedPtr< Entry > > m_addQueue; Map<Fingerprint, Vector<SharedPtr<Entry> > > m_bySubjectIdentity; // non-rejected certificates only
ForwardList< H384 > m_deleteQueue; ForwardList<SharedPtr<Entry> > m_addQueue;
ForwardList<H384> m_deleteQueue;
RWMutex m_lock; RWMutex m_lock;
}; };

View file

@ -12,16 +12,17 @@
/****/ /****/
#include "Utils.hpp" #include "Utils.hpp"
#include "Mutex.hpp"
#include "AES.hpp" #include "AES.hpp"
#include "Mutex.hpp"
#include "SHA512.hpp" #include "SHA512.hpp"
#include <time.h> #include <time.h>
#ifdef __UNIX_LIKE__ #ifdef __UNIX_LIKE__
#include <unistd.h>
#include <fcntl.h> #include <fcntl.h>
#include <sys/uio.h> #include <sys/uio.h>
#include <unistd.h>
#endif #endif
#ifdef __WINDOWS__ #ifdef __WINDOWS__
@ -32,8 +33,8 @@
#ifdef ZT_ARCH_ARM_HAS_NEON #ifdef ZT_ARCH_ARM_HAS_NEON
#ifdef __LINUX__ #ifdef __LINUX__
#include <sys/auxv.h>
#include <asm/hwcap.h> #include <asm/hwcap.h>
#include <sys/auxv.h>
#endif #endif
#if defined(__FreeBSD__) #if defined(__FreeBSD__)
@ -73,7 +74,6 @@ namespace Utils {
#ifdef ZT_ARCH_ARM_HAS_NEON #ifdef ZT_ARCH_ARM_HAS_NEON
ARMCapabilities::ARMCapabilities() noexcept ARMCapabilities::ARMCapabilities() noexcept
{ {
#ifdef __APPLE__ #ifdef __APPLE__
this->aes = true; this->aes = true;
@ -86,14 +86,15 @@ ARMCapabilities::ARMCapabilities() noexcept
#ifdef __LINUX__ #ifdef __LINUX__
#ifdef HWCAP2_AES #ifdef HWCAP2_AES
if (sizeof(void *) == 4) { if (sizeof(void*) == 4) {
const long hwcaps2 = getauxval(AT_HWCAP2); const long hwcaps2 = getauxval(AT_HWCAP2);
this->aes = (hwcaps2 & HWCAP2_AES) != 0; this->aes = (hwcaps2 & HWCAP2_AES) != 0;
this->crc32 = (hwcaps2 & HWCAP2_CRC32) != 0; this->crc32 = (hwcaps2 & HWCAP2_CRC32) != 0;
this->pmull = (hwcaps2 & HWCAP2_PMULL) != 0; this->pmull = (hwcaps2 & HWCAP2_PMULL) != 0;
this->sha1 = (hwcaps2 & HWCAP2_SHA1) != 0; this->sha1 = (hwcaps2 & HWCAP2_SHA1) != 0;
this->sha2 = (hwcaps2 & HWCAP2_SHA2) != 0; this->sha2 = (hwcaps2 & HWCAP2_SHA2) != 0;
} else { }
else {
#endif #endif
const long hwcaps = getauxval(AT_HWCAP); const long hwcaps = getauxval(AT_HWCAP);
this->aes = (hwcaps & HWCAP_AES) != 0; this->aes = (hwcaps & HWCAP_AES) != 0;
@ -107,7 +108,6 @@ ARMCapabilities::ARMCapabilities() noexcept
#endif #endif
#endif #endif
} }
const ARMCapabilities ARMCAP; const ARMCapabilities ARMCAP;
@ -120,17 +120,13 @@ CPUIDRegisters::CPUIDRegisters() noexcept
#ifdef __WINDOWS__ #ifdef __WINDOWS__
int regs[4]; int regs[4];
__cpuid(regs,1); __cpuid(regs, 1);
eax = (uint32_t)regs[0]; eax = (uint32_t)regs[0];
ebx = (uint32_t)regs[1]; ebx = (uint32_t)regs[1];
ecx = (uint32_t)regs[2]; ecx = (uint32_t)regs[2];
edx = (uint32_t)regs[3]; edx = (uint32_t)regs[3];
#else #else
__asm__ __volatile__ ( __asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(1), "c"(0));
"cpuid"
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
: "a"(1), "c"(0)
);
#endif #endif
rdrand = ((ecx & (1U << 30U)) != 0); rdrand = ((ecx & (1U << 30U)) != 0);
@ -138,17 +134,13 @@ CPUIDRegisters::CPUIDRegisters() noexcept
avx = ((ecx & (1U << 25U)) != 0); avx = ((ecx & (1U << 25U)) != 0);
#ifdef __WINDOWS__ #ifdef __WINDOWS__
__cpuid(regs,7); __cpuid(regs, 7);
eax = (uint32_t)regs[0]; eax = (uint32_t)regs[0];
ebx = (uint32_t)regs[1]; ebx = (uint32_t)regs[1];
ecx = (uint32_t)regs[2]; ecx = (uint32_t)regs[2];
edx = (uint32_t)regs[3]; edx = (uint32_t)regs[3];
#else #else
__asm__ __volatile__ ( __asm__ __volatile__("cpuid" : "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx) : "a"(7), "c"(0));
"cpuid"
: "=a"(eax), "=b"(ebx), "=c"(ecx), "=d"(edx)
: "a"(7), "c"(0)
);
#endif #endif
vaes = aes && avx && ((ecx & (1U << 9U)) != 0); vaes = aes && avx && ((ecx & (1U << 9U)) != 0);
@ -164,28 +156,28 @@ const CPUIDRegisters CPUID;
const std::bad_alloc BadAllocException; const std::bad_alloc BadAllocException;
const std::out_of_range OutOfRangeException("access out of range"); const std::out_of_range OutOfRangeException("access out of range");
const uint64_t ZERO256[4] = {0, 0, 0, 0}; 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 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(); const uint64_t s_mapNonce = getSecureRandomU64();
bool secureEq(const void *const a, const void *const b, const unsigned int len) noexcept bool secureEq(const void* const a, const void* const b, const unsigned int len) noexcept
{ {
uint8_t diff = 0; uint8_t diff = 0;
for (unsigned int i = 0; i < len; ++i) for (unsigned int i = 0; i < len; ++i)
diff |= ((reinterpret_cast<const uint8_t *>(a))[i] ^ (reinterpret_cast<const uint8_t *>(b))[i]); diff |= ((reinterpret_cast<const uint8_t*>(a))[i] ^ (reinterpret_cast<const uint8_t*>(b))[i]);
return (diff == 0); return (diff == 0);
} }
void burn(volatile void *const ptr, const unsigned int len) void burn(volatile void* const ptr, const unsigned int len)
{ {
static volatile uintptr_t foo = 0; static volatile uintptr_t foo = 0;
Utils::zero((void *)ptr, len); Utils::zero((void*)ptr, len);
// Force compiler not to optimize this function out by taking a volatile // Force compiler not to optimize this function out by taking a volatile
// parameter and also updating a volatile variable. // parameter and also updating a volatile variable.
foo += (uintptr_t)len ^ (uintptr_t)reinterpret_cast<volatile uint8_t *>(ptr)[0]; foo += (uintptr_t)len ^ (uintptr_t) reinterpret_cast<volatile uint8_t*>(ptr)[0];
} }
static unsigned long s_decimalRecursive(unsigned long n, char *s) static unsigned long s_decimalRecursive(unsigned long n, char* s)
{ {
if (n == 0) if (n == 0)
return 0; return 0;
@ -196,7 +188,7 @@ static unsigned long s_decimalRecursive(unsigned long n, char *s)
return pos + 1; return pos + 1;
} }
char *decimal(unsigned long n, char s[24]) noexcept char* decimal(unsigned long n, char s[24]) noexcept
{ {
if (n == 0) { if (n == 0) {
s[0] = '0'; s[0] = '0';
@ -207,36 +199,39 @@ char *decimal(unsigned long n, char s[24]) noexcept
return s; return s;
} }
char *hex(uint64_t i, char buf[17]) noexcept char* hex(uint64_t i, char buf[17]) noexcept
{ {
if (i != 0) { if (i != 0) {
char *p = nullptr; char* p = nullptr;
for (int b = 60; b >= 0; b -= 4) { for (int b = 60; b >= 0; b -= 4) {
const unsigned int nyb = (unsigned int)(i >> (unsigned int)b) & 0xfU; const unsigned int nyb = (unsigned int)(i >> (unsigned int)b) & 0xfU;
if (p) { if (p) {
*(p++) = HEXCHARS[nyb]; *(p++) = HEXCHARS[nyb];
} else if (nyb != 0) { }
else if (nyb != 0) {
p = buf; p = buf;
*(p++) = HEXCHARS[nyb]; *(p++) = HEXCHARS[nyb];
} }
} }
*p = 0; *p = 0;
return buf; return buf;
} else { }
else {
buf[0] = '0'; buf[0] = '0';
buf[1] = 0; buf[1] = 0;
return buf; return buf;
} }
} }
uint64_t unhex(const char *s) noexcept uint64_t unhex(const char* s) noexcept
{ {
uint64_t n = 0; uint64_t n = 0;
if (s) { if (s) {
int k = 0; int k = 0;
while (k < 16) { while (k < 16) {
char hc = *(s++); char hc = *(s++);
if (!hc) break; if (! hc)
break;
uint8_t c = 0; uint8_t c = 0;
if ((hc >= 48) && (hc <= 57)) if ((hc >= 48) && (hc <= 57))
@ -254,11 +249,11 @@ uint64_t unhex(const char *s) noexcept
return n; return n;
} }
char *hex(const void *d, unsigned int l, char *s) noexcept char* hex(const void* d, unsigned int l, char* s) noexcept
{ {
char *const save = s; char* const save = s;
for (unsigned int i = 0; i < l; ++i) { for (unsigned int i = 0; i < l; ++i) {
const unsigned int b = reinterpret_cast<const uint8_t *>(d)[i]; const unsigned int b = reinterpret_cast<const uint8_t*>(d)[i];
*(s++) = HEXCHARS[b >> 4U]; *(s++) = HEXCHARS[b >> 4U];
*(s++) = HEXCHARS[b & 0xfU]; *(s++) = HEXCHARS[b & 0xfU];
} }
@ -266,14 +261,16 @@ char *hex(const void *d, unsigned int l, char *s) noexcept
return save; return save;
} }
unsigned int unhex(const char *h, unsigned int hlen, void *buf, unsigned int buflen) noexcept unsigned int unhex(const char* h, unsigned int hlen, void* buf, unsigned int buflen) noexcept
{ {
unsigned int l = 0; unsigned int l = 0;
const char *hend = h + hlen; const char* hend = h + hlen;
while (l < buflen) { while (l < buflen) {
if (h == hend) break; if (h == hend)
uint8_t hc = *(reinterpret_cast<const uint8_t *>(h++)); break;
if (!hc) break; uint8_t hc = *(reinterpret_cast<const uint8_t*>(h++));
if (! hc)
break;
uint8_t c = 0; uint8_t c = 0;
if ((hc >= 48) && (hc <= 57)) if ((hc >= 48) && (hc <= 57))
@ -283,9 +280,11 @@ unsigned int unhex(const char *h, unsigned int hlen, void *buf, unsigned int buf
else if ((hc >= 65) && (hc <= 70)) else if ((hc >= 65) && (hc <= 70))
c = hc - 55; c = hc - 55;
if (h == hend) break; if (h == hend)
hc = *(reinterpret_cast<const uint8_t *>(h++)); break;
if (!hc) break; hc = *(reinterpret_cast<const uint8_t*>(h++));
if (! hc)
break;
c <<= 4U; c <<= 4U;
if ((hc >= 48) && (hc <= 57)) if ((hc >= 48) && (hc <= 57))
@ -295,7 +294,7 @@ unsigned int unhex(const char *h, unsigned int hlen, void *buf, unsigned int buf
else if ((hc >= 65) && (hc <= 70)) else if ((hc >= 65) && (hc <= 70))
c |= hc - 55; c |= hc - 55;
reinterpret_cast<uint8_t *>(buf)[l++] = c; reinterpret_cast<uint8_t*>(buf)[l++] = c;
} }
return l; return l;
} }
@ -303,7 +302,7 @@ unsigned int unhex(const char *h, unsigned int hlen, void *buf, unsigned int buf
#define ZT_GETSECURERANDOM_STATE_SIZE 64 #define ZT_GETSECURERANDOM_STATE_SIZE 64
#define ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR 1048576 #define ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR 1048576
void getSecureRandom(void *const buf, unsigned int bytes) noexcept void getSecureRandom(void* const buf, unsigned int bytes) noexcept
{ {
static Mutex globalLock; static Mutex globalLock;
static bool initialized = false; static bool initialized = false;
@ -321,20 +320,20 @@ void getSecureRandom(void *const buf, unsigned int bytes) noexcept
if (unlikely(randomByteCounter >= ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR)) { if (unlikely(randomByteCounter >= ZT_GETSECURERANDOM_ITERATIONS_PER_GENERATOR)) {
randomByteCounter = 0; randomByteCounter = 0;
if (unlikely(!initialized)) { if (unlikely(! initialized)) {
initialized = true; initialized = true;
Utils::zero< sizeof(randomState) >(randomState); Utils::zero<sizeof(randomState)>(randomState);
#ifdef __WINDOWS__ #ifdef __WINDOWS__
HCRYPTPROV cryptProvider = NULL; HCRYPTPROV cryptProvider = NULL;
if (!CryptAcquireContextA(&cryptProvider,NULL,NULL,PROV_RSA_FULL,CRYPT_VERIFYCONTEXT|CRYPT_SILENT)) { if (! CryptAcquireContextA(&cryptProvider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT | CRYPT_SILENT)) {
fprintf(stderr,"FATAL: Utils::getSecureRandom() unable to obtain WinCrypt context!\r\n"); fprintf(stderr, "FATAL: Utils::getSecureRandom() unable to obtain WinCrypt context!\r\n");
exit(1); exit(1);
} }
if (!CryptGenRandom(cryptProvider,(DWORD)sizeof(randomState),(BYTE *)randomState)) { if (! CryptGenRandom(cryptProvider, (DWORD)sizeof(randomState), (BYTE*)randomState)) {
fprintf(stderr,"FATAL: Utils::getSecureRandom() CryptGenRandom failed!\r\n"); fprintf(stderr, "FATAL: Utils::getSecureRandom() CryptGenRandom failed!\r\n");
exit(1); exit(1);
} }
CryptReleaseContext(cryptProvider,0); CryptReleaseContext(cryptProvider, 0);
#else #else
int devURandomFd = ::open("/dev/urandom", O_RDONLY); int devURandomFd = ::open("/dev/urandom", O_RDONLY);
if (devURandomFd < 0) { if (devURandomFd < 0) {
@ -356,7 +355,7 @@ void getSecureRandom(void *const buf, unsigned int bytes) noexcept
if (CPUID.rdrand) { if (CPUID.rdrand) {
uint64_t tmp = 0; uint64_t tmp = 0;
for (unsigned long i = 0; i < ZT_GETSECURERANDOM_STATE_SIZE; ++i) { for (unsigned long i = 0; i < ZT_GETSECURERANDOM_STATE_SIZE; ++i) {
_rdrand64_step((unsigned long long *)&tmp); _rdrand64_step((unsigned long long*)&tmp);
randomState[i] ^= tmp; randomState[i] ^= tmp;
} }
} }
@ -374,8 +373,8 @@ void getSecureRandom(void *const buf, unsigned int bytes) noexcept
// Generate random bytes using AES and bytes 32-48 of randomState as an in-place // Generate random bytes using AES and bytes 32-48 of randomState as an in-place
// AES-CTR counter. Counter can be machine endian; we don't care about portability // AES-CTR counter. Counter can be machine endian; we don't care about portability
// for a random generator. // for a random generator.
uint64_t *const ctr = randomState + 4; uint64_t* const ctr = randomState + 4;
uint8_t *out = reinterpret_cast<uint8_t *>(buf); uint8_t* out = reinterpret_cast<uint8_t*>(buf);
while (bytes >= 16) { while (bytes >= 16) {
++*ctr; ++*ctr;
@ -401,7 +400,7 @@ uint64_t getSecureRandomU64() noexcept
return tmp; return tmp;
} }
int b32e(const uint8_t *data, int length, char *result, int bufSize) noexcept int b32e(const uint8_t* data, int length, char* result, int bufSize) noexcept
{ {
if (length < 0 || length > (1 << 28U)) { if (length < 0 || length > (1 << 28U)) {
result[0] = (char)0; result[0] = (char)0;
@ -418,7 +417,8 @@ int b32e(const uint8_t *data, int length, char *result, int bufSize) noexcept
buffer <<= 8U; buffer <<= 8U;
buffer |= data[next++] & 0xffU; buffer |= data[next++] & 0xffU;
bitsLeft += 8; bitsLeft += 8;
} else { }
else {
int pad = 5 - bitsLeft; int pad = 5 - bitsLeft;
buffer <<= pad; buffer <<= pad;
bitsLeft += pad; bitsLeft += pad;
@ -437,12 +437,12 @@ int b32e(const uint8_t *data, int length, char *result, int bufSize) noexcept
return -1; return -1;
} }
int b32d(const char *encoded, uint8_t *result, int bufSize) noexcept int b32d(const char* encoded, uint8_t* result, int bufSize) noexcept
{ {
int buffer = 0; int buffer = 0;
int bitsLeft = 0; int bitsLeft = 0;
int count = 0; int count = 0;
for (const uint8_t *ptr = (const uint8_t *)encoded; count < bufSize && *ptr; ++ptr) { for (const uint8_t* ptr = (const uint8_t*)encoded; count < bufSize && *ptr; ++ptr) {
uint8_t ch = *ptr; uint8_t ch = *ptr;
if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '-' || ch == '.') { if (ch == ' ' || ch == '\t' || ch == '\r' || ch == '\n' || ch == '-' || ch == '.') {
continue; continue;
@ -451,17 +451,21 @@ int b32d(const char *encoded, uint8_t *result, int bufSize) noexcept
if (ch == '0') { if (ch == '0') {
ch = 'O'; ch = 'O';
} else if (ch == '1') { }
else if (ch == '1') {
ch = 'L'; ch = 'L';
} else if (ch == '8') { }
else if (ch == '8') {
ch = 'B'; ch = 'B';
} }
if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) { if ((ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) {
ch = (ch & 0x1f) - 1; ch = (ch & 0x1f) - 1;
} else if (ch >= '2' && ch <= '7') { }
else if (ch >= '2' && ch <= '7') {
ch -= '2' - 26; ch -= '2' - 26;
} else { }
else {
return -1; return -1;
} }
@ -506,9 +510,9 @@ uint64_t random() noexcept
return result; return result;
} }
bool scopy(char *const dest, const unsigned int len, const char *const src) noexcept bool scopy(char* const dest, const unsigned int len, const char* const src) noexcept
{ {
if (unlikely((len == 0)||(dest == nullptr))) { if (unlikely((len == 0) || (dest == nullptr))) {
return false; return false;
} }
if (unlikely(src == nullptr)) { if (unlikely(src == nullptr)) {
@ -528,12 +532,12 @@ bool scopy(char *const dest, const unsigned int len, const char *const src) noex
} }
} }
uint32_t fnv1a32(const void *const restrict data, const unsigned int len) noexcept uint32_t fnv1a32(const void* const restrict data, const unsigned int len) noexcept
{ {
uint32_t h = 0x811c9dc5; uint32_t h = 0x811c9dc5;
const uint32_t p = 0x01000193; const uint32_t p = 0x01000193;
for (unsigned int i = 0; i < len; ++i) for (unsigned int i = 0; i < len; ++i)
h = (h ^ (uint32_t)reinterpret_cast<const uint8_t *>(data)[i]) * p; h = (h ^ (uint32_t) reinterpret_cast<const uint8_t*>(data)[i]) * p;
return h; return h;
} }

View file

@ -16,13 +16,12 @@
#include "Constants.hpp" #include "Constants.hpp"
#include <stddef.h>
#include <stdarg.h>
#include <utility>
#include <algorithm> #include <algorithm>
#include <memory> #include <memory>
#include <stdarg.h>
#include <stddef.h>
#include <stdexcept> #include <stdexcept>
#include <utility>
namespace ZeroTier { namespace ZeroTier {
@ -37,15 +36,11 @@ namespace Utils {
// Macros to convert endian-ness at compile time for constants. // Macros to convert endian-ness at compile time for constants.
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
#define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)((uint16_t)((uint16_t)(x) << 8U) | (uint16_t)((uint16_t)(x) >> 8U))) #define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)((uint16_t)((uint16_t)(x) << 8U) | (uint16_t)((uint16_t)(x) >> 8U)))
#define ZT_CONST_TO_BE_UINT64(x) ( \ #define ZT_CONST_TO_BE_UINT64(x) \
(((uint64_t)(x) & 0x00000000000000ffULL) << 56U) | \ ((((uint64_t)(x)&0x00000000000000ffULL) << 56U) | (((uint64_t)(x)&0x000000000000ff00ULL) << 40U) \
(((uint64_t)(x) & 0x000000000000ff00ULL) << 40U) | \ | (((uint64_t)(x)&0x0000000000ff0000ULL) << 24U) | (((uint64_t)(x)&0x00000000ff000000ULL) << 8U) \
(((uint64_t)(x) & 0x0000000000ff0000ULL) << 24U) | \ | (((uint64_t)(x)&0x000000ff00000000ULL) >> 8U) | (((uint64_t)(x)&0x0000ff0000000000ULL) >> 24U) \
(((uint64_t)(x) & 0x00000000ff000000ULL) << 8U) | \ | (((uint64_t)(x)&0x00ff000000000000ULL) >> 40U) | (((uint64_t)(x)&0xff00000000000000ULL) >> 56U))
(((uint64_t)(x) & 0x000000ff00000000ULL) >> 8U) | \
(((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24U) | \
(((uint64_t)(x) & 0x00ff000000000000ULL) >> 40U) | \
(((uint64_t)(x) & 0xff00000000000000ULL) >> 56U))
#else #else
#define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)(x)) #define ZT_CONST_TO_BE_UINT16(x) ((uint16_t)(x))
#define ZT_CONST_TO_BE_UINT64(x) ((uint64_t)(x)) #define ZT_CONST_TO_BE_UINT64(x) ((uint64_t)(x))
@ -57,8 +52,7 @@ namespace Utils {
#define ZT_ROL32(x, r) (((x) << (r)) | ((x) >> (32 - (r)))) #define ZT_ROL32(x, r) (((x) << (r)) | ((x) >> (32 - (r))))
#ifdef ZT_ARCH_ARM_HAS_NEON #ifdef ZT_ARCH_ARM_HAS_NEON
struct ARMCapabilities struct ARMCapabilities {
{
ARMCapabilities() noexcept; ARMCapabilities() noexcept;
bool aes, crc32, pmull, sha1, sha2; bool aes, crc32, pmull, sha1, sha2;
}; };
@ -66,8 +60,7 @@ extern const ARMCapabilities ARMCAP;
#endif #endif
#ifdef ZT_ARCH_X64 #ifdef ZT_ARCH_X64
struct CPUIDRegisters struct CPUIDRegisters {
{
CPUIDRegisters() noexcept; CPUIDRegisters() noexcept;
bool rdrand, aes, avx, vaes, vpclmulqdq, avx2, avx512f, sha, fsrm; bool rdrand, aes, avx, vaes, vpclmulqdq, avx2, avx512f, sha, fsrm;
}; };
@ -100,7 +93,7 @@ extern const uint64_t s_mapNonce;
* @param len Length of strings * @param len Length of strings
* @return True if strings are equal * @return True if strings are equal
*/ */
bool secureEq(const void *a, const void *b, unsigned int len) noexcept; bool secureEq(const void* a, const void* b, unsigned int len) noexcept;
/** /**
* Be absolutely sure to zero memory * Be absolutely sure to zero memory
@ -111,14 +104,14 @@ bool secureEq(const void *a, const void *b, unsigned int len) noexcept;
* @param ptr Memory to zero * @param ptr Memory to zero
* @param len Length of memory in bytes * @param len Length of memory in bytes
*/ */
void burn(volatile void *ptr, unsigned int len); void burn(volatile void* ptr, unsigned int len);
/** /**
* @param n Number to convert * @param n Number to convert
* @param s Buffer, at least 24 bytes in size * @param s Buffer, at least 24 bytes in size
* @return String containing 'n' in base 10 form * @return String containing 'n' in base 10 form
*/ */
char *decimal(unsigned long n, char s[24]) noexcept; char* decimal(unsigned long n, char s[24]) noexcept;
/** /**
* Convert an unsigned integer into hex * Convert an unsigned integer into hex
@ -127,7 +120,7 @@ char *decimal(unsigned long n, char s[24]) noexcept;
* @param s Buffer to receive hex, must be at least (2*sizeof(i))+1 in size or overflow will occur. * @param s Buffer to receive hex, must be at least (2*sizeof(i))+1 in size or overflow will occur.
* @return Pointer to s containing hex string with trailing zero byte * @return Pointer to s containing hex string with trailing zero byte
*/ */
char *hex(uint64_t i, char buf[17]) noexcept; char* hex(uint64_t i, char buf[17]) noexcept;
/** /**
* Decode an unsigned integer in hex format * Decode an unsigned integer in hex format
@ -135,7 +128,7 @@ char *hex(uint64_t i, char buf[17]) noexcept;
* @param s String to decode, non-hex chars are ignored * @param s String to decode, non-hex chars are ignored
* @return Unsigned integer * @return Unsigned integer
*/ */
uint64_t unhex(const char *s) noexcept; uint64_t unhex(const char* s) noexcept;
/** /**
* Convert a byte array into hex * Convert a byte array into hex
@ -145,7 +138,7 @@ uint64_t unhex(const char *s) noexcept;
* @param s String buffer, must be at least (l*2)+1 in size or overflow will occur * @param s String buffer, must be at least (l*2)+1 in size or overflow will occur
* @return Pointer to filled string buffer * @return Pointer to filled string buffer
*/ */
char *hex(const void *d, unsigned int l, char *s) noexcept; char* hex(const void* d, unsigned int l, char* s) noexcept;
/** /**
* Decode a hex string * Decode a hex string
@ -156,7 +149,7 @@ char *hex(const void *d, unsigned int l, char *s) noexcept;
* @param buflen Length of output buffer * @param buflen Length of output buffer
* @return Number of written bytes * @return Number of written bytes
*/ */
unsigned int unhex(const char *h, unsigned int hlen, void *buf, unsigned int buflen) noexcept; unsigned int unhex(const char* h, unsigned int hlen, void* buf, unsigned int buflen) noexcept;
/** /**
* Generate secure random bytes * Generate secure random bytes
@ -167,7 +160,7 @@ unsigned int unhex(const char *h, unsigned int hlen, void *buf, unsigned int buf
* @param buf Buffer to fill * @param buf Buffer to fill
* @param bytes Number of random bytes to generate * @param bytes Number of random bytes to generate
*/ */
void getSecureRandom(void *buf, unsigned int bytes) noexcept; void getSecureRandom(void* buf, unsigned int bytes) noexcept;
/** /**
* @return Secure random 64-bit integer * @return Secure random 64-bit integer
@ -183,7 +176,7 @@ uint64_t getSecureRandomU64() noexcept;
* @param bufSize Size of result buffer * @param bufSize Size of result buffer
* @return Number of bytes written * @return Number of bytes written
*/ */
int b32e(const uint8_t *data, int length, char *result, int bufSize) noexcept; int b32e(const uint8_t* data, int length, char* result, int bufSize) noexcept;
/** /**
* Decode base32 string * Decode base32 string
@ -193,7 +186,7 @@ int b32e(const uint8_t *data, int length, char *result, int bufSize) noexcept;
* @param bufSize Size of result buffer * @param bufSize Size of result buffer
* @return Number of bytes written or -1 on error * @return Number of bytes written or -1 on error
*/ */
int b32d(const char *encoded, uint8_t *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.
@ -215,15 +208,15 @@ uint64_t random() noexcept;
* @param src Source string (if NULL, dest will receive a zero-length string and true is returned) * @param src Source string (if NULL, dest will receive a zero-length string and true is returned)
* @return True on success, false on overflow (buffer will still be 0-terminated) * @return True on success, false on overflow (buffer will still be 0-terminated)
*/ */
bool scopy(char *dest, unsigned int len, const char *src) noexcept; bool scopy(char* dest, unsigned int len, const char* src) noexcept;
/** /**
* Check if a buffer's contents are all zero * Check if a buffer's contents are all zero
*/ */
static ZT_INLINE bool allZero(const void *const b, const unsigned int l) noexcept static ZT_INLINE bool allZero(const void* const b, const unsigned int l) noexcept
{ {
for (unsigned int i=0;i<l;++i) { for (unsigned int i = 0; i < l; ++i) {
if (reinterpret_cast<const uint8_t *>(b)[i] != 0) if (reinterpret_cast<const uint8_t*>(b)[i] != 0)
return false; return false;
} }
return true; return true;
@ -237,7 +230,7 @@ static ZT_INLINE bool allZero(const void *const b, const unsigned int l) noexcep
* @param saveptr Pointer to pointer where function can save state * @param saveptr Pointer to pointer where function can save state
* @return Next token or NULL if none * @return Next token or NULL if none
*/ */
static ZT_INLINE char *stok(char *str, const char *delim, char **saveptr) noexcept static ZT_INLINE char* stok(char* str, const char* delim, char** saveptr) noexcept
{ {
#ifdef __WINDOWS__ #ifdef __WINDOWS__
return strtok_s(str, delim, saveptr); return strtok_s(str, delim, saveptr);
@ -246,13 +239,15 @@ static ZT_INLINE char *stok(char *str, const char *delim, char **saveptr) noexce
#endif #endif
} }
static ZT_INLINE unsigned int strToUInt(const char *s) noexcept static ZT_INLINE unsigned int strToUInt(const char* s) noexcept
{ return (unsigned int)strtoul(s, nullptr, 10); } {
return (unsigned int)strtoul(s, nullptr, 10);
}
static ZT_INLINE unsigned long long hexStrToU64(const char *s) noexcept static ZT_INLINE unsigned long long hexStrToU64(const char* s) noexcept
{ {
#ifdef __WINDOWS__ #ifdef __WINDOWS__
return (unsigned long long)_strtoui64(s,nullptr,16); return (unsigned long long)_strtoui64(s, nullptr, 16);
#else #else
return strtoull(s, nullptr, 16); return strtoull(s, nullptr, 16);
#endif #endif
@ -261,26 +256,33 @@ static ZT_INLINE unsigned long long hexStrToU64(const char *s) noexcept
#ifdef __GNUC__ #ifdef __GNUC__
static ZT_INLINE unsigned int countBits(const uint8_t v) noexcept static ZT_INLINE unsigned int countBits(const uint8_t v) noexcept
{ return (unsigned int)__builtin_popcount((unsigned int)v); } {
return (unsigned int)__builtin_popcount((unsigned int)v);
}
static ZT_INLINE unsigned int countBits(const uint16_t v) noexcept static ZT_INLINE unsigned int countBits(const uint16_t v) noexcept
{ return (unsigned int)__builtin_popcount((unsigned int)v); } {
return (unsigned int)__builtin_popcount((unsigned int)v);
}
static ZT_INLINE unsigned int countBits(const uint32_t v) noexcept static ZT_INLINE unsigned int countBits(const uint32_t v) noexcept
{ return (unsigned int)__builtin_popcountl((unsigned long)v); } {
return (unsigned int)__builtin_popcountl((unsigned long)v);
}
static ZT_INLINE unsigned int countBits(const uint64_t v) noexcept static ZT_INLINE unsigned int countBits(const uint64_t v) noexcept
{ return (unsigned int)__builtin_popcountll((unsigned long long)v); } {
return (unsigned int)__builtin_popcountll((unsigned long long)v);
}
#else #else
template<typename T> template <typename T> static ZT_INLINE unsigned int countBits(T v) noexcept
static ZT_INLINE unsigned int countBits(T v) noexcept
{ {
v = v - ((v >> 1) & (T)~(T)0/3); v = v - ((v >> 1) & (T) ~(T)0 / 3);
v = (v & (T)~(T)0/15*3) + ((v >> 2) & (T)~(T)0/15*3); v = (v & (T) ~(T)0 / 15 * 3) + ((v >> 2) & (T) ~(T)0 / 15 * 3);
v = (v + (v >> 4)) & (T)~(T)0/255*15; v = (v + (v >> 4)) & (T) ~(T)0 / 255 * 15;
return (unsigned int)((v * ((~((T)0))/((T)255))) >> ((sizeof(T) - 1) * 8)); return (unsigned int)((v * ((~((T)0)) / ((T)255))) >> ((sizeof(T) - 1) * 8));
} }
#endif #endif
@ -300,15 +302,9 @@ static ZT_INLINE uint64_t swapBytes(const uint64_t n) noexcept
return (uint64_t)_byteswap_uint64((unsigned __int64)n); return (uint64_t)_byteswap_uint64((unsigned __int64)n);
#else #else
return ( return (
((n & 0x00000000000000ffULL) << 56) | ((n & 0x00000000000000ffULL) << 56) | ((n & 0x000000000000ff00ULL) << 40) | ((n & 0x0000000000ff0000ULL) << 24)
((n & 0x000000000000ff00ULL) << 40) | | ((n & 0x00000000ff000000ULL) << 8) | ((n & 0x000000ff00000000ULL) >> 8) | ((n & 0x0000ff0000000000ULL) >> 24)
((n & 0x0000000000ff0000ULL) << 24) | | ((n & 0x00ff000000000000ULL) >> 40) | ((n & 0xff00000000000000ULL) >> 56));
((n & 0x00000000ff000000ULL) << 8) |
((n & 0x000000ff00000000ULL) >> 8) |
((n & 0x0000ff0000000000ULL) >> 24) |
((n & 0x00ff000000000000ULL) >> 40) |
((n & 0xff00000000000000ULL) >> 56)
);
#endif #endif
#endif #endif
} }
@ -353,109 +349,108 @@ static ZT_INLINE uint16_t swapBytes(const uint16_t n) noexcept
// These are helper adapters to load and swap integer types special cased by size // These are helper adapters to load and swap integer types special cased by size
// to work with all typedef'd variants, signed/unsigned, etc. // to work with all typedef'd variants, signed/unsigned, etc.
template< typename I, unsigned int S > template <typename I, unsigned int S> class _swap_bytes_bysize;
class _swap_bytes_bysize;
template< typename I > template <typename I> class _swap_bytes_bysize<I, 1> {
class _swap_bytes_bysize< I, 1 > public:
{
public:
static ZT_INLINE I s(const I n) noexcept static ZT_INLINE I s(const I n) noexcept
{ return n; } {
return n;
}
}; };
template< typename I > template <typename I> class _swap_bytes_bysize<I, 2> {
class _swap_bytes_bysize< I, 2 > public:
{
public:
static ZT_INLINE I s(const I n) noexcept static ZT_INLINE I s(const I n) noexcept
{ return (I)swapBytes((uint16_t)n); } {
return (I)swapBytes((uint16_t)n);
}
}; };
template< typename I > template <typename I> class _swap_bytes_bysize<I, 4> {
class _swap_bytes_bysize< I, 4 > public:
{
public:
static ZT_INLINE I s(const I n) noexcept static ZT_INLINE I s(const I n) noexcept
{ return (I)swapBytes((uint32_t)n); } {
return (I)swapBytes((uint32_t)n);
}
}; };
template< typename I > template <typename I> class _swap_bytes_bysize<I, 8> {
class _swap_bytes_bysize< I, 8 > public:
{
public:
static ZT_INLINE I s(const I n) noexcept static ZT_INLINE I s(const I n) noexcept
{ return (I)swapBytes((uint64_t)n); } {
return (I)swapBytes((uint64_t)n);
}
}; };
template< typename I, unsigned int S > template <typename I, unsigned int S> class _load_be_bysize;
class _load_be_bysize;
template< typename I > template <typename I> class _load_be_bysize<I, 1> {
class _load_be_bysize< I, 1 > public:
{ static ZT_INLINE I l(const uint8_t* const p) noexcept
public: {
static ZT_INLINE I l(const uint8_t *const p) noexcept return p[0];
{ return p[0]; } }
}; };
template< typename I > template <typename I> class _load_be_bysize<I, 2> {
class _load_be_bysize< I, 2 > public:
{ static ZT_INLINE I l(const uint8_t* const p) noexcept
public: {
static ZT_INLINE I l(const uint8_t *const p) noexcept return (I)(((unsigned int)p[0] << 8U) | (unsigned int)p[1]);
{ return (I)(((unsigned int)p[0] << 8U) | (unsigned int)p[1]); } }
}; };
template< typename I > template <typename I> class _load_be_bysize<I, 4> {
class _load_be_bysize< I, 4 > public:
{ static ZT_INLINE I l(const uint8_t* const p) noexcept
public: {
static ZT_INLINE I l(const uint8_t *const p) noexcept return (I)(((uint32_t)p[0] << 24U) | ((uint32_t)p[1] << 16U) | ((uint32_t)p[2] << 8U) | (uint32_t)p[3]);
{ return (I)(((uint32_t)p[0] << 24U) | ((uint32_t)p[1] << 16U) | ((uint32_t)p[2] << 8U) | (uint32_t)p[3]); } }
}; };
template< typename I > template <typename I> class _load_be_bysize<I, 8> {
class _load_be_bysize< I, 8 > public:
{ static ZT_INLINE I l(const uint8_t* const p) noexcept
public: {
static ZT_INLINE I l(const uint8_t *const p) noexcept return (
{ return (I)(((uint64_t)p[0] << 56U) | ((uint64_t)p[1] << 48U) | ((uint64_t)p[2] << 40U) | ((uint64_t)p[3] << 32U) | ((uint64_t)p[4] << 24U) | ((uint64_t)p[5] << 16U) | ((uint64_t)p[6] << 8U) | (uint64_t)p[7]); } I)(((uint64_t)p[0] << 56U) | ((uint64_t)p[1] << 48U) | ((uint64_t)p[2] << 40U) | ((uint64_t)p[3] << 32U) | ((uint64_t)p[4] << 24U) | ((uint64_t)p[5] << 16U) | ((uint64_t)p[6] << 8U) | (uint64_t)p[7]);
}
}; };
template< typename I, unsigned int S > template <typename I, unsigned int S> class _load_le_bysize;
class _load_le_bysize;
template< typename I > template <typename I> class _load_le_bysize<I, 1> {
class _load_le_bysize< I, 1 > public:
{ static ZT_INLINE I l(const uint8_t* const p) noexcept
public: {
static ZT_INLINE I l(const uint8_t *const p) noexcept return p[0];
{ return p[0]; } }
}; };
template< typename I > template <typename I> class _load_le_bysize<I, 2> {
class _load_le_bysize< I, 2 > public:
{ static ZT_INLINE I l(const uint8_t* const p) noexcept
public: {
static ZT_INLINE I l(const uint8_t *const p) noexcept return (I)((unsigned int)p[0] | ((unsigned int)p[1] << 8U));
{ return (I)((unsigned int)p[0] | ((unsigned int)p[1] << 8U)); } }
}; };
template< typename I > template <typename I> class _load_le_bysize<I, 4> {
class _load_le_bysize< I, 4 > public:
{ static ZT_INLINE I l(const uint8_t* const p) noexcept
public: {
static ZT_INLINE I l(const uint8_t *const p) noexcept return (I)((uint32_t)p[0] | ((uint32_t)p[1] << 8U) | ((uint32_t)p[2] << 16U) | ((uint32_t)p[3] << 24U));
{ return (I)((uint32_t)p[0] | ((uint32_t)p[1] << 8U) | ((uint32_t)p[2] << 16U) | ((uint32_t)p[3] << 24U)); } }
}; };
template< typename I > template <typename I> class _load_le_bysize<I, 8> {
class _load_le_bysize< I, 8 > public:
{ static ZT_INLINE I l(const uint8_t* const p) noexcept
public: {
static ZT_INLINE I l(const uint8_t *const p) noexcept return (
{ return (I)((uint64_t)p[0] | ((uint64_t)p[1] << 8U) | ((uint64_t)p[2] << 16U) | ((uint64_t)p[3] << 24U) | ((uint64_t)p[4] << 32U) | ((uint64_t)p[5] << 40U) | ((uint64_t)p[6] << 48U) | ((uint64_t)p[7]) << 56U); } I)((uint64_t)p[0] | ((uint64_t)p[1] << 8U) | ((uint64_t)p[2] << 16U) | ((uint64_t)p[3] << 24U) | ((uint64_t)p[4] << 32U) | ((uint64_t)p[5] << 40U) | ((uint64_t)p[6] << 48U) | ((uint64_t)p[7]) << 56U);
}
}; };
/** /**
@ -465,11 +460,10 @@ public:
* @param n Value to convert * @param n Value to convert
* @return Value in big-endian order * @return Value in big-endian order
*/ */
template< typename I > template <typename I> static ZT_INLINE I hton(const I n) noexcept
static ZT_INLINE I hton(const I n) noexcept
{ {
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
return _swap_bytes_bysize< I, sizeof(I) >::s(n); return _swap_bytes_bysize<I, sizeof(I)>::s(n);
#else #else
return n; return n;
#endif #endif
@ -482,11 +476,10 @@ static ZT_INLINE I hton(const I n) noexcept
* @param n Value to convert * @param n Value to convert
* @return Value in host byte order * @return Value in host byte order
*/ */
template< typename I > template <typename I> static ZT_INLINE I ntoh(const I n) noexcept
static ZT_INLINE I ntoh(const I n) noexcept
{ {
#if __BYTE_ORDER == __LITTLE_ENDIAN #if __BYTE_ORDER == __LITTLE_ENDIAN
return _swap_bytes_bysize< I, sizeof(I) >::s(n); return _swap_bytes_bysize<I, sizeof(I)>::s(n);
#else #else
return n; return n;
#endif #endif
@ -499,16 +492,15 @@ static ZT_INLINE I ntoh(const I n) noexcept
* @param p Byte stream, must be at least sizeof(I) in size * @param p Byte stream, must be at least sizeof(I) in size
* @return Loaded raw integer * @return Loaded raw integer
*/ */
template< typename I > template <typename I> static ZT_INLINE I loadMachineEndian(const void* const restrict p) noexcept
static ZT_INLINE I loadMachineEndian(const void *const restrict p) noexcept
{ {
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
I tmp; I tmp;
for(int i=0;i<(int)sizeof(I);++i) for (int i = 0; i < (int)sizeof(I); ++i)
reinterpret_cast<uint8_t *>(&tmp)[i] = reinterpret_cast<const uint8_t *>(p)[i]; reinterpret_cast<uint8_t*>(&tmp)[i] = reinterpret_cast<const uint8_t*>(p)[i];
return tmp; return tmp;
#else #else
return *reinterpret_cast<const I *>(p); return *reinterpret_cast<const I*>(p);
#endif #endif
} }
@ -519,14 +511,13 @@ static ZT_INLINE I loadMachineEndian(const void *const restrict p) noexcept
* @param p Byte array (must be at least sizeof(I)) * @param p Byte array (must be at least sizeof(I))
* @param i Integer to store * @param i Integer to store
*/ */
template< typename I > template <typename I> static ZT_INLINE void storeMachineEndian(void* const restrict p, const I i) noexcept
static ZT_INLINE void storeMachineEndian(void *const restrict p, const I i) noexcept
{ {
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
for(unsigned int k=0;k<sizeof(I);++k) for (unsigned int k = 0; k < sizeof(I); ++k)
reinterpret_cast<uint8_t *>(p)[k] = reinterpret_cast<const uint8_t *>(&i)[k]; reinterpret_cast<uint8_t*>(p)[k] = reinterpret_cast<const uint8_t*>(&i)[k];
#else #else
*reinterpret_cast<I *>(p) = i; *reinterpret_cast<I*>(p) = i;
#endif #endif
} }
@ -537,13 +528,12 @@ static ZT_INLINE void storeMachineEndian(void *const restrict p, const I i) noex
* @param p Byte stream, must be at least sizeof(I) in size * @param p Byte stream, must be at least sizeof(I) in size
* @return Decoded integer * @return Decoded integer
*/ */
template< typename I > template <typename I> static ZT_INLINE I loadBigEndian(const void* const restrict p) noexcept
static ZT_INLINE I loadBigEndian(const void *const restrict p) noexcept
{ {
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
return _load_be_bysize<I,sizeof(I)>::l(reinterpret_cast<const uint8_t *>(p)); return _load_be_bysize<I, sizeof(I)>::l(reinterpret_cast<const uint8_t*>(p));
#else #else
return ntoh(*reinterpret_cast<const I *>(p)); return ntoh(*reinterpret_cast<const I*>(p));
#endif #endif
} }
@ -554,13 +544,12 @@ static ZT_INLINE I loadBigEndian(const void *const restrict p) noexcept
* @param p Byte stream to write (must be at least sizeof(I)) * @param p Byte stream to write (must be at least sizeof(I))
* #param i Integer to write * #param i Integer to write
*/ */
template< typename I > template <typename I> static ZT_INLINE void storeBigEndian(void* const restrict p, I i) noexcept
static ZT_INLINE void storeBigEndian(void *const restrict p, I i) noexcept
{ {
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
storeMachineEndian(p,hton(i)); storeMachineEndian(p, hton(i));
#else #else
*reinterpret_cast<I *>(p) = hton(i); *reinterpret_cast<I*>(p) = hton(i);
#endif #endif
} }
@ -571,13 +560,12 @@ static ZT_INLINE void storeBigEndian(void *const restrict p, I i) noexcept
* @param p Byte stream, must be at least sizeof(I) in size * @param p Byte stream, must be at least sizeof(I) in size
* @return Decoded integer * @return Decoded integer
*/ */
template< typename I > template <typename I> static ZT_INLINE I loadLittleEndian(const void* const restrict p) noexcept
static ZT_INLINE I loadLittleEndian(const void *const restrict p) noexcept
{ {
#if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS) #if __BYTE_ORDER == __BIG_ENDIAN || defined(ZT_NO_UNALIGNED_ACCESS)
return _load_le_bysize<I,sizeof(I)>::l(reinterpret_cast<const uint8_t *>(p)); return _load_le_bysize<I, sizeof(I)>::l(reinterpret_cast<const uint8_t*>(p));
#else #else
return *reinterpret_cast<const I *>(p); return *reinterpret_cast<const I*>(p);
#endif #endif
} }
@ -588,16 +576,15 @@ static ZT_INLINE I loadLittleEndian(const void *const restrict p) noexcept
* @param p Byte stream to write (must be at least sizeof(I)) * @param p Byte stream to write (must be at least sizeof(I))
* #param i Integer to write * #param i Integer to write
*/ */
template< typename I > template <typename I> static ZT_INLINE void storeLittleEndian(void* const restrict p, const I i) noexcept
static ZT_INLINE void storeLittleEndian(void *const restrict p, const I i) noexcept
{ {
#if __BYTE_ORDER == __BIG_ENDIAN #if __BYTE_ORDER == __BIG_ENDIAN
storeMachineEndian(p,_swap_bytes_bysize<I,sizeof(I)>::s(i)); storeMachineEndian(p, _swap_bytes_bysize<I, sizeof(I)>::s(i));
#else #else
#ifdef ZT_NO_UNALIGNED_ACCESS #ifdef ZT_NO_UNALIGNED_ACCESS
storeMachineEndian(p,i); storeMachineEndian(p, i);
#else #else
*reinterpret_cast<I *>(p) = i; *reinterpret_cast<I*>(p) = i;
#endif #endif
#endif #endif
} }
@ -609,12 +596,11 @@ static ZT_INLINE void storeLittleEndian(void *const restrict p, const I i) noexc
* @param dest Destination memory * @param dest Destination memory
* @param src Source memory * @param src Source memory
*/ */
template< unsigned long L > template <unsigned long L> static ZT_INLINE void copy(void* dest, const void* src) noexcept
static ZT_INLINE void copy(void *dest, const void *src) noexcept
{ {
#if defined(ZT_ARCH_X64) && defined(__GNUC__) #if defined(ZT_ARCH_X64) && defined(__GNUC__)
uintptr_t l = L; uintptr_t l = L;
__asm__ __volatile__ ("cld ; rep movsb" : "+c"(l), "+S"(src), "+D"(dest) :: "memory"); __asm__ __volatile__("cld ; rep movsb" : "+c"(l), "+S"(src), "+D"(dest)::"memory");
#else #else
memcpy(dest, src, L); memcpy(dest, src, L);
#endif #endif
@ -627,10 +613,10 @@ static ZT_INLINE void copy(void *dest, const void *src) noexcept
* @param src Source memory * @param src Source memory
* @param len Bytes to copy * @param len Bytes to copy
*/ */
static ZT_INLINE void copy(void *dest, const void *src, unsigned long len) noexcept static ZT_INLINE void copy(void* dest, const void* src, unsigned long len) noexcept
{ {
#if defined(ZT_ARCH_X64) && defined(__GNUC__) #if defined(ZT_ARCH_X64) && defined(__GNUC__)
__asm__ __volatile__ ("cld ; rep movsb" : "+c"(len), "+S"(src), "+D"(dest) :: "memory"); __asm__ __volatile__("cld ; rep movsb" : "+c"(len), "+S"(src), "+D"(dest)::"memory");
#else #else
memcpy(dest, src, len); memcpy(dest, src, len);
#endif #endif
@ -642,12 +628,11 @@ static ZT_INLINE void copy(void *dest, const void *src, unsigned long len) noexc
* @tparam L Size in bytes * @tparam L Size in bytes
* @param dest Memory to zero * @param dest Memory to zero
*/ */
template< unsigned long L > template <unsigned long L> static ZT_INLINE void zero(void* dest) noexcept
static ZT_INLINE void zero(void *dest) noexcept
{ {
#if defined(ZT_ARCH_X64) && defined(__GNUC__) #if defined(ZT_ARCH_X64) && defined(__GNUC__)
uintptr_t l = L; uintptr_t l = L;
__asm__ __volatile__ ("cld ; rep stosb" :"+c" (l), "+D" (dest) : "a" (0) : "memory"); __asm__ __volatile__("cld ; rep stosb" : "+c"(l), "+D"(dest) : "a"(0) : "memory");
#else #else
memset(dest, 0, L); memset(dest, 0, L);
#endif #endif
@ -659,10 +644,10 @@ static ZT_INLINE void zero(void *dest) noexcept
* @param dest Memory to zero * @param dest Memory to zero
* @param len Size in bytes * @param len Size in bytes
*/ */
static ZT_INLINE void zero(void *dest, unsigned long len) noexcept static ZT_INLINE void zero(void* dest, unsigned long len) noexcept
{ {
#if defined(ZT_ARCH_X64) && defined(__GNUC__) #if defined(ZT_ARCH_X64) && defined(__GNUC__)
__asm__ __volatile__ ("cld ; rep stosb" :"+c" (len), "+D" (dest) : "a" (0) : "memory"); __asm__ __volatile__("cld ; rep stosb" : "+c"(len), "+D"(dest) : "a"(0) : "memory");
#else #else
memset(dest, 0, len); memset(dest, 0, len);
#endif #endif
@ -677,7 +662,7 @@ static ZT_INLINE void zero(void *dest, unsigned long len) noexcept
* @param len Length of data * @param len Length of data
* @return FNV1a checksum * @return FNV1a checksum
*/ */
uint32_t fnv1a32(const void *restrict data, unsigned int len) noexcept; uint32_t fnv1a32(const void* restrict data, unsigned int len) noexcept;
/** /**
* Mix bits in a 64-bit integer (non-cryptographic, for hash tables) * Mix bits in a 64-bit integer (non-cryptographic, for hash tables)

File diff suppressed because it is too large Load diff

View file

@ -14,15 +14,15 @@
#ifndef ZT_VL1_HPP #ifndef ZT_VL1_HPP
#define ZT_VL1_HPP #define ZT_VL1_HPP
#include "Constants.hpp"
#include "Defragmenter.hpp"
#include "Buf.hpp"
#include "Address.hpp" #include "Address.hpp"
#include "Protocol.hpp" #include "Buf.hpp"
#include "Mutex.hpp"
#include "FCV.hpp"
#include "Containers.hpp"
#include "CallContext.hpp" #include "CallContext.hpp"
#include "Constants.hpp"
#include "Containers.hpp"
#include "Defragmenter.hpp"
#include "FCV.hpp"
#include "Mutex.hpp"
#include "Protocol.hpp"
#define ZT_VL1_MAX_WHOIS_WAITING_PACKETS 32 #define ZT_VL1_MAX_WHOIS_WAITING_PACKETS 32
@ -43,10 +43,9 @@ class VL2;
* *
* This class is thread safe. * This class is thread safe.
*/ */
class VL1 class VL1 {
{ public:
public: explicit VL1(const Context& ctx);
explicit VL1(const Context &ctx);
/** /**
* Called when a packet is received from the real network * Called when a packet is received from the real network
@ -62,40 +61,103 @@ public:
* @param data Packet data * @param data Packet data
* @param len Packet length * @param len Packet length
*/ */
void onRemotePacket(CallContext &cc, int64_t localSocket, const InetAddress &fromAddr, SharedPtr< Buf > &data, unsigned int len) noexcept; void onRemotePacket(
CallContext& cc,
int64_t localSocket,
const InetAddress& fromAddr,
SharedPtr<Buf>& data,
unsigned int len) noexcept;
private: private:
void m_relay(CallContext &cc, const SharedPtr< Path > &path, Address destination, SharedPtr< Buf > &pkt, int pktSize); void m_relay(CallContext& cc, const SharedPtr<Path>& path, Address destination, SharedPtr<Buf>& pkt, int pktSize);
void m_sendPendingWhois(CallContext &cc); void m_sendPendingWhois(CallContext& cc);
SharedPtr< Peer > m_HELLO(CallContext &cc, const SharedPtr< Path > &path, Buf &pkt, int packetSize); SharedPtr<Peer> m_HELLO(CallContext& cc, const SharedPtr<Path>& path, Buf& pkt, int packetSize);
bool m_ERROR(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb); bool m_ERROR(
bool m_OK(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize, Protocol::Verb &inReVerb); CallContext& cc,
bool m_WHOIS(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize); uint64_t packetId,
bool m_RENDEZVOUS(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize); unsigned int auth,
bool m_ECHO(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize); const SharedPtr<Path>& path,
bool m_PUSH_DIRECT_PATHS(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize); const SharedPtr<Peer>& peer,
bool m_USER_MESSAGE(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize); Buf& pkt,
bool m_ENCAP(CallContext &cc, uint64_t packetId, unsigned int auth, const SharedPtr< Path > &path, const SharedPtr< Peer > &peer, Buf &pkt, int packetSize); int packetSize,
Protocol::Verb& inReVerb);
bool m_OK(
CallContext& cc,
uint64_t packetId,
unsigned int auth,
const SharedPtr<Path>& path,
const SharedPtr<Peer>& peer,
Buf& pkt,
int packetSize,
Protocol::Verb& inReVerb);
bool m_WHOIS(
CallContext& cc,
uint64_t packetId,
unsigned int auth,
const SharedPtr<Path>& path,
const SharedPtr<Peer>& peer,
Buf& pkt,
int packetSize);
bool m_RENDEZVOUS(
CallContext& cc,
uint64_t packetId,
unsigned int auth,
const SharedPtr<Path>& path,
const SharedPtr<Peer>& peer,
Buf& pkt,
int packetSize);
bool m_ECHO(
CallContext& cc,
uint64_t packetId,
unsigned int auth,
const SharedPtr<Path>& path,
const SharedPtr<Peer>& peer,
Buf& pkt,
int packetSize);
bool m_PUSH_DIRECT_PATHS(
CallContext& cc,
uint64_t packetId,
unsigned int auth,
const SharedPtr<Path>& path,
const SharedPtr<Peer>& peer,
Buf& pkt,
int packetSize);
bool m_USER_MESSAGE(
CallContext& cc,
uint64_t packetId,
unsigned int auth,
const SharedPtr<Path>& path,
const SharedPtr<Peer>& peer,
Buf& pkt,
int packetSize);
bool m_ENCAP(
CallContext& cc,
uint64_t packetId,
unsigned int auth,
const SharedPtr<Path>& path,
const SharedPtr<Peer>& peer,
Buf& pkt,
int packetSize);
const Context &m_ctx; const Context& m_ctx;
// Defragmentation engine for handling inbound packets with more than one fragment. // Defragmentation engine for handling inbound packets with more than one fragment.
Defragmenter< ZT_MAX_PACKET_FRAGMENTS > m_inputPacketAssembler; Defragmenter<ZT_MAX_PACKET_FRAGMENTS> m_inputPacketAssembler;
// Queue of outbound WHOIS reqeusts and packets waiting on them. // Queue of outbound WHOIS reqeusts and packets waiting on them.
struct p_WhoisQueueItem struct p_WhoisQueueItem {
{
ZT_INLINE p_WhoisQueueItem() : lastRetry(0), retries(0), waitingPacketCount(0) ZT_INLINE p_WhoisQueueItem() : lastRetry(0), retries(0), waitingPacketCount(0)
{} {
}
int64_t lastRetry; int64_t lastRetry;
unsigned int retries; unsigned int retries;
unsigned int waitingPacketCount; unsigned int waitingPacketCount;
unsigned int waitingPacketSize[ZT_VL1_MAX_WHOIS_WAITING_PACKETS]; unsigned int waitingPacketSize[ZT_VL1_MAX_WHOIS_WAITING_PACKETS];
SharedPtr< Buf > waitingPacket[ZT_VL1_MAX_WHOIS_WAITING_PACKETS]; SharedPtr<Buf> waitingPacket[ZT_VL1_MAX_WHOIS_WAITING_PACKETS];
}; };
Map< Address, p_WhoisQueueItem > m_whoisQueue; Map<Address, p_WhoisQueueItem> m_whoisQueue;
Mutex m_whoisQueue_l; Mutex m_whoisQueue_l;
}; };

View file

@ -12,58 +12,129 @@
/****/ /****/
#include "VL2.hpp" #include "VL2.hpp"
#include "Context.hpp" #include "Context.hpp"
#include "VL1.hpp"
#include "Topology.hpp"
#include "Peer.hpp"
#include "Path.hpp"
#include "Network.hpp"
#include "MAC.hpp" #include "MAC.hpp"
#include "Network.hpp"
#include "Path.hpp"
#include "Peer.hpp"
#include "Topology.hpp"
#include "VL1.hpp"
namespace ZeroTier { namespace ZeroTier {
VL2::VL2(const Context &ctx): VL2::VL2(const Context& ctx) : m_ctx(ctx)
m_ctx(ctx)
{ {
} }
void VL2::onLocalEthernet(CallContext &cc, const SharedPtr< Network > &network, const MAC &from, const MAC &to, const unsigned int etherType, unsigned int vlanId, SharedPtr< Buf > &data, unsigned int len) void VL2::onLocalEthernet(
CallContext& cc,
const SharedPtr<Network>& network,
const MAC& from,
const MAC& to,
const unsigned int etherType,
unsigned int vlanId,
SharedPtr<Buf>& data,
unsigned int len)
{ {
} }
bool VL2::m_FRAME(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) bool VL2::m_FRAME(
CallContext& cc,
const uint64_t packetId,
const unsigned int auth,
const SharedPtr<Path>& path,
SharedPtr<Peer>& peer,
Buf& pkt,
int packetSize)
{ {
} }
bool VL2::m_EXT_FRAME(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) bool VL2::m_EXT_FRAME(
CallContext& cc,
const uint64_t packetId,
const unsigned int auth,
const SharedPtr<Path>& path,
SharedPtr<Peer>& peer,
Buf& pkt,
int packetSize)
{ {
} }
bool VL2::m_MULTICAST_LIKE(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) bool VL2::m_MULTICAST_LIKE(
CallContext& cc,
const uint64_t packetId,
const unsigned int auth,
const SharedPtr<Path>& path,
SharedPtr<Peer>& peer,
Buf& pkt,
int packetSize)
{ {
} }
bool VL2::m_NETWORK_CREDENTIALS(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) bool VL2::m_NETWORK_CREDENTIALS(
CallContext& cc,
const uint64_t packetId,
const unsigned int auth,
const SharedPtr<Path>& path,
SharedPtr<Peer>& peer,
Buf& pkt,
int packetSize)
{ {
} }
bool VL2::m_NETWORK_CONFIG_REQUEST(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) bool VL2::m_NETWORK_CONFIG_REQUEST(
CallContext& cc,
const uint64_t packetId,
const unsigned int auth,
const SharedPtr<Path>& path,
SharedPtr<Peer>& peer,
Buf& pkt,
int packetSize)
{ {
} }
bool VL2::m_NETWORK_CONFIG(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) bool VL2::m_NETWORK_CONFIG(
CallContext& cc,
const uint64_t packetId,
const unsigned int auth,
const SharedPtr<Path>& path,
SharedPtr<Peer>& peer,
Buf& pkt,
int packetSize)
{ {
} }
bool VL2::m_MULTICAST_GATHER(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) bool VL2::m_MULTICAST_GATHER(
CallContext& cc,
const uint64_t packetId,
const unsigned int auth,
const SharedPtr<Path>& path,
SharedPtr<Peer>& peer,
Buf& pkt,
int packetSize)
{ {
} }
bool VL2::m_MULTICAST_FRAME_deprecated(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) bool VL2::m_MULTICAST_FRAME_deprecated(
CallContext& cc,
const uint64_t packetId,
const unsigned int auth,
const SharedPtr<Path>& path,
SharedPtr<Peer>& peer,
Buf& pkt,
int packetSize)
{ {
} }
bool VL2::m_MULTICAST(CallContext &cc, const uint64_t packetId, const unsigned int auth, const SharedPtr< Path > &path, SharedPtr< Peer > &peer, Buf &pkt, int packetSize) bool VL2::m_MULTICAST(
CallContext& cc,
const uint64_t packetId,
const unsigned int auth,
const SharedPtr<Path>& path,
SharedPtr<Peer>& peer,
Buf& pkt,
int packetSize)
{ {
} }

Some files were not shown because too many files have changed in this diff Show more