Merge master into multipath

This commit is contained in:
Joseph Henry 2019-08-12 11:40:13 -07:00
commit 77ae929eb3
300 changed files with 20343 additions and 34032 deletions

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -54,28 +54,16 @@ public:
* @param bits Raw address -- 5 bytes, big-endian byte order
* @param len Length of array
*/
Address(const void *bits,unsigned int len)
{
setTo(bits,len);
}
Address(const void *bits,unsigned int len) { setTo(bits,len); }
inline Address &operator=(const Address &a)
{
_a = a._a;
return *this;
}
inline Address &operator=(const uint64_t a)
{
_a = (a & 0xffffffffffULL);
return *this;
}
inline Address &operator=(const Address &a) { _a = a._a; return *this; }
inline Address &operator=(const uint64_t a) { _a = (a & 0xffffffffffULL); return *this; }
/**
* @param bits Raw address -- 5 bytes, big-endian byte order
* @param len Length of array
*/
inline void setTo(const void *bits,unsigned int len)
inline void setTo(const void *bits,const unsigned int len)
{
if (len < ZT_ADDRESS_LENGTH) {
_a = 0;
@ -94,7 +82,7 @@ public:
* @param bits Buffer to hold 5-byte address in big-endian byte order
* @param len Length of array
*/
inline void copyTo(void *bits,unsigned int len) const
inline void copyTo(void *const bits,const unsigned int len) const
{
if (len < ZT_ADDRESS_LENGTH)
return;
@ -125,37 +113,23 @@ public:
/**
* @return Integer containing address (0 to 2^40)
*/
inline uint64_t toInt() const
{
return _a;
}
inline uint64_t toInt() const { return _a; }
/**
* @return Hash code for use with Hashtable
*/
inline unsigned long hashCode() const
{
return (unsigned long)_a;
}
inline unsigned long hashCode() const { return (unsigned long)_a; }
/**
* @return Hexadecimal string
*/
inline char *toString(char buf[11]) const
{
return Utils::hex10(_a,buf);
}
inline char *toString(char buf[11]) const { return Utils::hex10(_a,buf); }
/**
* @return True if this address is not zero
*/
inline operator bool() const { return (_a != 0); }
/**
* Set to null/zero
*/
inline void zero() { _a = 0; }
/**
* Check if this address is reserved
*
@ -165,16 +139,15 @@ public:
*
* @return True if address is reserved and may not be used
*/
inline bool isReserved() const
{
return ((!_a)||((_a >> 32) == ZT_ADDRESS_RESERVED_PREFIX));
}
inline bool isReserved() const { return ((!_a)||((_a >> 32) == ZT_ADDRESS_RESERVED_PREFIX)); }
/**
* @param i Value from 0 to 4 (inclusive)
* @return Byte at said position (address interpreted in big-endian order)
*/
inline unsigned char operator[](unsigned int i) const { return (unsigned char)((_a >> (32 - (i * 8))) & 0xff); }
inline uint8_t operator[](unsigned int i) const { return (uint8_t)(_a >> (32 - (i * 8))); }
inline void zero() { _a = 0; }
inline bool operator==(const uint64_t &a) const { return (_a == (a & 0xffffffffffULL)); }
inline bool operator!=(const uint64_t &a) const { return (_a != (a & 0xffffffffffULL)); }

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -116,9 +116,9 @@ public:
if (unlikely(b._l > C))
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
if (C2 == C) {
ZT_FAST_MEMCPY(this,&b,sizeof(Buffer<C>));
memcpy(this,&b,sizeof(Buffer<C>));
} else {
ZT_FAST_MEMCPY(_b,b._b,_l = b._l);
memcpy(_b,b._b,_l = b._l);
}
return *this;
}
@ -127,7 +127,7 @@ public:
{
if (unlikely(l > C))
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
ZT_FAST_MEMCPY(_b,b,l);
memcpy(_b,b,l);
_l = l;
}
@ -281,7 +281,7 @@ public:
{
if (unlikely((_l + l) > C))
throw ZT_EXCEPTION_OUT_OF_BOUNDS;
ZT_FAST_MEMCPY(_b + _l,b,l);
memcpy(_b + _l,b,l);
_l += l;
}

View file

@ -15,6 +15,8 @@ Derived from public domain code by D. J. Bernstein.
#include "C25519.hpp"
#include "SHA512.hpp"
#include "Buffer.hpp"
#include "Hashtable.hpp"
#include "Mutex.hpp"
#ifdef __WINDOWS__
#pragma warning(disable: 4146)
@ -22,15 +24,722 @@ Derived from public domain code by D. J. Bernstein.
namespace {
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
#define crypto_int32 int32_t
#define crypto_uint32 uint32_t
#define crypto_int64 int64_t
#define crypto_uint64 uint64_t
#define crypto_hash_sha512_BYTES 64
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
typedef uint8_t u8;
typedef int32_t s32;
typedef int64_t limb;
static inline void fsum(limb *output, const limb *in) {
unsigned i;
for (i = 0; i < 10; i += 2) {
output[0+i] = output[0+i] + in[0+i];
output[1+i] = output[1+i] + in[1+i];
}
}
static inline void fdifference(limb *output, const limb *in) {
unsigned i;
for (i = 0; i < 10; ++i) {
output[i] = in[i] - output[i];
}
}
static inline void fscalar_product(limb *output, const limb *in, const limb scalar) {
unsigned i;
for (i = 0; i < 10; ++i) {
output[i] = in[i] * scalar;
}
}
static inline void fproduct(limb *output, const limb *in2, const limb *in) {
output[0] = ((limb) ((s32) in2[0])) * ((s32) in[0]);
output[1] = ((limb) ((s32) in2[0])) * ((s32) in[1]) +
((limb) ((s32) in2[1])) * ((s32) in[0]);
output[2] = 2 * ((limb) ((s32) in2[1])) * ((s32) in[1]) +
((limb) ((s32) in2[0])) * ((s32) in[2]) +
((limb) ((s32) in2[2])) * ((s32) in[0]);
output[3] = ((limb) ((s32) in2[1])) * ((s32) in[2]) +
((limb) ((s32) in2[2])) * ((s32) in[1]) +
((limb) ((s32) in2[0])) * ((s32) in[3]) +
((limb) ((s32) in2[3])) * ((s32) in[0]);
output[4] = ((limb) ((s32) in2[2])) * ((s32) in[2]) +
2 * (((limb) ((s32) in2[1])) * ((s32) in[3]) +
((limb) ((s32) in2[3])) * ((s32) in[1])) +
((limb) ((s32) in2[0])) * ((s32) in[4]) +
((limb) ((s32) in2[4])) * ((s32) in[0]);
output[5] = ((limb) ((s32) in2[2])) * ((s32) in[3]) +
((limb) ((s32) in2[3])) * ((s32) in[2]) +
((limb) ((s32) in2[1])) * ((s32) in[4]) +
((limb) ((s32) in2[4])) * ((s32) in[1]) +
((limb) ((s32) in2[0])) * ((s32) in[5]) +
((limb) ((s32) in2[5])) * ((s32) in[0]);
output[6] = 2 * (((limb) ((s32) in2[3])) * ((s32) in[3]) +
((limb) ((s32) in2[1])) * ((s32) in[5]) +
((limb) ((s32) in2[5])) * ((s32) in[1])) +
((limb) ((s32) in2[2])) * ((s32) in[4]) +
((limb) ((s32) in2[4])) * ((s32) in[2]) +
((limb) ((s32) in2[0])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[0]);
output[7] = ((limb) ((s32) in2[3])) * ((s32) in[4]) +
((limb) ((s32) in2[4])) * ((s32) in[3]) +
((limb) ((s32) in2[2])) * ((s32) in[5]) +
((limb) ((s32) in2[5])) * ((s32) in[2]) +
((limb) ((s32) in2[1])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[1]) +
((limb) ((s32) in2[0])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[0]);
output[8] = ((limb) ((s32) in2[4])) * ((s32) in[4]) +
2 * (((limb) ((s32) in2[3])) * ((s32) in[5]) +
((limb) ((s32) in2[5])) * ((s32) in[3]) +
((limb) ((s32) in2[1])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[1])) +
((limb) ((s32) in2[2])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[2]) +
((limb) ((s32) in2[0])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[0]);
output[9] = ((limb) ((s32) in2[4])) * ((s32) in[5]) +
((limb) ((s32) in2[5])) * ((s32) in[4]) +
((limb) ((s32) in2[3])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[3]) +
((limb) ((s32) in2[2])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[2]) +
((limb) ((s32) in2[1])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[1]) +
((limb) ((s32) in2[0])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[0]);
output[10] = 2 * (((limb) ((s32) in2[5])) * ((s32) in[5]) +
((limb) ((s32) in2[3])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[3]) +
((limb) ((s32) in2[1])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[1])) +
((limb) ((s32) in2[4])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[4]) +
((limb) ((s32) in2[2])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[2]);
output[11] = ((limb) ((s32) in2[5])) * ((s32) in[6]) +
((limb) ((s32) in2[6])) * ((s32) in[5]) +
((limb) ((s32) in2[4])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[4]) +
((limb) ((s32) in2[3])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[3]) +
((limb) ((s32) in2[2])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[2]);
output[12] = ((limb) ((s32) in2[6])) * ((s32) in[6]) +
2 * (((limb) ((s32) in2[5])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[5]) +
((limb) ((s32) in2[3])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[3])) +
((limb) ((s32) in2[4])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[4]);
output[13] = ((limb) ((s32) in2[6])) * ((s32) in[7]) +
((limb) ((s32) in2[7])) * ((s32) in[6]) +
((limb) ((s32) in2[5])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[5]) +
((limb) ((s32) in2[4])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[4]);
output[14] = 2 * (((limb) ((s32) in2[7])) * ((s32) in[7]) +
((limb) ((s32) in2[5])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[5])) +
((limb) ((s32) in2[6])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[6]);
output[15] = ((limb) ((s32) in2[7])) * ((s32) in[8]) +
((limb) ((s32) in2[8])) * ((s32) in[7]) +
((limb) ((s32) in2[6])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[6]);
output[16] = ((limb) ((s32) in2[8])) * ((s32) in[8]) +
2 * (((limb) ((s32) in2[7])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[7]));
output[17] = ((limb) ((s32) in2[8])) * ((s32) in[9]) +
((limb) ((s32) in2[9])) * ((s32) in[8]);
output[18] = 2 * ((limb) ((s32) in2[9])) * ((s32) in[9]);
}
static inline void freduce_degree(limb *output) {
output[8] += output[18] << 4;
output[8] += output[18] << 1;
output[8] += output[18];
output[7] += output[17] << 4;
output[7] += output[17] << 1;
output[7] += output[17];
output[6] += output[16] << 4;
output[6] += output[16] << 1;
output[6] += output[16];
output[5] += output[15] << 4;
output[5] += output[15] << 1;
output[5] += output[15];
output[4] += output[14] << 4;
output[4] += output[14] << 1;
output[4] += output[14];
output[3] += output[13] << 4;
output[3] += output[13] << 1;
output[3] += output[13];
output[2] += output[12] << 4;
output[2] += output[12] << 1;
output[2] += output[12];
output[1] += output[11] << 4;
output[1] += output[11] << 1;
output[1] += output[11];
output[0] += output[10] << 4;
output[0] += output[10] << 1;
output[0] += output[10];
}
#if (-1 & 3) != 3
#error "This code only works on a two's complement system"
#endif
static inline limb div_by_2_26(const limb v)
{
/* High word of v; no shift needed. */
const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
/* Set to all 1s if v was negative; else set to 0s. */
const int32_t sign = ((int32_t) highword) >> 31;
/* Set to 0x3ffffff if v was negative; else set to 0. */
const int32_t roundoff = ((uint32_t) sign) >> 6;
/* Should return v / (1<<26) */
return (v + roundoff) >> 26;
}
static inline limb div_by_2_25(const limb v)
{
/* High word of v; no shift needed*/
const uint32_t highword = (uint32_t) (((uint64_t) v) >> 32);
/* Set to all 1s if v was negative; else set to 0s. */
const int32_t sign = ((int32_t) highword) >> 31;
/* Set to 0x1ffffff if v was negative; else set to 0. */
const int32_t roundoff = ((uint32_t) sign) >> 7;
/* Should return v / (1<<25) */
return (v + roundoff) >> 25;
}
static inline void freduce_coefficients(limb *output) {
unsigned i;
output[10] = 0;
for (i = 0; i < 10; i += 2) {
limb over = div_by_2_26(output[i]);
/* The entry condition (that |output[i]| < 280*2^54) means that over is, at
* most, 280*2^28 in the first iteration of this loop. This is added to the
* next limb and we can approximate the resulting bound of that limb by
* 281*2^54. */
output[i] -= over << 26;
output[i+1] += over;
/* For the first iteration, |output[i+1]| < 281*2^54, thus |over| <
* 281*2^29. When this is added to the next limb, the resulting bound can
* be approximated as 281*2^54.
*
* For subsequent iterations of the loop, 281*2^54 remains a conservative
* bound and no overflow occurs. */
over = div_by_2_25(output[i+1]);
output[i+1] -= over << 25;
output[i+2] += over;
}
/* Now |output[10]| < 281*2^29 and all other coefficients are reduced. */
output[0] += output[10] << 4;
output[0] += output[10] << 1;
output[0] += output[10];
output[10] = 0;
/* Now output[1..9] are reduced, and |output[0]| < 2^26 + 19*281*2^29
* So |over| will be no more than 2^16. */
{
limb over = div_by_2_26(output[0]);
output[0] -= over << 26;
output[1] += over;
}
/* Now output[0,2..9] are reduced, and |output[1]| < 2^25 + 2^16 < 2^26. The
* bound on |output[1]| is sufficient to meet our needs. */
}
static inline void fmul(limb *output, const limb *in, const limb *in2) {
limb t[19];
fproduct(t, in, in2);
/* |t[i]| < 14*2^54 */
freduce_degree(t);
freduce_coefficients(t);
/* |t[i]| < 2^26 */
memcpy(output, t, sizeof(limb) * 10);
}
static inline void fsquare_inner(limb *output, const limb *in) {
output[0] = ((limb) ((s32) in[0])) * ((s32) in[0]);
output[1] = 2 * ((limb) ((s32) in[0])) * ((s32) in[1]);
output[2] = 2 * (((limb) ((s32) in[1])) * ((s32) in[1]) +
((limb) ((s32) in[0])) * ((s32) in[2]));
output[3] = 2 * (((limb) ((s32) in[1])) * ((s32) in[2]) +
((limb) ((s32) in[0])) * ((s32) in[3]));
output[4] = ((limb) ((s32) in[2])) * ((s32) in[2]) +
4 * ((limb) ((s32) in[1])) * ((s32) in[3]) +
2 * ((limb) ((s32) in[0])) * ((s32) in[4]);
output[5] = 2 * (((limb) ((s32) in[2])) * ((s32) in[3]) +
((limb) ((s32) in[1])) * ((s32) in[4]) +
((limb) ((s32) in[0])) * ((s32) in[5]));
output[6] = 2 * (((limb) ((s32) in[3])) * ((s32) in[3]) +
((limb) ((s32) in[2])) * ((s32) in[4]) +
((limb) ((s32) in[0])) * ((s32) in[6]) +
2 * ((limb) ((s32) in[1])) * ((s32) in[5]));
output[7] = 2 * (((limb) ((s32) in[3])) * ((s32) in[4]) +
((limb) ((s32) in[2])) * ((s32) in[5]) +
((limb) ((s32) in[1])) * ((s32) in[6]) +
((limb) ((s32) in[0])) * ((s32) in[7]));
output[8] = ((limb) ((s32) in[4])) * ((s32) in[4]) +
2 * (((limb) ((s32) in[2])) * ((s32) in[6]) +
((limb) ((s32) in[0])) * ((s32) in[8]) +
2 * (((limb) ((s32) in[1])) * ((s32) in[7]) +
((limb) ((s32) in[3])) * ((s32) in[5])));
output[9] = 2 * (((limb) ((s32) in[4])) * ((s32) in[5]) +
((limb) ((s32) in[3])) * ((s32) in[6]) +
((limb) ((s32) in[2])) * ((s32) in[7]) +
((limb) ((s32) in[1])) * ((s32) in[8]) +
((limb) ((s32) in[0])) * ((s32) in[9]));
output[10] = 2 * (((limb) ((s32) in[5])) * ((s32) in[5]) +
((limb) ((s32) in[4])) * ((s32) in[6]) +
((limb) ((s32) in[2])) * ((s32) in[8]) +
2 * (((limb) ((s32) in[3])) * ((s32) in[7]) +
((limb) ((s32) in[1])) * ((s32) in[9])));
output[11] = 2 * (((limb) ((s32) in[5])) * ((s32) in[6]) +
((limb) ((s32) in[4])) * ((s32) in[7]) +
((limb) ((s32) in[3])) * ((s32) in[8]) +
((limb) ((s32) in[2])) * ((s32) in[9]));
output[12] = ((limb) ((s32) in[6])) * ((s32) in[6]) +
2 * (((limb) ((s32) in[4])) * ((s32) in[8]) +
2 * (((limb) ((s32) in[5])) * ((s32) in[7]) +
((limb) ((s32) in[3])) * ((s32) in[9])));
output[13] = 2 * (((limb) ((s32) in[6])) * ((s32) in[7]) +
((limb) ((s32) in[5])) * ((s32) in[8]) +
((limb) ((s32) in[4])) * ((s32) in[9]));
output[14] = 2 * (((limb) ((s32) in[7])) * ((s32) in[7]) +
((limb) ((s32) in[6])) * ((s32) in[8]) +
2 * ((limb) ((s32) in[5])) * ((s32) in[9]));
output[15] = 2 * (((limb) ((s32) in[7])) * ((s32) in[8]) +
((limb) ((s32) in[6])) * ((s32) in[9]));
output[16] = ((limb) ((s32) in[8])) * ((s32) in[8]) +
4 * ((limb) ((s32) in[7])) * ((s32) in[9]);
output[17] = 2 * ((limb) ((s32) in[8])) * ((s32) in[9]);
output[18] = 2 * ((limb) ((s32) in[9])) * ((s32) in[9]);
}
static void fsquare(limb *output, const limb *in) {
limb t[19];
fsquare_inner(t, in);
/* |t[i]| < 14*2^54 because the largest product of two limbs will be <
* 2^(27+27) and fsquare_inner adds together, at most, 14 of those
* products. */
freduce_degree(t);
freduce_coefficients(t);
/* |t[i]| < 2^26 */
memcpy(output, t, sizeof(limb) * 10);
}
static inline void fexpand(limb *output, const u8 *input) {
#define F(n,start,shift,mask) \
output[n] = ((((limb) input[start + 0]) | \
((limb) input[start + 1]) << 8 | \
((limb) input[start + 2]) << 16 | \
((limb) input[start + 3]) << 24) >> shift) & mask;
F(0, 0, 0, 0x3ffffff);
F(1, 3, 2, 0x1ffffff);
F(2, 6, 3, 0x3ffffff);
F(3, 9, 5, 0x1ffffff);
F(4, 12, 6, 0x3ffffff);
F(5, 16, 0, 0x1ffffff);
F(6, 19, 1, 0x3ffffff);
F(7, 22, 3, 0x1ffffff);
F(8, 25, 4, 0x3ffffff);
F(9, 28, 6, 0x1ffffff);
#undef F
}
#if (-32 >> 1) != -16
#error "This code only works when >> does sign-extension on negative numbers"
#endif
static inline s32 s32_eq(s32 a, s32 b) {
a = ~(a ^ b);
a &= a << 16;
a &= a << 8;
a &= a << 4;
a &= a << 2;
a &= a << 1;
return a >> 31;
}
static inline s32 s32_gte(s32 a, s32 b) {
a -= b;
/* a >= 0 iff a >= b. */
return ~(a >> 31);
}
static inline void fcontract(u8 *output, limb *input_limbs) {
int i;
int j;
s32 input[10];
s32 mask;
/* |input_limbs[i]| < 2^26, so it's valid to convert to an s32. */
for (i = 0; i < 10; i++) {
input[i] = input_limbs[i];
}
for (j = 0; j < 2; ++j) {
for (i = 0; i < 9; ++i) {
if ((i & 1) == 1) {
/* This calculation is a time-invariant way to make input[i]
* non-negative by borrowing from the next-larger limb. */
const s32 mask = input[i] >> 31;
const s32 carry = -((input[i] & mask) >> 25);
input[i] = input[i] + (carry << 25);
input[i+1] = input[i+1] - carry;
} else {
const s32 mask = input[i] >> 31;
const s32 carry = -((input[i] & mask) >> 26);
input[i] = input[i] + (carry << 26);
input[i+1] = input[i+1] - carry;
}
}
/* There's no greater limb for input[9] to borrow from, but we can multiply
* by 19 and borrow from input[0], which is valid mod 2^255-19. */
{
const s32 mask = input[9] >> 31;
const s32 carry = -((input[9] & mask) >> 25);
input[9] = input[9] + (carry << 25);
input[0] = input[0] - (carry * 19);
}
/* After the first iteration, input[1..9] are non-negative and fit within
* 25 or 26 bits, depending on position. However, input[0] may be
* negative. */
}
/* The first borrow-propagation pass above ended with every limb
except (possibly) input[0] non-negative.
If input[0] was negative after the first pass, then it was because of a
carry from input[9]. On entry, input[9] < 2^26 so the carry was, at most,
one, since (2**26-1) >> 25 = 1. Thus input[0] >= -19.
In the second pass, each limb is decreased by at most one. Thus the second
borrow-propagation pass could only have wrapped around to decrease
input[0] again if the first pass left input[0] negative *and* input[1]
through input[9] were all zero. In that case, input[1] is now 2^25 - 1,
and this last borrow-propagation step will leave input[1] non-negative. */
{
const s32 mask = input[0] >> 31;
const s32 carry = -((input[0] & mask) >> 26);
input[0] = input[0] + (carry << 26);
input[1] = input[1] - carry;
}
/* All input[i] are now non-negative. However, there might be values between
* 2^25 and 2^26 in a limb which is, nominally, 25 bits wide. */
for (j = 0; j < 2; j++) {
for (i = 0; i < 9; i++) {
if ((i & 1) == 1) {
const s32 carry = input[i] >> 25;
input[i] &= 0x1ffffff;
input[i+1] += carry;
} else {
const s32 carry = input[i] >> 26;
input[i] &= 0x3ffffff;
input[i+1] += carry;
}
}
{
const s32 carry = input[9] >> 25;
input[9] &= 0x1ffffff;
input[0] += 19*carry;
}
}
/* If the first carry-chain pass, just above, ended up with a carry from
* input[9], and that caused input[0] to be out-of-bounds, then input[0] was
* < 2^26 + 2*19, because the carry was, at most, two.
*
* If the second pass carried from input[9] again then input[0] is < 2*19 and
* the input[9] -> input[0] carry didn't push input[0] out of bounds. */
/* It still remains the case that input might be between 2^255-19 and 2^255.
* In this case, input[1..9] must take their maximum value and input[0] must
* be >= (2^255-19) & 0x3ffffff, which is 0x3ffffed. */
mask = s32_gte(input[0], 0x3ffffed);
for (i = 1; i < 10; i++) {
if ((i & 1) == 1) {
mask &= s32_eq(input[i], 0x1ffffff);
} else {
mask &= s32_eq(input[i], 0x3ffffff);
}
}
/* mask is either 0xffffffff (if input >= 2^255-19) and zero otherwise. Thus
* this conditionally subtracts 2^255-19. */
input[0] -= mask & 0x3ffffed;
for (i = 1; i < 10; i++) {
if ((i & 1) == 1) {
input[i] -= mask & 0x1ffffff;
} else {
input[i] -= mask & 0x3ffffff;
}
}
input[1] <<= 2;
input[2] <<= 3;
input[3] <<= 5;
input[4] <<= 6;
input[6] <<= 1;
input[7] <<= 3;
input[8] <<= 4;
input[9] <<= 6;
#define F(i, s) \
output[s+0] |= input[i] & 0xff; \
output[s+1] = (input[i] >> 8) & 0xff; \
output[s+2] = (input[i] >> 16) & 0xff; \
output[s+3] = (input[i] >> 24) & 0xff;
output[0] = 0;
output[16] = 0;
F(0,0);
F(1,3);
F(2,6);
F(3,9);
F(4,12);
F(5,16);
F(6,19);
F(7,22);
F(8,25);
F(9,28);
#undef F
}
static inline void fmonty(limb *x2, limb *z2, /* output 2Q */
limb *x3, limb *z3, /* output Q + Q' */
limb *x, limb *z, /* input Q */
limb *xprime, limb *zprime, /* input Q' */
const limb *qmqp /* input Q - Q' */) {
limb origx[10], origxprime[10], zzz[19], xx[19], zz[19], xxprime[19],
zzprime[19], zzzprime[19], xxxprime[19];
memcpy(origx, x, 10 * sizeof(limb));
fsum(x, z);
/* |x[i]| < 2^27 */
fdifference(z, origx); /* does x - z */
/* |z[i]| < 2^27 */
memcpy(origxprime, xprime, sizeof(limb) * 10);
fsum(xprime, zprime);
/* |xprime[i]| < 2^27 */
fdifference(zprime, origxprime);
/* |zprime[i]| < 2^27 */
fproduct(xxprime, xprime, z);
/* |xxprime[i]| < 14*2^54: the largest product of two limbs will be <
* 2^(27+27) and fproduct adds together, at most, 14 of those products.
* (Approximating that to 2^58 doesn't work out.) */
fproduct(zzprime, x, zprime);
/* |zzprime[i]| < 14*2^54 */
freduce_degree(xxprime);
freduce_coefficients(xxprime);
/* |xxprime[i]| < 2^26 */
freduce_degree(zzprime);
freduce_coefficients(zzprime);
/* |zzprime[i]| < 2^26 */
memcpy(origxprime, xxprime, sizeof(limb) * 10);
fsum(xxprime, zzprime);
/* |xxprime[i]| < 2^27 */
fdifference(zzprime, origxprime);
/* |zzprime[i]| < 2^27 */
fsquare(xxxprime, xxprime);
/* |xxxprime[i]| < 2^26 */
fsquare(zzzprime, zzprime);
/* |zzzprime[i]| < 2^26 */
fproduct(zzprime, zzzprime, qmqp);
/* |zzprime[i]| < 14*2^52 */
freduce_degree(zzprime);
freduce_coefficients(zzprime);
/* |zzprime[i]| < 2^26 */
memcpy(x3, xxxprime, sizeof(limb) * 10);
memcpy(z3, zzprime, sizeof(limb) * 10);
fsquare(xx, x);
/* |xx[i]| < 2^26 */
fsquare(zz, z);
/* |zz[i]| < 2^26 */
fproduct(x2, xx, zz);
/* |x2[i]| < 14*2^52 */
freduce_degree(x2);
freduce_coefficients(x2);
/* |x2[i]| < 2^26 */
fdifference(zz, xx); // does zz = xx - zz
/* |zz[i]| < 2^27 */
memset(zzz + 10, 0, sizeof(limb) * 9);
fscalar_product(zzz, zz, 121665);
/* |zzz[i]| < 2^(27+17) */
/* No need to call freduce_degree here:
fscalar_product doesn't increase the degree of its input. */
freduce_coefficients(zzz);
/* |zzz[i]| < 2^26 */
fsum(zzz, xx);
/* |zzz[i]| < 2^27 */
fproduct(z2, zz, zzz);
/* |z2[i]| < 14*2^(26+27) */
freduce_degree(z2);
freduce_coefficients(z2);
/* |z2|i| < 2^26 */
}
static inline void swap_conditional(limb a[19], limb b[19], limb iswap) {
unsigned i;
const s32 swap = (s32) -iswap;
for (i = 0; i < 10; ++i) {
const s32 x = swap & ( ((s32)a[i]) ^ ((s32)b[i]) );
a[i] = ((s32)a[i]) ^ x;
b[i] = ((s32)b[i]) ^ x;
}
}
static inline void cmult(limb *resultx, limb *resultz, const u8 *n, const limb *q) {
limb a[19] = {0}, b[19] = {1}, c[19] = {1}, d[19] = {0};
limb *nqpqx = a, *nqpqz = b, *nqx = c, *nqz = d, *t;
limb e[19] = {0}, f[19] = {1}, g[19] = {0}, h[19] = {1};
limb *nqpqx2 = e, *nqpqz2 = f, *nqx2 = g, *nqz2 = h;
unsigned i, j;
memcpy(nqpqx, q, sizeof(limb) * 10);
for (i = 0; i < 32; ++i) {
u8 byte = n[31 - i];
for (j = 0; j < 8; ++j) {
const limb bit = byte >> 7;
swap_conditional(nqx, nqpqx, bit);
swap_conditional(nqz, nqpqz, bit);
fmonty(nqx2, nqz2,
nqpqx2, nqpqz2,
nqx, nqz,
nqpqx, nqpqz,
q);
swap_conditional(nqx2, nqpqx2, bit);
swap_conditional(nqz2, nqpqz2, bit);
t = nqx;
nqx = nqx2;
nqx2 = t;
t = nqz;
nqz = nqz2;
nqz2 = t;
t = nqpqx;
nqpqx = nqpqx2;
nqpqx2 = t;
t = nqpqz;
nqpqz = nqpqz2;
nqpqz2 = t;
byte <<= 1;
}
}
memcpy(resultx, nqx, sizeof(limb) * 10);
memcpy(resultz, nqz, sizeof(limb) * 10);
}
static inline void crecip(limb *out, const limb *z) {
limb z2[10];
limb z9[10];
limb z11[10];
limb z2_5_0[10];
limb z2_10_0[10];
limb z2_20_0[10];
limb z2_50_0[10];
limb z2_100_0[10];
limb t0[10];
limb t1[10];
int i;
/* 2 */ fsquare(z2,z);
/* 4 */ fsquare(t1,z2);
/* 8 */ fsquare(t0,t1);
/* 9 */ fmul(z9,t0,z);
/* 11 */ fmul(z11,z9,z2);
/* 22 */ fsquare(t0,z11);
/* 2^5 - 2^0 = 31 */ fmul(z2_5_0,t0,z9);
/* 2^6 - 2^1 */ fsquare(t0,z2_5_0);
/* 2^7 - 2^2 */ fsquare(t1,t0);
/* 2^8 - 2^3 */ fsquare(t0,t1);
/* 2^9 - 2^4 */ fsquare(t1,t0);
/* 2^10 - 2^5 */ fsquare(t0,t1);
/* 2^10 - 2^0 */ fmul(z2_10_0,t0,z2_5_0);
/* 2^11 - 2^1 */ fsquare(t0,z2_10_0);
/* 2^12 - 2^2 */ fsquare(t1,t0);
/* 2^20 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
/* 2^20 - 2^0 */ fmul(z2_20_0,t1,z2_10_0);
/* 2^21 - 2^1 */ fsquare(t0,z2_20_0);
/* 2^22 - 2^2 */ fsquare(t1,t0);
/* 2^40 - 2^20 */ for (i = 2;i < 20;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
/* 2^40 - 2^0 */ fmul(t0,t1,z2_20_0);
/* 2^41 - 2^1 */ fsquare(t1,t0);
/* 2^42 - 2^2 */ fsquare(t0,t1);
/* 2^50 - 2^10 */ for (i = 2;i < 10;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
/* 2^50 - 2^0 */ fmul(z2_50_0,t0,z2_10_0);
/* 2^51 - 2^1 */ fsquare(t0,z2_50_0);
/* 2^52 - 2^2 */ fsquare(t1,t0);
/* 2^100 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
/* 2^100 - 2^0 */ fmul(z2_100_0,t1,z2_50_0);
/* 2^101 - 2^1 */ fsquare(t1,z2_100_0);
/* 2^102 - 2^2 */ fsquare(t0,t1);
/* 2^200 - 2^100 */ for (i = 2;i < 100;i += 2) { fsquare(t1,t0); fsquare(t0,t1); }
/* 2^200 - 2^0 */ fmul(t1,t0,z2_100_0);
/* 2^201 - 2^1 */ fsquare(t0,t1);
/* 2^202 - 2^2 */ fsquare(t1,t0);
/* 2^250 - 2^50 */ for (i = 2;i < 50;i += 2) { fsquare(t0,t1); fsquare(t1,t0); }
/* 2^250 - 2^0 */ fmul(t0,t1,z2_50_0);
/* 2^251 - 2^1 */ fsquare(t1,t0);
/* 2^252 - 2^2 */ fsquare(t0,t1);
/* 2^253 - 2^3 */ fsquare(t1,t0);
/* 2^254 - 2^4 */ fsquare(t0,t1);
/* 2^255 - 2^5 */ fsquare(t1,t0);
/* 2^255 - 21 */ fmul(out,t1,z11);
}
static void crypto_scalarmult(u8 *mypublic, const u8 *secret, const u8 *basepoint) {
limb bp[10], x[10], z[11], zmone[10];
uint8_t e[32];
int i;
for (i = 0; i < 32; ++i) e[i] = secret[i];
e[0] &= 248;
e[31] &= 127;
e[31] |= 64;
fexpand(bp, basepoint);
cmult(x, z, e, bp);
crecip(zmone, z);
fmul(z, x, zmone);
fcontract(mypublic, z);
}
#if 0
void add(unsigned int out[32],const unsigned int a[32],const unsigned int b[32])
{
unsigned int j;
@ -285,11 +994,12 @@ int crypto_scalarmult(unsigned char *q,const unsigned char *n,const unsigned cha
for (i = 0;i < 32;++i) q[i] = work[64 + i];
return 0;
}
#endif
static const unsigned char base[32] = {9};
int crypto_scalarmult_base(unsigned char *q,const unsigned char *n)
static inline void crypto_scalarmult_base(unsigned char *q,const unsigned char *n)
{
return crypto_scalarmult(q,n,base);
crypto_scalarmult(q,n,base);
}
//////////////////////////////////////////////////////////////////////////////
@ -792,7 +1502,6 @@ void sc25519_mul(sc25519 *r, const sc25519 *x, const sc25519 *y)
for(j=0;j<32;j++)
t[i+j] += x->v[i] * y->v[j];
/* Reduce coefficients */
for(i=0;i<63;i++)
{
carry = t[i] >> 8;
@ -1996,7 +2705,7 @@ void get_hram(unsigned char *hram, const unsigned char *sm, const unsigned char
} // anonymous namespace
#ifdef ZT_USE_FAST_X64_ED25519
extern "C" void ed25519_amd64_asm_sign(const unsigned char *sk,const unsigned char *pk,const unsigned char *m,const unsigned int mlen,unsigned char *sig);
extern "C" void ed25519_amd64_asm_sign(const unsigned char *sk,const unsigned char *pk,const unsigned char *digest,unsigned char *sig);
#endif
namespace ZeroTier {
@ -2019,8 +2728,11 @@ void C25519::agree(const C25519::Private &mine,const C25519::Public &their,void
void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPublic,const void *msg,unsigned int len,void *signature)
{
unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg)
SHA512::hash(digest,msg,len);
#ifdef ZT_USE_FAST_X64_ED25519
ed25519_amd64_asm_sign(myPrivate.data + 32,myPublic.data + 32,(const unsigned char *)msg,len,(unsigned char *)signature);
ed25519_amd64_asm_sign(myPrivate.data + 32,myPublic.data + 32,digest,(unsigned char *)signature);
#else
sc25519 sck, scs, scsk;
ge25519 ger;
@ -2030,9 +2742,6 @@ void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPubli
unsigned char hmg[crypto_hash_sha512_BYTES];
unsigned char hram[crypto_hash_sha512_BYTES];
unsigned char *sig = (unsigned char *)signature;
unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg)
SHA512::hash(digest,msg,len);
SHA512::hash(extsk,myPrivate.data + 32,32);
extsk[0] &= 248;
@ -2071,18 +2780,17 @@ void C25519::sign(const C25519::Private &myPrivate,const C25519::Public &myPubli
bool C25519::verify(const C25519::Public &their,const void *msg,unsigned int len,const void *signature)
{
const unsigned char *const sig = (const unsigned char *)signature;
unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg)
SHA512::hash(digest,msg,len);
if (!Utils::secureEq(sig + 64,digest,32))
return false;
unsigned char t2[32];
ge25519 get1, get2;
sc25519 schram, scs;
unsigned char hram[crypto_hash_sha512_BYTES];
unsigned char m[96];
unsigned char digest[64]; // we sign the first 32 bytes of SHA-512(msg)
const unsigned char *sig = (const unsigned char *)signature;
// First check the message's integrity
SHA512::hash(digest,msg,len);
if (!Utils::secureEq(sig + 64,digest,32))
return false;
if (ge25519_unpackneg_vartime(&get1,their.data + 32))
return false;

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -72,9 +72,15 @@ class Capability : public Credential
public:
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_CAPABILITY; }
Capability()
Capability() :
_nwid(0),
_ts(0),
_id(0),
_maxCustodyChainLength(0),
_ruleCount(0)
{
memset(this,0,sizeof(Capability));
memset(_rules,0,sizeof(_rules));
memset(_custody,0,sizeof(_custody));
}
/**
@ -85,16 +91,15 @@ public:
* @param rules Network flow rules for this capability
* @param ruleCount Number of flow rules
*/
Capability(uint32_t id,uint64_t nwid,int64_t ts,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount)
Capability(uint32_t id,uint64_t nwid,int64_t ts,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount) :
_nwid(nwid),
_ts(ts),
_id(id),
_maxCustodyChainLength((mccl > 0) ? ((mccl < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) ? mccl : (unsigned int)ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) : 1),
_ruleCount((ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES)
{
memset(this,0,sizeof(Capability));
_nwid = nwid;
_ts = ts;
_id = id;
_maxCustodyChainLength = (mccl > 0) ? ((mccl < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) ? mccl : (unsigned int)ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) : 1;
_ruleCount = (ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES;
if (_ruleCount)
ZT_FAST_MEMCPY(_rules,rules,sizeof(ZT_VirtualNetworkRule) * _ruleCount);
if (_ruleCount > 0)
memcpy(_rules,rules,sizeof(ZT_VirtualNetworkRule) * _ruleCount);
}
/**
@ -320,16 +325,16 @@ public:
break;
case ZT_NETWORK_RULE_MATCH_MAC_SOURCE:
case ZT_NETWORK_RULE_MATCH_MAC_DEST:
ZT_FAST_MEMCPY(rules[ruleCount].v.mac,b.field(p,6),6);
memcpy(rules[ruleCount].v.mac,b.field(p,6),6);
break;
case ZT_NETWORK_RULE_MATCH_IPV4_SOURCE:
case ZT_NETWORK_RULE_MATCH_IPV4_DEST:
ZT_FAST_MEMCPY(&(rules[ruleCount].v.ipv4.ip),b.field(p,4),4);
memcpy(&(rules[ruleCount].v.ipv4.ip),b.field(p,4),4);
rules[ruleCount].v.ipv4.mask = (uint8_t)b[p + 4];
break;
case ZT_NETWORK_RULE_MATCH_IPV6_SOURCE:
case ZT_NETWORK_RULE_MATCH_IPV6_DEST:
ZT_FAST_MEMCPY(rules[ruleCount].v.ipv6.ip,b.field(p,16),16);
memcpy(rules[ruleCount].v.ipv6.ip,b.field(p,16),16);
rules[ruleCount].v.ipv6.mask = (uint8_t)b[p + 16];
break;
case ZT_NETWORK_RULE_MATCH_IP_TOS:
@ -423,7 +428,7 @@ public:
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{
memset(this,0,sizeof(Capability));
*this = Capability();
unsigned int p = startAt;
@ -452,7 +457,7 @@ public:
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
p += 2;
ZT_FAST_MEMCPY(_custody[i].signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
memcpy(_custody[i].signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
} else {
p += 2 + b.template at<uint16_t>(p);
}

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -112,15 +112,8 @@ public:
/**
* Create an empty certificate of membership
*/
CertificateOfMembership()
{
memset(this,0,sizeof(CertificateOfMembership));
}
CertificateOfMembership(const CertificateOfMembership &c)
{
ZT_FAST_MEMCPY(this,&c,sizeof(CertificateOfMembership));
}
CertificateOfMembership() :
_qualifierCount(0) {}
/**
* Create from required fields common to all networks
@ -145,12 +138,6 @@ public:
memset(_signature.data,0,ZT_C25519_SIGNATURE_LEN);
}
inline CertificateOfMembership &operator=(const CertificateOfMembership &c)
{
ZT_FAST_MEMCPY(this,&c,sizeof(CertificateOfMembership));
return *this;
}
/**
* Create from binary-serialized COM in buffer
*
@ -329,7 +316,7 @@ public:
p += ZT_ADDRESS_LENGTH;
if (_signedBy) {
ZT_FAST_MEMCPY(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
}

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -69,19 +69,16 @@ public:
CertificateOfOwnership()
{
memset(this,0,sizeof(CertificateOfOwnership));
memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership));
}
CertificateOfOwnership(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id) :
_networkId(nwid),
_ts(ts),
_flags(0),
_id(id),
_thingCount(0),
_issuedTo(issuedTo)
CertificateOfOwnership(const uint64_t nwid,const int64_t ts,const Address &issuedTo,const uint32_t id)
{
memset(_thingTypes,0,sizeof(_thingTypes));
memset(_thingValues,0,sizeof(_thingValues));
memset(reinterpret_cast<void *>(this),0,sizeof(CertificateOfOwnership));
_networkId = nwid;
_ts = ts;
_id = id;
_issuedTo = issuedTo;
}
inline uint64_t networkId() const { return _networkId; }
@ -115,11 +112,11 @@ public:
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
if (ip.ss_family == AF_INET) {
_thingTypes[_thingCount] = THING_IPV4_ADDRESS;
ZT_FAST_MEMCPY(_thingValues[_thingCount],&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
memcpy(_thingValues[_thingCount],&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
++_thingCount;
} else if (ip.ss_family == AF_INET6) {
_thingTypes[_thingCount] = THING_IPV6_ADDRESS;
ZT_FAST_MEMCPY(_thingValues[_thingCount],reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr,16);
memcpy(_thingValues[_thingCount],reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr,16);
++_thingCount;
}
}
@ -188,7 +185,7 @@ public:
{
unsigned int p = startAt;
memset(this,0,sizeof(CertificateOfOwnership));
*this = CertificateOfOwnership();
_networkId = b.template at<uint64_t>(p); p += 8;
_ts = b.template at<uint64_t>(p); p += 8;
@ -198,7 +195,7 @@ public:
for(unsigned int i=0,j=_thingCount;i<j;++i) {
if (i < ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
_thingTypes[i] = (uint8_t)b[p++];
ZT_FAST_MEMCPY(_thingValues[i],b.field(p,ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE),ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
memcpy(_thingValues[i],b.field(p,ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE),ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE;
}
}
@ -209,7 +206,7 @@ public:
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
p += 2;
ZT_FAST_MEMCPY(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
} else {
p += 2 + b.template at<uint16_t>(p);
}

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -72,14 +72,6 @@
#include <machine/endian.h>
#endif
// Defined this macro to disable "type punning" on a number of targets that
// have issues with unaligned memory access.
#if defined(__arm__) || defined(__ARMEL__) || (defined(__APPLE__) && ( (defined(TARGET_OS_IPHONE) && (TARGET_OS_IPHONE != 0)) || (defined(TARGET_OS_WATCH) && (TARGET_OS_WATCH != 0)) || (defined(TARGET_IPHONE_SIMULATOR) && (TARGET_IPHONE_SIMULATOR != 0)) ) )
#ifndef ZT_NO_TYPE_PUNNING
#define ZT_NO_TYPE_PUNNING
#endif
#endif
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
#ifndef __UNIX_LIKE__
#define __UNIX_LIKE__
@ -107,13 +99,23 @@
#pragma warning(disable : 4101)
#undef __UNIX_LIKE__
#undef __BSD__
#define ZT_PATH_SEPARATOR '\\'
#define ZT_PATH_SEPARATOR_S "\\"
#define ZT_EOL_S "\r\n"
#include <WinSock2.h>
#include <Windows.h>
#endif
#ifdef __NetBSD__
#ifndef RTF_MULTICAST
#define RTF_MULTICAST 0x20000000
#endif
#endif
// Define ZT_NO_TYPE_PUNNING to disable reckless casts on anything other than x86/x64.
#if (!(defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64) || defined(_M_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)))
#ifndef ZT_NO_TYPE_PUNNING
#define ZT_NO_TYPE_PUNNING
#endif
#endif
// Assume little endian if not defined
#if (defined(__APPLE__) || defined(__WINDOWS__)) && (!defined(__BYTE_ORDER))
#undef __BYTE_ORDER
@ -124,7 +126,11 @@
#define __BYTE_ORDER 1234
#endif
#ifdef __UNIX_LIKE__
#ifdef __WINDOWS__
#define ZT_PATH_SEPARATOR '\\'
#define ZT_PATH_SEPARATOR_S "\\"
#define ZT_EOL_S "\r\n"
#else
#define ZT_PATH_SEPARATOR '/'
#define ZT_PATH_SEPARATOR_S "/"
#define ZT_EOL_S "\n"
@ -134,10 +140,6 @@
#include <endian.h>
#endif
#ifdef __NetBSD__
#define RTF_MULTICAST 0x20000000
#endif
#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)
#ifndef likely
#define likely(x) __builtin_expect((x),1)
@ -187,19 +189,13 @@
/**
* Size of RX queue
*
* This is about 2mb, and can be decreased for small devices. A queue smaller
* than about 4 is probably going to cause a lot of lost packets.
*/
#define ZT_RX_QUEUE_SIZE 64
#define ZT_RX_QUEUE_SIZE 32
/**
* Size of TX queue
*
* This is about 2mb, and can be decreased for small devices. A queue smaller
* than about 4 is probably going to cause a lot of lost packets.
*/
#define ZT_TX_QUEUE_SIZE 64
#define ZT_TX_QUEUE_SIZE 32
/**
* Length of secret key in bytes -- 256-bit -- do not change
@ -231,11 +227,6 @@
*/
#define ZT_RECEIVE_QUEUE_TIMEOUT 5000
/**
* Maximum latency to allow for OK(HELLO) before packet is discarded
*/
#define ZT_HELLO_MAX_ALLOWABLE_LATENCY 120000
/**
* Maximum number of ZT hops allowed (this is not IP hops/TTL)
*
@ -258,11 +249,6 @@
*/
#define ZT_MULTICAST_EXPLICIT_GATHER_DELAY (ZT_MULTICAST_LIKE_EXPIRE / 10)
/**
* Expiration for credentials presented for MULTICAST_LIKE or MULTICAST_GATHER (for non-network-members)
*/
#define ZT_MULTICAST_CREDENTIAL_EXPIRATON ZT_MULTICAST_LIKE_EXPIRE
/**
* Timeout for outgoing multicasts
*
@ -275,6 +261,11 @@
*/
#define ZT_PING_CHECK_INVERVAL 5000
/**
* How often the local.conf file is checked for changes (service, should be moved there)
*/
#define ZT_LOCAL_CONF_FILE_CHECK_INTERVAL 10000
/**
* How frequently to check for changes to the system's network interfaces. When
* the service decides to use this constant it's because we want to react more
@ -323,7 +314,7 @@
* since we will record a 0 bit/s measurement if no valid latency measurement was made within this
* window of time.
*/
#define ZT_PATH_LATENCY_SAMPLE_INTERVAL ZT_MULTIPATH_PEER_PING_PERIOD * 2
#define ZT_PATH_LATENCY_SAMPLE_INTERVAL (ZT_MULTIPATH_PEER_PING_PERIOD * 2)
/**
* Interval used for rate-limiting the computation of path quality estimates.
@ -360,16 +351,16 @@
/**
* How much each factor contributes to the "stability" score of a path
*/
#define ZT_PATH_CONTRIB_PDV 1.0 / 3.0
#define ZT_PATH_CONTRIB_LATENCY 1.0 / 3.0
#define ZT_PATH_CONTRIB_THROUGHPUT_DISTURBANCE 1.0 / 3.0
#define ZT_PATH_CONTRIB_PDV (1.0 / 3.0)
#define ZT_PATH_CONTRIB_LATENCY (1.0 / 3.0)
#define ZT_PATH_CONTRIB_THROUGHPUT_DISTURBANCE (1.0 / 3.0)
/**
* How much each factor contributes to the "quality" score of a path
*/
#define ZT_PATH_CONTRIB_STABILITY 0.75 / 3.0
#define ZT_PATH_CONTRIB_THROUGHPUT 1.50 / 3.0
#define ZT_PATH_CONTRIB_SCOPE 0.75 / 3.0
#define ZT_PATH_CONTRIB_STABILITY (0.75 / 3.0)
#define ZT_PATH_CONTRIB_THROUGHPUT (1.50 / 3.0)
#define ZT_PATH_CONTRIB_SCOPE (0.75 / 3.0)
/**
* How often a QoS packet is sent
@ -385,7 +376,7 @@
/**
* How many ID:sojourn time pairs in a single QoS packet
*/
#define ZT_PATH_QOS_TABLE_SIZE (ZT_PATH_MAX_QOS_PACKET_SZ * 8) / (64 + 16)
#define ZT_PATH_QOS_TABLE_SIZE ((ZT_PATH_MAX_QOS_PACKET_SZ * 8) / (64 + 16))
/**
* Maximum number of outgoing packets we monitor for QoS information
@ -395,12 +386,12 @@
/**
* Timeout for QoS records
*/
#define ZT_PATH_QOS_TIMEOUT ZT_PATH_QOS_INTERVAL * 2
#define ZT_PATH_QOS_TIMEOUT (ZT_PATH_QOS_INTERVAL * 2)
/**
* How often the service tests the path throughput
*/
#define ZT_PATH_THROUGHPUT_MEASUREMENT_INTERVAL ZT_PATH_ACK_INTERVAL * 8
#define ZT_PATH_THROUGHPUT_MEASUREMENT_INTERVAL (ZT_PATH_ACK_INTERVAL * 8)
/**
* Minimum amount of time between each ACK packet
@ -470,8 +461,11 @@
/**
* Delay between full-fledge pings of directly connected peers.
*
* With multipath bonding enabled ping peers more often to measure
* packet loss and latency.
* packet loss and latency. This uses more bandwidth so is disabled
* by default to avoid increasing idle bandwidth use for regular
* links.
*/
#define ZT_MULTIPATH_PEER_PING_PERIOD 5000
@ -488,7 +482,11 @@
/**
* Timeout for overall peer activity (measured from last receive)
*/
#ifndef ZT_SDK
#define ZT_PEER_ACTIVITY_TIMEOUT 500000
#else
#define ZT_PEER_ACTIVITY_TIMEOUT 30000
#endif
/**
* General rate limit timeout for multiple packet types (HELLO, etc.)
@ -534,14 +532,19 @@
#define ZT_MAX_BRIDGE_ROUTES 67108864
/**
* If there is no known route, spam to up to this many active bridges
* If there is no known L2 bridging route, spam to up to this many active bridges
*/
#define ZT_MAX_BRIDGE_SPAM 32
/**
* Interval between direct path pushes in milliseconds
*/
#define ZT_DIRECT_PATH_PUSH_INTERVAL 120000
#define ZT_DIRECT_PATH_PUSH_INTERVAL 15000
/**
* Interval between direct path pushes in milliseconds if we already have a path
*/
#define ZT_DIRECT_PATH_PUSH_INTERVAL_HAVEPATH 120000
/**
* Time horizon for push direct paths cutoff
@ -626,16 +629,7 @@
*/
#define ZT_THREAD_MIN_STACK_SIZE 1048576
/* Ethernet frame types that might be relevant to us */
#define ZT_ETHERTYPE_IPV4 0x0800
#define ZT_ETHERTYPE_ARP 0x0806
#define ZT_ETHERTYPE_RARP 0x8035
#define ZT_ETHERTYPE_ATALK 0x809b
#define ZT_ETHERTYPE_AARP 0x80f3
#define ZT_ETHERTYPE_IPX_A 0x8137
#define ZT_ETHERTYPE_IPX_B 0x8138
#define ZT_ETHERTYPE_IPV6 0x86dd
// Exceptions thrown in core ZT code
#define ZT_EXCEPTION_OUT_OF_BOUNDS 100
#define ZT_EXCEPTION_OUT_OF_MEMORY 101
#define ZT_EXCEPTION_PRIVATE_KEY_REQUIRED 102

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -248,7 +248,7 @@ public:
if (b[p++] != 0)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
ZT_FAST_MEMCPY(_publicKey.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN);
memcpy(_publicKey.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN);
p += ZT_C25519_PUBLIC_KEY_LEN;
unsigned int privateKeyLength = (unsigned int)b[p++];
@ -256,7 +256,7 @@ public:
if (privateKeyLength != ZT_C25519_PRIVATE_KEY_LEN)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
_privateKey = new C25519::Private();
ZT_FAST_MEMCPY(_privateKey->data,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
memcpy(_privateKey->data,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
p += ZT_C25519_PRIVATE_KEY_LEN;
}

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -91,31 +91,37 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
}
const Packet::Verb v = verb();
bool r = true;
switch(v) {
//case Packet::VERB_NOP:
default: // ignore unknown verbs, but if they pass auth check they are "received"
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),v,0,Packet::VERB_NOP,false,0);
return true;
case Packet::VERB_HELLO: return _doHELLO(RR,tPtr,true);
case Packet::VERB_ACK: return _doACK(RR,tPtr,peer);
case Packet::VERB_QOS_MEASUREMENT: return _doQOS_MEASUREMENT(RR,tPtr,peer);
case Packet::VERB_ERROR: return _doERROR(RR,tPtr,peer);
case Packet::VERB_OK: return _doOK(RR,tPtr,peer);
case Packet::VERB_WHOIS: return _doWHOIS(RR,tPtr,peer);
case Packet::VERB_RENDEZVOUS: return _doRENDEZVOUS(RR,tPtr,peer);
case Packet::VERB_FRAME: return _doFRAME(RR,tPtr,peer);
case Packet::VERB_EXT_FRAME: return _doEXT_FRAME(RR,tPtr,peer);
case Packet::VERB_ECHO: return _doECHO(RR,tPtr,peer);
case Packet::VERB_MULTICAST_LIKE: return _doMULTICAST_LIKE(RR,tPtr,peer);
case Packet::VERB_NETWORK_CREDENTIALS: return _doNETWORK_CREDENTIALS(RR,tPtr,peer);
case Packet::VERB_NETWORK_CONFIG_REQUEST: return _doNETWORK_CONFIG_REQUEST(RR,tPtr,peer);
case Packet::VERB_NETWORK_CONFIG: return _doNETWORK_CONFIG(RR,tPtr,peer);
case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,tPtr,peer);
case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,tPtr,peer);
case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,tPtr,peer);
case Packet::VERB_USER_MESSAGE: return _doUSER_MESSAGE(RR,tPtr,peer);
case Packet::VERB_REMOTE_TRACE: return _doREMOTE_TRACE(RR,tPtr,peer);
break;
case Packet::VERB_HELLO: r = _doHELLO(RR,tPtr,true); break;
case Packet::VERB_ACK: r = _doACK(RR,tPtr,peer); break;
case Packet::VERB_QOS_MEASUREMENT: r = _doQOS_MEASUREMENT(RR,tPtr,peer); break;
case Packet::VERB_ERROR: r = _doERROR(RR,tPtr,peer); break;
case Packet::VERB_OK: r = _doOK(RR,tPtr,peer); break;
case Packet::VERB_WHOIS: r = _doWHOIS(RR,tPtr,peer); break;
case Packet::VERB_RENDEZVOUS: r = _doRENDEZVOUS(RR,tPtr,peer); break;
case Packet::VERB_FRAME: r = _doFRAME(RR,tPtr,peer); break;
case Packet::VERB_EXT_FRAME: r = _doEXT_FRAME(RR,tPtr,peer); break;
case Packet::VERB_ECHO: r = _doECHO(RR,tPtr,peer); break;
case Packet::VERB_MULTICAST_LIKE: r = _doMULTICAST_LIKE(RR,tPtr,peer); break;
case Packet::VERB_NETWORK_CREDENTIALS: r = _doNETWORK_CREDENTIALS(RR,tPtr,peer); break;
case Packet::VERB_NETWORK_CONFIG_REQUEST: r = _doNETWORK_CONFIG_REQUEST(RR,tPtr,peer); break;
case Packet::VERB_NETWORK_CONFIG: r = _doNETWORK_CONFIG(RR,tPtr,peer); break;
case Packet::VERB_MULTICAST_GATHER: r = _doMULTICAST_GATHER(RR,tPtr,peer); break;
case Packet::VERB_MULTICAST_FRAME: r = _doMULTICAST_FRAME(RR,tPtr,peer); break;
case Packet::VERB_PUSH_DIRECT_PATHS: r = _doPUSH_DIRECT_PATHS(RR,tPtr,peer); break;
case Packet::VERB_USER_MESSAGE: r = _doUSER_MESSAGE(RR,tPtr,peer); break;
case Packet::VERB_REMOTE_TRACE: r = _doREMOTE_TRACE(RR,tPtr,peer); break;
}
if (r) {
RR->node->statsLogVerb((unsigned int)v,(unsigned int)size());
return true;
}
return false;
} else {
RR->sw->requestWhois(tPtr,RR->node->now(),sourceAddress);
return false;
@ -172,7 +178,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
networkId = at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD);
const SharedPtr<Network> network(RR->node->network(networkId));
const int64_t now = RR->node->now();
if ( (network) && (network->config().com) && (peer->rateGateIncomingComRequest(now)) )
if ((network)&&(network->config().com))
network->pushCredentialsNow(tPtr,peer->address(),now);
} break;
@ -220,6 +226,7 @@ bool IncomingPacket::_doACK(const RuntimeEnvironment *RR,void *tPtr,const Shared
return true;
}
bool IncomingPacket::_doQOS_MEASUREMENT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
if (!peer->rateGateQoS(RR->node->now()))
@ -466,9 +473,6 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP
case Packet::VERB_HELLO: {
const uint64_t latency = RR->node->now() - at<uint64_t>(ZT_PROTO_VERB_HELLO__OK__IDX_TIMESTAMP);
if (latency > ZT_HELLO_MAX_ALLOWABLE_LATENCY)
return true;
const unsigned int vProto = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_PROTOCOL_VERSION];
const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MAJOR_VERSION];
const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO__OK__IDX_MINOR_VERSION];
@ -498,8 +502,8 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP
}
}
if (!hops() && (RR->node->getMultipathMode() != ZT_MULTIPATH_NONE)) {
_path->updateLatency((unsigned int)latency, RR->node->now());
if (!hops()) {
_path->updateLatency((unsigned int)latency,RR->node->now());
}
peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision);
@ -610,7 +614,7 @@ bool IncomingPacket::_doRENDEZVOUS(const RuntimeEnvironment *RR,void *tPtr,const
const unsigned int port = at<uint16_t>(ZT_PROTO_VERB_RENDEZVOUS_IDX_PORT);
const unsigned int addrlen = (*this)[ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRLEN];
if ((port > 0)&&((addrlen == 4)||(addrlen == 16))) {
const InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port);
InetAddress atAddr(field(ZT_PROTO_VERB_RENDEZVOUS_IDX_ADDRESS,addrlen),addrlen,port);
if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,with,_path->localSocket(),atAddr)) {
const uint64_t junk = RR->node->prng();
RR->node->putPacket(tPtr,_path->localSocket(),atAddr,&junk,4,2); // send low-TTL junk packet to 'open' local NAT(s) and stateful firewalls
@ -643,10 +647,8 @@ bool IncomingPacket::_doFRAME(const RuntimeEnvironment *RR,void *tPtr,const Shar
}
} else {
_sendErrorNeedCredentials(RR,tPtr,peer,nwid);
RR->t->incomingNetworkAccessDenied(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_FRAME,true);
return false;
}
} else {
_sendErrorNeedCredentials(RR,tPtr,peer,nwid);
}
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_FRAME,0,Packet::VERB_NOP,trustEstablished,nwid);
@ -672,8 +674,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const
if (!network->gate(tPtr,peer)) {
RR->t->incomingNetworkAccessDenied(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_EXT_FRAME,true);
_sendErrorNeedCredentials(RR,tPtr,peer,nwid);
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_EXT_FRAME,0,Packet::VERB_NOP,false,nwid);
return true;
return false;
}
if (size() > ZT_PROTO_VERB_EXT_FRAME_IDX_PAYLOAD) {
@ -757,45 +758,25 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const Share
bool IncomingPacket::_doMULTICAST_LIKE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
const int64_t now = RR->node->now();
bool authorized = false;
uint64_t lastNwid = 0;
uint64_t authOnNetwork[256]; // cache for approved network IDs
unsigned int authOnNetworkCount = 0;
SharedPtr<Network> network;
bool trustEstablished = false;
// Iterate through 18-byte network,MAC,ADI tuples
// Packet contains a series of 18-byte network,MAC,ADI tuples
for(unsigned int ptr=ZT_PACKET_IDX_PAYLOAD;ptr<size();ptr+=18) {
const uint64_t nwid = at<uint64_t>(ptr);
bool auth = false;
for(unsigned int i=0;i<authOnNetworkCount;++i) {
if (nwid == authOnNetwork[i]) {
auth = true;
break;
}
}
if (!auth) {
if ((!network)||(network->id() != nwid))
network = RR->node->network(nwid);
const bool authOnNet = ((network)&&(network->gate(tPtr,peer)));
if (!authOnNet)
_sendErrorNeedCredentials(RR,tPtr,peer,nwid);
trustEstablished |= authOnNet;
if (authOnNet||RR->mc->cacheAuthorized(peer->address(),nwid,now)) {
auth = true;
if (authOnNetworkCount < 256) // sanity check, packets can't really be this big
authOnNetwork[authOnNetworkCount++] = nwid;
}
}
if (auth) {
const MulticastGroup group(MAC(field(ptr + 8,6),6),at<uint32_t>(ptr + 14));
RR->mc->add(tPtr,now,nwid,group,peer->address());
if (nwid != lastNwid) {
lastNwid = nwid;
SharedPtr<Network> network(RR->node->network(nwid));
if (network)
authorized = network->gate(tPtr,peer);
if (!authorized)
authorized = ((RR->topology->amUpstream())||(RR->node->localControllerHasAuthorized(now,nwid,peer->address())));
}
if (authorized)
RR->mc->add(tPtr,now,nwid,MulticastGroup(MAC(field(ptr + 8,6),6),at<uint32_t>(ptr + 14)),peer->address());
}
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,trustEstablished,(network) ? network->id() : 0);
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_LIKE,0,Packet::VERB_NOP,false,0);
return true;
}
@ -828,7 +809,7 @@ bool IncomingPacket::_doNETWORK_CREDENTIALS(const RuntimeEnvironment *RR,void *t
case Membership::ADD_DEFERRED_FOR_WHOIS:
return false;
}
} else RR->mc->addCredential(tPtr,com,false);
}
}
}
++p; // skip trailing 0 after COMs if present
@ -982,18 +963,23 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr
try {
CertificateOfMembership com;
com.deserialize(*this,ZT_PROTO_VERB_MULTICAST_GATHER_IDX_COM);
if (com) {
if (network)
network->addCredential(tPtr,com);
else RR->mc->addCredential(tPtr,com,false);
}
if ((com)&&(network))
network->addCredential(tPtr,com);
} catch ( ... ) {} // discard invalid COMs
}
const bool trustEstablished = ((network)&&(network->gate(tPtr,peer)));
if (!trustEstablished)
_sendErrorNeedCredentials(RR,tPtr,peer,nwid);
if ( ( trustEstablished || RR->mc->cacheAuthorized(peer->address(),nwid,RR->node->now()) ) && (gatherLimit > 0) ) {
bool trustEstablished = false;
if (network) {
if (network->gate(tPtr,peer)) {
trustEstablished = true;
} else {
_sendErrorNeedCredentials(RR,tPtr,peer,nwid);
return false;
}
}
const int64_t now = RR->node->now();
if ((gatherLimit > 0)&&((trustEstablished)||(RR->topology->amUpstream())||(RR->node->localControllerHasAuthorized(now,nwid,peer->address())))) {
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
outp.append((unsigned char)Packet::VERB_MULTICAST_GATHER);
outp.append(packetId());
@ -1003,7 +989,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr
const unsigned int gatheredLocally = RR->mc->gather(peer->address(),nwid,mg,outp,gatherLimit);
if (gatheredLocally > 0) {
outp.armor(peer->key(),true);
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
_path->send(RR,tPtr,outp.data(),outp.size(),now);
}
}
@ -1031,10 +1017,8 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
}
if (!network->gate(tPtr,peer)) {
RR->t->incomingNetworkAccessDenied(tPtr,network,_path,packetId(),size(),peer->address(),Packet::VERB_MULTICAST_FRAME,true);
_sendErrorNeedCredentials(RR,tPtr,peer,nwid);
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid);
return true;
return false;
}
unsigned int gatherLimit = 0;
@ -1109,7 +1093,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid);
} else {
_sendErrorNeedCredentials(RR,tPtr,peer,nwid);
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,false,nwid);
return false;
}
return true;
@ -1221,16 +1205,13 @@ bool IncomingPacket::_doREMOTE_TRACE(const RuntimeEnvironment *RR,void *tPtr,con
void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid)
{
const int64_t now = RR->node->now();
if (peer->rateGateOutgoingComRequest(now)) {
Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR);
outp.append((uint8_t)verb());
outp.append(packetId());
outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
outp.append(nwid);
outp.armor(peer->key(),true);
_path->send(RR,tPtr,outp.data(),outp.size(),now);
}
Packet outp(source(),RR->identity.address(),Packet::VERB_ERROR);
outp.append((uint8_t)verb());
outp.append(packetId());
outp.append((uint8_t)Packet::ERROR_NEED_MEMBERSHIP_CERTIFICATE);
outp.append(nwid);
outp.armor(peer->key(),true);
_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
}
} // namespace ZeroTier

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -46,39 +46,38 @@ InetAddress::IpScope InetAddress::ipScope() const
case AF_INET: {
const uint32_t ip = Utils::ntoh((uint32_t)reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr);
switch(ip >> 24) {
case 0x00: return IP_SCOPE_NONE; // 0.0.0.0/8 (reserved, never used)
case 0x06: return IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army)
case 0x0a: return IP_SCOPE_PRIVATE; // 10.0.0.0/8
case 0x0b: return IP_SCOPE_PSEUDOPRIVATE; // 11.0.0.0/8 (US DoD)
case 0x15: return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN)
case 0x16: return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA)
case 0x19: return IP_SCOPE_PSEUDOPRIVATE; // 25.0.0.0/8 (UK Ministry of Defense)
case 0x1a: return IP_SCOPE_PSEUDOPRIVATE; // 26.0.0.0/8 (US DISA)
case 0x1c: return IP_SCOPE_PSEUDOPRIVATE; // 28.0.0.0/8 (US DSI-North)
case 0x1d: return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA)
case 0x1e: return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA)
case 0x2c: return IP_SCOPE_PSEUDOPRIVATE; // 44.0.0.0/8 (Amateur Radio)
case 0x33: return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of Social Security)
case 0x37: return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD)
case 0x38: return IP_SCOPE_PSEUDOPRIVATE; // 56.0.0.0/8 (US Postal Service)
case 0x00: return IP_SCOPE_NONE; // 0.0.0.0/8 (reserved, never used)
case 0x06: return IP_SCOPE_PSEUDOPRIVATE; // 6.0.0.0/8 (US Army)
case 0x0a: return IP_SCOPE_PRIVATE; // 10.0.0.0/8
case 0x0b: return IP_SCOPE_PSEUDOPRIVATE; // 11.0.0.0/8 (US DoD)
case 0x15: return IP_SCOPE_PSEUDOPRIVATE; // 21.0.0.0/8 (US DDN-RVN)
case 0x16: return IP_SCOPE_PSEUDOPRIVATE; // 22.0.0.0/8 (US DISA)
case 0x19: return IP_SCOPE_PSEUDOPRIVATE; // 25.0.0.0/8 (UK Ministry of Defense)
case 0x1a: return IP_SCOPE_PSEUDOPRIVATE; // 26.0.0.0/8 (US DISA)
case 0x1c: return IP_SCOPE_PSEUDOPRIVATE; // 28.0.0.0/8 (US DSI-North)
case 0x1d: return IP_SCOPE_PSEUDOPRIVATE; // 29.0.0.0/8 (US DISA)
case 0x1e: return IP_SCOPE_PSEUDOPRIVATE; // 30.0.0.0/8 (US DISA)
case 0x33: return IP_SCOPE_PSEUDOPRIVATE; // 51.0.0.0/8 (UK Department of Social Security)
case 0x37: return IP_SCOPE_PSEUDOPRIVATE; // 55.0.0.0/8 (US DoD)
case 0x38: return IP_SCOPE_PSEUDOPRIVATE; // 56.0.0.0/8 (US Postal Service)
case 0x64:
if ((ip & 0xffc00000) == 0x64400000) return IP_SCOPE_PRIVATE; // 100.64.0.0/10
if ((ip & 0xffc00000) == 0x64400000) return IP_SCOPE_PRIVATE; // 100.64.0.0/10
break;
case 0x7f: return IP_SCOPE_LOOPBACK; // 127.0.0.0/8
case 0x7f: return IP_SCOPE_LOOPBACK; // 127.0.0.0/8
case 0xa9:
if ((ip & 0xffff0000) == 0xa9fe0000) return IP_SCOPE_LINK_LOCAL; // 169.254.0.0/16
if ((ip & 0xffff0000) == 0xa9fe0000) return IP_SCOPE_LINK_LOCAL; // 169.254.0.0/16
break;
case 0xac:
if ((ip & 0xfff00000) == 0xac100000) return IP_SCOPE_PRIVATE; // 172.16.0.0/12
if ((ip & 0xfff00000) == 0xac100000) return IP_SCOPE_PRIVATE; // 172.16.0.0/12
break;
case 0xc0:
if ((ip & 0xffff0000) == 0xc0a80000) return IP_SCOPE_PRIVATE; // 192.168.0.0/16
if ((ip & 0xffff0000) == 0xc0a80000) return IP_SCOPE_PRIVATE; // 192.168.0.0/16
break;
case 0xff: return IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable)
case 0xff: return IP_SCOPE_NONE; // 255.0.0.0/8 (broadcast, or unused/unusable)
}
switch(ip >> 28) {
case 0xe: return IP_SCOPE_MULTICAST; // 224.0.0.0/4
case 0xf: return IP_SCOPE_PSEUDOPRIVATE; // 240.0.0.0/4 ("reserved," usually unusable)
case 0xe: return IP_SCOPE_MULTICAST; // 224.0.0.0/4
case 0xf: return IP_SCOPE_PSEUDOPRIVATE; // 240.0.0.0/4 ("reserved," usually unusable)
}
return IP_SCOPE_GLOBAL;
} break;
@ -86,21 +85,21 @@ InetAddress::IpScope InetAddress::ipScope() const
case AF_INET6: {
const unsigned char *ip = reinterpret_cast<const unsigned char *>(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr);
if ((ip[0] & 0xf0) == 0xf0) {
if (ip[0] == 0xff) return IP_SCOPE_MULTICAST; // ff00::/8
if (ip[0] == 0xff) return IP_SCOPE_MULTICAST; // ff00::/8
if ((ip[0] == 0xfe)&&((ip[1] & 0xc0) == 0x80)) {
unsigned int k = 2;
while ((!ip[k])&&(k < 15)) ++k;
if ((k == 15)&&(ip[15] == 0x01))
return IP_SCOPE_LOOPBACK; // fe80::1/128
return IP_SCOPE_LOOPBACK; // fe80::1/128
else return IP_SCOPE_LINK_LOCAL; // fe80::/10
}
if ((ip[0] & 0xfe) == 0xfc) return IP_SCOPE_PRIVATE; // fc00::/7
if ((ip[0] & 0xfe) == 0xfc) return IP_SCOPE_PRIVATE; // fc00::/7
}
unsigned int k = 0;
while ((!ip[k])&&(k < 15)) ++k;
if (k == 15) { // all 0's except last byte
if (ip[15] == 0x01) return IP_SCOPE_LOOPBACK; // ::1/128
if (ip[15] == 0x00) return IP_SCOPE_NONE; // ::/128
if (ip[15] == 0x01) return IP_SCOPE_LOOPBACK; // ::1/128
if (ip[15] == 0x00) return IP_SCOPE_NONE; // ::/128
}
return IP_SCOPE_GLOBAL;
} break;
@ -115,13 +114,13 @@ void InetAddress::set(const void *ipBytes,unsigned int ipLen,unsigned int port)
memset(this,0,sizeof(InetAddress));
if (ipLen == 4) {
uint32_t ipb[1];
ZT_FAST_MEMCPY(ipb,ipBytes,4);
memcpy(ipb,ipBytes,4);
ss_family = AF_INET;
reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr = ipb[0];
reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton((uint16_t)port);
} else if (ipLen == 16) {
ss_family = AF_INET6;
ZT_FAST_MEMCPY(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,ipBytes,16);
memcpy(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,ipBytes,16);
reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_port = Utils::hton((uint16_t)port);
}
}
@ -139,33 +138,23 @@ char *InetAddress::toString(char buf[64]) const
char *InetAddress::toIpString(char buf[64]) const
{
buf[0] = (char)0;
switch(ss_family) {
case AF_INET: {
const uint8_t *a = reinterpret_cast<const uint8_t *>(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr));
char *p = buf;
for(int i=0;;++i) {
Utils::decimal((unsigned long)a[i],p);
if (i != 3) {
while (*p) ++p;
*(p++) = '.';
} else break;
}
} break;
#ifdef _WIN32
inet_ntop(AF_INET, (void*)&reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN);
#else
inet_ntop(AF_INET, &reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr, buf, INET_ADDRSTRLEN);
#endif
} break;
case AF_INET6: {
uint16_t a[8];
ZT_FAST_MEMCPY(a,reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,16);
char *p = buf;
for(int i=0;i<8;++i) {
Utils::hex(Utils::ntoh(a[i]),p);
p[4] = (i == 7) ? (char)0 : ':';
p += 5;
}
#ifdef _WIN32
inet_ntop(AF_INET6, (void*)reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN);
#else
inet_ntop(AF_INET6, reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr, buf, INET6_ADDRSTRLEN);
#endif
} break;
default:
buf[0] = (char)0;
break;
}
return buf;
}
@ -191,30 +180,16 @@ bool InetAddress::fromString(const char *ipSlashPort)
}
if (strchr(buf,':')) {
uint16_t a[8];
unsigned int b = 0;
char *saveptr = (char *)0;
for(char *s=Utils::stok(buf,":",&saveptr);((s)&&(b<8));s=Utils::stok((char *)0,":",&saveptr))
a[b++] = Utils::hton((uint16_t)(Utils::hexStrToUInt(s) & 0xffff));
struct sockaddr_in6 *const in6 = reinterpret_cast<struct sockaddr_in6 *>(this);
inet_pton(AF_INET6, buf, &in6->sin6_addr.s6_addr);
in6->sin6_family = AF_INET6;
ZT_FAST_MEMCPY(in6->sin6_addr.s6_addr,a,16);
in6->sin6_port = Utils::hton((uint16_t)port);
return true;
} else if (strchr(buf,'.')) {
uint8_t a[4];
unsigned int b = 0;
char *saveptr = (char *)0;
for(char *s=Utils::stok(buf,".",&saveptr);((s)&&(b<4));s=Utils::stok((char *)0,".",&saveptr))
a[b++] = (uint8_t)(Utils::strToUInt(s) & 0xff);
struct sockaddr_in *const in = reinterpret_cast<struct sockaddr_in *>(this);
inet_pton(AF_INET, buf, &in->sin_addr.s_addr);
in->sin_family = AF_INET;
ZT_FAST_MEMCPY(&(in->sin_addr.s_addr),a,4);
in->sin_port = Utils::hton((uint16_t)port);
return true;
} else {
return false;
@ -238,7 +213,7 @@ InetAddress InetAddress::netmask() const
nm[0] = 0;
nm[1] = 0;
}
ZT_FAST_MEMCPY(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm,16);
memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm,16);
} break;
}
return r;
@ -264,10 +239,10 @@ InetAddress InetAddress::network() const
case AF_INET6: {
uint64_t nm[2];
const unsigned int bits = netmaskBits();
ZT_FAST_MEMCPY(nm,reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,16);
memcpy(nm,reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,16);
nm[0] &= Utils::hton((uint64_t)((bits >= 64) ? 0xffffffffffffffffULL : (0xffffffffffffffffULL << (64 - bits))));
nm[1] &= Utils::hton((uint64_t)((bits <= 64) ? 0ULL : (0xffffffffffffffffULL << (128 - bits))));
ZT_FAST_MEMCPY(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm,16);
memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,nm,16);
} break;
}
return r;

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -91,8 +91,8 @@ struct InetAddress : public sockaddr_storage
};
InetAddress() { memset(this,0,sizeof(InetAddress)); }
InetAddress(const InetAddress &a) { ZT_FAST_MEMCPY(this,&a,sizeof(InetAddress)); }
InetAddress(const InetAddress *a) { ZT_FAST_MEMCPY(this,a,sizeof(InetAddress)); }
InetAddress(const InetAddress &a) { memcpy(this,&a,sizeof(InetAddress)); }
InetAddress(const InetAddress *a) { memcpy(this,a,sizeof(InetAddress)); }
InetAddress(const struct sockaddr_storage &ss) { *this = ss; }
InetAddress(const struct sockaddr_storage *ss) { *this = ss; }
InetAddress(const struct sockaddr &sa) { *this = sa; }
@ -108,28 +108,28 @@ struct InetAddress : public sockaddr_storage
inline InetAddress &operator=(const InetAddress &a)
{
if (&a != this)
ZT_FAST_MEMCPY(this,&a,sizeof(InetAddress));
memcpy(this,&a,sizeof(InetAddress));
return *this;
}
inline InetAddress &operator=(const InetAddress *a)
{
if (a != this)
ZT_FAST_MEMCPY(this,a,sizeof(InetAddress));
memcpy(this,a,sizeof(InetAddress));
return *this;
}
inline InetAddress &operator=(const struct sockaddr_storage &ss)
{
if (reinterpret_cast<const InetAddress *>(&ss) != this)
ZT_FAST_MEMCPY(this,&ss,sizeof(InetAddress));
memcpy(this,&ss,sizeof(InetAddress));
return *this;
}
inline InetAddress &operator=(const struct sockaddr_storage *ss)
{
if (reinterpret_cast<const InetAddress *>(ss) != this)
ZT_FAST_MEMCPY(this,ss,sizeof(InetAddress));
memcpy(this,ss,sizeof(InetAddress));
return *this;
}
@ -137,7 +137,7 @@ struct InetAddress : public sockaddr_storage
{
if (reinterpret_cast<const InetAddress *>(&sa) != this) {
memset(this,0,sizeof(InetAddress));
ZT_FAST_MEMCPY(this,&sa,sizeof(struct sockaddr_in));
memcpy(this,&sa,sizeof(struct sockaddr_in));
}
return *this;
}
@ -146,7 +146,7 @@ struct InetAddress : public sockaddr_storage
{
if (reinterpret_cast<const InetAddress *>(sa) != this) {
memset(this,0,sizeof(InetAddress));
ZT_FAST_MEMCPY(this,sa,sizeof(struct sockaddr_in));
memcpy(this,sa,sizeof(struct sockaddr_in));
}
return *this;
}
@ -155,7 +155,7 @@ struct InetAddress : public sockaddr_storage
{
if (reinterpret_cast<const InetAddress *>(&sa) != this) {
memset(this,0,sizeof(InetAddress));
ZT_FAST_MEMCPY(this,&sa,sizeof(struct sockaddr_in6));
memcpy(this,&sa,sizeof(struct sockaddr_in6));
}
return *this;
}
@ -164,7 +164,7 @@ struct InetAddress : public sockaddr_storage
{
if (reinterpret_cast<const InetAddress *>(sa) != this) {
memset(this,0,sizeof(InetAddress));
ZT_FAST_MEMCPY(this,sa,sizeof(struct sockaddr_in6));
memcpy(this,sa,sizeof(struct sockaddr_in6));
}
return *this;
}
@ -175,10 +175,10 @@ struct InetAddress : public sockaddr_storage
memset(this,0,sizeof(InetAddress));
switch(sa.sa_family) {
case AF_INET:
ZT_FAST_MEMCPY(this,&sa,sizeof(struct sockaddr_in));
memcpy(this,&sa,sizeof(struct sockaddr_in));
break;
case AF_INET6:
ZT_FAST_MEMCPY(this,&sa,sizeof(struct sockaddr_in6));
memcpy(this,&sa,sizeof(struct sockaddr_in6));
break;
}
}
@ -191,10 +191,10 @@ struct InetAddress : public sockaddr_storage
memset(this,0,sizeof(InetAddress));
switch(sa->sa_family) {
case AF_INET:
ZT_FAST_MEMCPY(this,sa,sizeof(struct sockaddr_in));
memcpy(this,sa,sizeof(struct sockaddr_in));
break;
case AF_INET6:
ZT_FAST_MEMCPY(this,sa,sizeof(struct sockaddr_in6));
memcpy(this,sa,sizeof(struct sockaddr_in6));
break;
}
}
@ -388,7 +388,7 @@ struct InetAddress : public sockaddr_storage
break;
case AF_INET6:
r.ss_family = AF_INET6;
ZT_FAST_MEMCPY(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,16);
memcpy(reinterpret_cast<struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,16);
break;
}
return r;
@ -537,12 +537,12 @@ struct InetAddress : public sockaddr_storage
return (unsigned int)(b.template at<uint16_t>(p) + 3); // other addresses begin with 16-bit non-inclusive length
case 0x04:
ss_family = AF_INET;
ZT_FAST_MEMCPY(&(reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr),b.field(p,4),4); p += 4;
memcpy(&(reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr),b.field(p,4),4); p += 4;
reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p)); p += 2;
break;
case 0x06:
ss_family = AF_INET6;
ZT_FAST_MEMCPY(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,b.field(p,16),16); p += 16;
memcpy(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,b.field(p,16),16); p += 16;
reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p)); p += 2;
break;
default:

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -35,61 +35,42 @@
#include "Node.hpp"
#include "Trace.hpp"
#define ZT_CREDENTIAL_PUSH_EVERY (ZT_NETWORK_AUTOCONF_DELAY / 3)
namespace ZeroTier {
Membership::Membership() :
_lastUpdatedMulticast(0),
_lastPushedCom(0),
_comRevocationThreshold(0),
_lastPushedCredentials(0),
_revocations(4),
_remoteTags(4),
_remoteCaps(4),
_remoteCoos(4)
{
resetPushState();
}
void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force)
void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex)
{
bool sendCom = ( (nconf.com) && ( ((now - _lastPushedCom) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) );
const Capability *sendCap;
if (localCapabilityIndex >= 0) {
sendCap = &(nconf.capabilities[localCapabilityIndex]);
if ( ((now - _localCredLastPushed.cap[localCapabilityIndex]) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) )
_localCredLastPushed.cap[localCapabilityIndex] = now;
else sendCap = (const Capability *)0;
} else sendCap = (const Capability *)0;
const Capability *sendCap = (localCapabilityIndex >= 0) ? &(nconf.capabilities[localCapabilityIndex]) : (const Capability *)0;
const Tag *sendTags[ZT_MAX_NETWORK_TAGS];
unsigned int sendTagCount = 0;
for(unsigned int t=0;t<nconf.tagCount;++t) {
if ( ((now - _localCredLastPushed.tag[t]) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) {
_localCredLastPushed.tag[t] = now;
sendTags[sendTagCount++] = &(nconf.tags[t]);
}
}
for(unsigned int t=0;t<nconf.tagCount;++t)
sendTags[sendTagCount++] = &(nconf.tags[t]);
const CertificateOfOwnership *sendCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP];
unsigned int sendCooCount = 0;
for(unsigned int c=0;c<nconf.certificateOfOwnershipCount;++c) {
if ( ((now - _localCredLastPushed.coo[c]) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) {
_localCredLastPushed.coo[c] = now;
sendCoos[sendCooCount++] = &(nconf.certificatesOfOwnership[c]);
}
}
for(unsigned int c=0;c<nconf.certificateOfOwnershipCount;++c)
sendCoos[sendCooCount++] = &(nconf.certificatesOfOwnership[c]);
unsigned int tagPtr = 0;
unsigned int cooPtr = 0;
bool sendCom = (bool)(nconf.com);
while ((tagPtr < sendTagCount)||(cooPtr < sendCooCount)||(sendCom)||(sendCap)) {
Packet outp(peerAddress,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
if (sendCom) {
sendCom = false;
nconf.com.serialize(outp);
_lastPushedCom = now;
}
outp.append((uint8_t)0x00);
@ -123,6 +104,8 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
outp.compress();
RR->sw->send(tPtr,outp,true);
}
_lastPushedCredentials = now;
}
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com)

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -67,10 +67,7 @@ public:
Membership();
/**
* Send COM and other credentials to this peer if needed
*
* This checks last pushed times for our COM and for other credentials and
* sends VERB_NETWORK_CREDENTIALS if the recipient might need them.
* Send COM and other credentials to this peer
*
* @param RR Runtime environment
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
@ -78,9 +75,16 @@ public:
* @param peerAddress Address of member peer (the one that this Membership describes)
* @param nconf My network config
* @param localCapabilityIndex Index of local capability to include (in nconf.capabilities[]) or -1 if none
* @param force If true, send objects regardless of last push time
*/
void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force);
void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex);
/**
* @return True if we haven't pushed credentials in a long time (to cause proactive credential push)
*/
inline bool shouldPushCredentials(const int64_t now) const
{
return ((now - _lastPushedCredentials) > ZT_PEER_ACTIVITY_TIMEOUT);
}
/**
* Check whether we should push MULTICAST_LIKEs to this peer, and update last sent time if true
@ -182,17 +186,6 @@ public:
*/
void clean(const int64_t now,const NetworkConfig &nconf);
/**
* Reset last pushed time for local credentials
*
* This is done when we update our network configuration and our credentials have changed
*/
inline void resetPushState()
{
_lastPushedCom = 0;
memset(&_localCredLastPushed,0,sizeof(_localCredLastPushed));
}
/**
* Generates a key for the internal use in indexing credentials by type and credential ID
*/
@ -211,7 +204,7 @@ private:
}
template<typename C>
void _cleanCredImpl(const NetworkConfig &nconf,Hashtable<uint32_t,C> &remoteCreds)
inline void _cleanCredImpl(const NetworkConfig &nconf,Hashtable<uint32_t,C> &remoteCreds)
{
uint32_t *k = (uint32_t *)0;
C *v = (C *)0;
@ -225,12 +218,12 @@ private:
// Last time we pushed MULTICAST_LIKE(s)
int64_t _lastUpdatedMulticast;
// Last time we pushed our COM to this peer
int64_t _lastPushedCom;
// Revocation threshold for COM or 0 if none
int64_t _comRevocationThreshold;
// Time we last pushed credentials
int64_t _lastPushedCredentials;
// Remote member's latest network COM
CertificateOfMembership _com;
@ -242,13 +235,6 @@ private:
Hashtable< uint32_t,Capability > _remoteCaps;
Hashtable< uint32_t,CertificateOfOwnership > _remoteCoos;
// Time we last pushed our local credentials to this member
struct {
uint64_t tag[ZT_MAX_NETWORK_TAGS];
uint64_t cap[ZT_MAX_NETWORK_CAPABILITIES];
uint64_t coo[ZT_MAX_CERTIFICATES_OF_OWNERSHIP];
} _localCredLastPushed;
public:
class CapabilityIterator
{

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -42,8 +42,7 @@ namespace ZeroTier {
Multicaster::Multicaster(const RuntimeEnvironment *renv) :
RR(renv),
_groups(256),
_gatherAuth(256)
_groups(32)
{
}
@ -415,25 +414,6 @@ void Multicaster::clean(int64_t now)
}
}
}
{
Mutex::Lock _l(_gatherAuth_m);
_GatherAuthKey *k = (_GatherAuthKey *)0;
uint64_t *ts = NULL;
Hashtable<_GatherAuthKey,uint64_t>::Iterator i(_gatherAuth);
while (i.next(k,ts)) {
if ((now - *ts) >= ZT_MULTICAST_CREDENTIAL_EXPIRATON)
_gatherAuth.erase(*k);
}
}
}
void Multicaster::addCredential(void *tPtr,const CertificateOfMembership &com,bool alreadyValidated)
{
if ((alreadyValidated)||(com.verify(RR,tPtr) == 0)) {
Mutex::Lock _l(_gatherAuth_m);
_gatherAuth[_GatherAuthKey(com.networkId(),com.issuedTo())] = RR->node->now();
}
}
void Multicaster::_add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup &mg,MulticastGroupStatus &gs,const Address &member)
@ -444,15 +424,17 @@ void Multicaster::_add(void *tPtr,int64_t now,uint64_t nwid,const MulticastGroup
if (member == RR->identity.address())
return;
for(std::vector<MulticastGroupMember>::iterator m(gs.members.begin());m!=gs.members.end();++m) {
std::vector<MulticastGroupMember>::iterator m(std::lower_bound(gs.members.begin(),gs.members.end(),member));
if (m != gs.members.end()) {
if (m->address == member) {
m->timestamp = now;
return;
}
gs.members.insert(m,MulticastGroupMember(member,now));
} else {
gs.members.push_back(MulticastGroupMember(member,now));
}
gs.members.push_back(MulticastGroupMember(member,now));
for(std::list<OutboundMulticast>::iterator tx(gs.txQueue.begin());tx!=gs.txQueue.end();) {
if (tx->atLimit())
gs.txQueue.erase(tx++);

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -158,33 +158,6 @@ public:
*/
void clean(int64_t now);
/**
* Add an authorization credential
*
* The Multicaster keeps its own track of when valid credentials of network
* membership are presented. This allows it to control MULTICAST_LIKE
* GATHER authorization for networks this node does not belong to.
*
* @param com Certificate of membership
* @param alreadyValidated If true, COM has already been checked and found to be valid and signed
*/
void addCredential(void *tPtr,const CertificateOfMembership &com,bool alreadyValidated);
/**
* Check authorization for GATHER and LIKE for non-network-members
*
* @param a Address of peer
* @param nwid Network ID
* @param now Current time
* @return True if GATHER and LIKE should be allowed
*/
bool cacheAuthorized(const Address &a,const uint64_t nwid,const int64_t now) const
{
Mutex::Lock _l(_gatherAuth_m);
const uint64_t *p = _gatherAuth.get(_GatherAuthKey(nwid,a));
return ((p)&&((now - *p) < ZT_MULTICAST_CREDENTIAL_EXPIRATON));
}
private:
struct Key
{
@ -203,6 +176,10 @@ private:
MulticastGroupMember() {}
MulticastGroupMember(const Address &a,uint64_t ts) : address(a),timestamp(ts) {}
inline bool operator<(const Address &a) const { return (address < a); }
inline bool operator==(const Address &a) const { return (address == a); }
inline bool operator!=(const Address &a) const { return (address != a); }
Address address;
uint64_t timestamp; // time of last notification
};
@ -222,18 +199,6 @@ private:
Hashtable<Multicaster::Key,MulticastGroupStatus> _groups;
Mutex _groups_m;
struct _GatherAuthKey
{
_GatherAuthKey() : member(0),networkId(0) {}
_GatherAuthKey(const uint64_t nwid,const Address &a) : member(a.toInt()),networkId(nwid) {}
inline unsigned long hashCode() const { return (unsigned long)(member ^ networkId); }
inline bool operator==(const _GatherAuthKey &k) const { return ((member == k.member)&&(networkId == k.networkId)); }
uint64_t member;
uint64_t networkId;
};
Hashtable< _GatherAuthKey,uint64_t > _gatherAuth;
Mutex _gatherAuth_m;
};
} // namespace ZeroTier

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -631,7 +631,6 @@ bool Network::filterOutgoingPacket(
const unsigned int vlanId,
uint8_t &qosBucket)
{
const int64_t now = RR->node->now();
Address ztFinalDest(ztDest);
int localCapabilityIndex = -1;
int accept = 0;
@ -664,9 +663,6 @@ bool Network::filterOutgoingPacket(
accept = 1;
if ((!noTee)&&(cc2)) {
Membership &m2 = _membership(cc2);
m2.pushCredentials(RR,tPtr,now,cc2,_config,localCapabilityIndex,false);
Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(_id);
outp.append((uint8_t)(ccWatch2 ? 0x16 : 0x02));
@ -701,13 +697,7 @@ bool Network::filterOutgoingPacket(
}
if (accept) {
if (membership)
membership->pushCredentials(RR,tPtr,now,ztDest,_config,localCapabilityIndex,false);
if ((!noTee)&&(cc)) {
Membership &m2 = _membership(cc);
m2.pushCredentials(RR,tPtr,now,cc,_config,localCapabilityIndex,false);
Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(_id);
outp.append((uint8_t)(ccWatch ? 0x16 : 0x02));
@ -720,9 +710,6 @@ bool Network::filterOutgoingPacket(
}
if ((ztDest != ztFinalDest)&&(ztFinalDest)) {
Membership &m2 = _membership(ztFinalDest);
m2.pushCredentials(RR,tPtr,now,ztFinalDest,_config,localCapabilityIndex,false);
Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(_id);
outp.append((uint8_t)0x04);
@ -797,8 +784,6 @@ int Network::filterIncomingPacket(
if (accept) {
if (cc2) {
_membership(cc2).pushCredentials(RR,tPtr,RR->node->now(),cc2,_config,-1,false);
Packet outp(cc2,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(_id);
outp.append((uint8_t)(ccWatch2 ? 0x1c : 0x08));
@ -830,8 +815,6 @@ int Network::filterIncomingPacket(
if (accept) {
if (cc) {
_membership(cc).pushCredentials(RR,tPtr,RR->node->now(),cc,_config,-1,false);
Packet outp(cc,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(_id);
outp.append((uint8_t)(ccWatch ? 0x1c : 0x08));
@ -844,8 +827,6 @@ int Network::filterIncomingPacket(
}
if ((ztDest != ztFinalDest)&&(ztFinalDest)) {
_membership(ztFinalDest).pushCredentials(RR,tPtr,RR->node->now(),ztFinalDest,_config,-1,false);
Packet outp(ztFinalDest,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(_id);
outp.append((uint8_t)0x0a);
@ -995,7 +976,7 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add
return false;
c->haveChunkIds[c->haveChunks++] = chunkId;
ZT_FAST_MEMCPY(c->data.unsafeData() + chunkIndex,chunkData,chunkLen);
memcpy(c->data.unsafeData() + chunkIndex,chunkData,chunkLen);
c->haveBytes += chunkLen;
if (c->haveBytes == totalLength) {
@ -1050,18 +1031,12 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD
_portInitialized = true;
_externalConfig(&ctmp);
Address *a = (Address *)0;
Membership *m = (Membership *)0;
Hashtable<Address,Membership>::Iterator i(_memberships);
while (i.next(a,m))
m->resetPushState();
}
_portError = RR->node->configureVirtualNetworkPort(tPtr,_id,&_uPtr,(oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp);
if (saveToDisk) {
Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> *d = new Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>();
Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> *const d = new Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY>();
try {
if (nconf.toDictionary(*d,false)) {
uint64_t tmp[2];
@ -1267,7 +1242,6 @@ bool Network::gate(void *tPtr,const SharedPtr<Peer> &peer)
if (!m)
m = &(_membership(peer->address()));
if (m->multicastLikeGate(now)) {
m->pushCredentials(RR,tPtr,now,peer->address(),_config,-1,false);
_announceMulticastGroupsTo(tPtr,peer->address(),_allMulticastGroups());
}
return true;
@ -1364,15 +1338,8 @@ Membership::AddCredentialResult Network::addCredential(void *tPtr,const Certific
{
if (com.networkId() != _id)
return Membership::ADD_REJECTED;
const Address a(com.issuedTo());
Mutex::Lock _l(_lock);
Membership &m = _membership(a);
const Membership::AddCredentialResult result = m.addCredential(RR,tPtr,_config,com);
if ((result == Membership::ADD_ACCEPTED_NEW)||(result == Membership::ADD_ACCEPTED_REDUNDANT)) {
m.pushCredentials(RR,tPtr,RR->node->now(),a,_config,-1,false);
RR->mc->addCredential(tPtr,com,true);
}
return result;
return _membership(com.issuedTo()).addCredential(RR,tPtr,_config,com);
}
Membership::AddCredentialResult Network::addCredential(void *tPtr,const Address &sentFrom,const Revocation &rev)
@ -1450,7 +1417,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
ec->assignedAddressCount = 0;
for(unsigned int i=0;i<ZT_MAX_ZT_ASSIGNED_ADDRESSES;++i) {
if (i < _config.staticIpCount) {
ZT_FAST_MEMCPY(&(ec->assignedAddresses[i]),&(_config.staticIps[i]),sizeof(struct sockaddr_storage));
memcpy(&(ec->assignedAddresses[i]),&(_config.staticIps[i]),sizeof(struct sockaddr_storage));
++ec->assignedAddressCount;
} else {
memset(&(ec->assignedAddresses[i]),0,sizeof(struct sockaddr_storage));
@ -1460,7 +1427,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
ec->routeCount = 0;
for(unsigned int i=0;i<ZT_MAX_NETWORK_ROUTES;++i) {
if (i < _config.routeCount) {
ZT_FAST_MEMCPY(&(ec->routes[i]),&(_config.routes[i]),sizeof(ZT_VirtualNetworkRoute));
memcpy(&(ec->routes[i]),&(_config.routes[i]),sizeof(ZT_VirtualNetworkRoute));
++ec->routeCount;
} else {
memset(&(ec->routes[i]),0,sizeof(ZT_VirtualNetworkRoute));
@ -1495,7 +1462,8 @@ void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMu
std::sort(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end());
for(std::vector<Address>::const_iterator a(alwaysAnnounceTo.begin());a!=alwaysAnnounceTo.end();++a) {
// push COM to non-members so they can do multicast request auth
/*
// push COM to non-members so they can do multicast request auth
if ( (_config.com) && (!_memberships.contains(*a)) && (*a != RR->identity.address()) ) {
Packet outp(*a,RR->identity.address(),Packet::VERB_NETWORK_CREDENTIALS);
_config.com.serialize(outp);
@ -1506,6 +1474,7 @@ void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMu
outp.append((uint16_t)0); // no certificates of ownership
RR->sw->send(tPtr,outp,true);
}
*/
_announceMulticastGroupsTo(tPtr,*a,groups);
}
}
@ -1515,7 +1484,6 @@ void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMu
Membership *m = (Membership *)0;
Hashtable<Address,Membership>::Iterator i(_memberships);
while (i.next(a,m)) {
m->pushCredentials(RR,tPtr,now,*a,_config,-1,false);
if ( ( m->multicastLikeGate(now) || (newMulticastGroup) ) && (m->isAllowedOnNetwork(_config)) && (!std::binary_search(alwaysAnnounceTo.begin(),alwaysAnnounceTo.end(),*a)) )
_announceMulticastGroupsTo(tPtr,*a,groups);
}
@ -1525,25 +1493,27 @@ void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMu
void Network::_announceMulticastGroupsTo(void *tPtr,const Address &peer,const std::vector<MulticastGroup> &allMulticastGroups)
{
// Assumes _lock is locked
Packet outp(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
Packet *const outp = new Packet(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
for(std::vector<MulticastGroup>::const_iterator mg(allMulticastGroups.begin());mg!=allMulticastGroups.end();++mg) {
if ((outp.size() + 24) >= ZT_PROTO_MAX_PACKET_LENGTH) {
outp.compress();
RR->sw->send(tPtr,outp,true);
outp.reset(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
if ((outp->size() + 24) >= ZT_PROTO_MAX_PACKET_LENGTH) {
outp->compress();
RR->sw->send(tPtr,*outp,true);
outp->reset(peer,RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
}
// network ID, MAC, ADI
outp.append((uint64_t)_id);
mg->mac().appendTo(outp);
outp.append((uint32_t)mg->adi());
outp->append((uint64_t)_id);
mg->mac().appendTo(*outp);
outp->append((uint32_t)mg->adi());
}
if (outp.size() > ZT_PROTO_MIN_PACKET_LENGTH) {
outp.compress();
RR->sw->send(tPtr,outp,true);
if (outp->size() > ZT_PROTO_MIN_PACKET_LENGTH) {
outp->compress();
RR->sw->send(tPtr,*outp,true);
}
delete outp;
}
std::vector<MulticastGroup> Network::_allMulticastGroups() const

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -290,6 +290,11 @@ public:
return ((br) ? *br : Address());
}
/**
* @return True if QoS is in effect for this network
*/
inline bool qosEnabled() { return false; }
/**
* Set a bridge route
*
@ -298,13 +303,6 @@ public:
*/
void learnBridgeRoute(const MAC &mac,const Address &addr);
/**
* Whether QoS is in effect for this network
*/
bool QoSEnabled() {
return false;
}
/**
* Learn a multicast group that is bridged to our tap device
*
@ -367,7 +365,22 @@ public:
inline void pushCredentialsNow(void *tPtr,const Address &to,const int64_t now)
{
Mutex::Lock _l(_lock);
_membership(to).pushCredentials(RR,tPtr,now,to,_config,-1,true);
_membership(to).pushCredentials(RR,tPtr,now,to,_config,-1);
}
/**
* Push credentials if we haven't done so in a very long time
*
* @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call
* @param to Destination peer address
* @param now Current time
*/
inline void pushCredentialsIfNeeded(void *tPtr,const Address &to,const int64_t now)
{
Mutex::Lock _l(_lock);
Membership &m = _membership(to);
if (m.shouldPushCredentials(now))
m.pushCredentials(RR,tPtr,now,to,_config,-1);
}
/**

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -200,10 +200,11 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d)
{
static const NetworkConfig NIL_NC;
Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> *tmp = new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>();
try {
memset(this,0,sizeof(NetworkConfig));
*this = NIL_NC;
// Fields that are always present, new or old
this->networkId = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,0);

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -221,9 +221,28 @@ namespace ZeroTier {
class NetworkConfig
{
public:
NetworkConfig() { memset(this,0,sizeof(NetworkConfig)); }
NetworkConfig(const NetworkConfig &nc) { ZT_FAST_MEMCPY(this,&nc,sizeof(NetworkConfig)); }
inline NetworkConfig &operator=(const NetworkConfig &nc) { ZT_FAST_MEMCPY(this,&nc,sizeof(NetworkConfig)); return *this; }
NetworkConfig() :
networkId(0),
timestamp(0),
credentialTimeMaxDelta(0),
revision(0),
issuedTo(),
remoteTraceTarget(),
flags(0),
remoteTraceLevel(Trace::LEVEL_NORMAL),
mtu(0),
multicastLimit(0),
specialistCount(0),
routeCount(0),
staticIpCount(0),
ruleCount(0),
capabilityCount(0),
tagCount(0),
certificateOfOwnershipCount(0),
type(ZT_NETWORK_TYPE_PRIVATE)
{
name[0] = 0;
}
/**
* Write this network config to a dictionary for transport
@ -255,7 +274,18 @@ public:
/**
* @return True if frames should not be compressed
*/
inline bool disableCompression() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_DISABLE_COMPRESSION) != 0); }
inline bool disableCompression() const
{
#ifndef ZT_DISABLE_COMPRESSION
return ((this->flags & ZT_NETWORKCONFIG_FLAG_DISABLE_COMPRESSION) != 0);
#else
/* Compression is disabled for libzt builds since it causes non-obvious chaotic
interference with lwIP's TCP congestion algorithm. Compression is also disabled
for some NAS builds due to the usage of low-performance processors in certain
older and budget models. */
return false;
#endif
}
/**
* @return Network type is public (no access control)

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -66,7 +66,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
{
if (callbacks->version != 0)
throw ZT_EXCEPTION_INVALID_ARGUMENT;
ZT_FAST_MEMCPY(&_cb,callbacks,sizeof(ZT_Node_Callbacks));
memcpy(&_cb,callbacks,sizeof(ZT_Node_Callbacks));
// Initialize non-cryptographic PRNG from a good random source
Utils::getSecureRandom((void *)_prngState,sizeof(_prngState));
@ -76,6 +76,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,int64
memset(_expectingRepliesToBucketPtr,0,sizeof(_expectingRepliesToBucketPtr));
memset(_expectingRepliesTo,0,sizeof(_expectingRepliesTo));
memset(_lastIdentityVerification,0,sizeof(_lastIdentityVerification));
memset((void *)(&_stats),0,sizeof(_stats));
uint64_t idtmp[2];
idtmp[0] = 0; idtmp[1] = 0;
@ -268,6 +269,15 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
Hashtable< Address,std::vector<InetAddress> > alwaysContact;
RR->topology->getUpstreamsToContact(alwaysContact);
// Uncomment to dump stats
/*
for(unsigned int i=0;i<32;i++) {
if (_stats.inVerbCounts[i] > 0)
printf("%.2x\t%12lld %lld\n",i,(unsigned long long)_stats.inVerbCounts[i],(unsigned long long)_stats.inVerbBytes[i]);
}
printf("\n");
*/
// Check last receive time on designated upstreams to see if we seem to be online
int64_t lastReceivedFromUpstream = 0;
{
@ -281,6 +291,19 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,int64_t now,volatile int64
}
}
// Clean up any old local controller auth memorizations.
{
_localControllerAuthorizations_m.lock();
Hashtable< _LocalControllerAuth,int64_t >::Iterator i(_localControllerAuthorizations);
_LocalControllerAuth *k = (_LocalControllerAuth *)0;
int64_t *v = (int64_t *)0;
while (i.next(k,v)) {
if ((*v - now) > (ZT_NETWORK_AUTOCONF_DELAY * 3))
_localControllerAuthorizations.erase(*k);
}
_localControllerAuthorizations_m.unlock();
}
// Get peers we should stay connected to according to network configs
// Also get networks and whether they need config so we only have to do one pass over networks
std::vector< std::pair< SharedPtr<Network>,bool > > networkConfigNeeded;
@ -471,13 +494,13 @@ ZT_PeerList *Node::peers() const
p->hadAggregateLink |= pi->second->hasAggregateLink();
p->pathCount = 0;
for(std::vector< SharedPtr<Path> >::iterator path(paths.begin());path!=paths.end();++path) {
ZT_FAST_MEMCPY(&(p->paths[p->pathCount].address),&((*path)->address()),sizeof(struct sockaddr_storage));
memcpy(&(p->paths[p->pathCount].address),&((*path)->address()),sizeof(struct sockaddr_storage));
p->paths[p->pathCount].lastSend = (*path)->lastOut();
p->paths[p->pathCount].lastReceive = (*path)->lastIn();
p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address());
p->paths[p->pathCount].expired = 0;
p->paths[p->pathCount].preferred = ((*path) == bestp) ? 1 : 0;
p->paths[p->pathCount].latency = (*path)->latency();
p->paths[p->pathCount].latency = (float)(*path)->latency();
p->paths[p->pathCount].packetDelayVariance = (*path)->packetDelayVariance();
p->paths[p->pathCount].throughputDisturbCoeff = (*path)->throughputDisturbanceCoefficient();
p->paths[p->pathCount].packetErrorRatio = (*path)->packetErrorRatio();
@ -633,6 +656,10 @@ std::vector<World> Node::moons() const
void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &destination,const NetworkConfig &nc,bool sendLegacyFormatConfig)
{
_localControllerAuthorizations_m.lock();
_localControllerAuthorizations[_LocalControllerAuth(nwid,destination)] = now();
_localControllerAuthorizations_m.unlock();
if (destination == RR->identity.address()) {
SharedPtr<Network> n(network(nwid));
if (!n) return;

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -263,6 +263,22 @@ public:
inline void setMultipathMode(uint8_t mode) { _multipathMode = mode; }
inline uint8_t getMultipathMode() { return _multipathMode; }
inline bool localControllerHasAuthorized(const int64_t now,const uint64_t nwid,const Address &addr) const
{
_localControllerAuthorizations_m.lock();
const int64_t *const at = _localControllerAuthorizations.get(_LocalControllerAuth(nwid,addr));
_localControllerAuthorizations_m.unlock();
if (at)
return ((now - *at) < (ZT_NETWORK_AUTOCONF_DELAY * 3));
return false;
}
inline void statsLogVerb(const unsigned int v,const unsigned int bytes)
{
++_stats.inVerbCounts[v];
_stats.inVerbBytes[v] += (uint64_t)bytes;
}
private:
RuntimeEnvironment _RR;
RuntimeEnvironment *RR;
@ -276,6 +292,22 @@ private:
// Time of last identity verification indexed by InetAddress.rateGateHash() -- used in IncomingPacket::_doHELLO() via rateGateIdentityVerification()
int64_t _lastIdentityVerification[16384];
// Statistics about stuff happening
volatile ZT_NodeStatistics _stats;
// Map that remembers if we have recently sent a network config to someone
// querying us as a controller.
struct _LocalControllerAuth
{
uint64_t nwid,address;
_LocalControllerAuth(const uint64_t nwid_,const Address &address_) : nwid(nwid_),address(address_.toInt()) {}
inline unsigned long hashCode() const { return (unsigned long)(nwid ^ address); }
inline bool operator==(const _LocalControllerAuth &a) const { return ((a.nwid == nwid)&&(a.address == address)); }
inline bool operator!=(const _LocalControllerAuth &a) const { return ((a.nwid != nwid)||(a.address != address)); }
};
Hashtable< _LocalControllerAuth,int64_t > _localControllerAuthorizations;
Mutex _localControllerAuthorizations_m;
Hashtable< uint64_t,SharedPtr<Network> > _networks;
Mutex _networks_m;

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -78,21 +78,20 @@ void OutboundMulticast::init(
if (!disableCompression)
_packet.compress();
ZT_FAST_MEMCPY(_frameData,payload,_frameLen);
memcpy(_frameData,payload,_frameLen);
}
void OutboundMulticast::sendOnly(const RuntimeEnvironment *RR,void *tPtr,const Address &toAddr)
{
const SharedPtr<Network> nw(RR->node->network(_nwid));
const Address toAddr2(toAddr);
uint8_t QoSBucket = 255; // Dummy value
if ((nw)&&(nw->filterOutgoingPacket(tPtr,true,RR->identity.address(),toAddr2,_macSrc,_macDest,_frameData,_frameLen,_etherType,0,QoSBucket))) {
if ((nw)&&(nw->filterOutgoingPacket(tPtr,true,RR->identity.address(),toAddr,_macSrc,_macDest,_frameData,_frameLen,_etherType,0,QoSBucket))) {
nw->pushCredentialsIfNeeded(tPtr,toAddr,RR->node->now());
_packet.newInitializationVector();
_packet.setDestination(toAddr2);
_packet.setDestination(toAddr);
RR->node->expectReplyTo(_packet.packetId());
Packet tmp(_packet); // make a copy of packet so as not to garble the original -- GitHub issue #461
RR->sw->send(tPtr,tmp,true);
_tmp = _packet;
RR->sw->send(tPtr,_tmp,true);
}
}

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -161,7 +161,7 @@ private:
unsigned int _limit;
unsigned int _frameLen;
unsigned int _etherType;
Packet _packet;
Packet _packet,_tmp;
std::vector<Address> _alreadySentTo;
uint8_t _frameData[ZT_MAX_MTU];
};

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -42,8 +42,8 @@
#ifdef _MSC_VER
#define FORCE_INLINE static __forceinline
#include <intrin.h>
#pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
#pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */
#pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */
#pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */
#else
#define FORCE_INLINE static inline
#endif
@ -155,16 +155,16 @@ namespace {
A library is provided to take care of it, see lz4frame.h.
*/
#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
#define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */
#define LZ4_VERSION_RELEASE 5 /* for tweaks, bug-fixes, or development */
#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */
#define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */
#define LZ4_VERSION_RELEASE 5 /* for tweaks, bug-fixes, or development */
#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE)
#define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE
#define LZ4_QUOTE(str) #str
#define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str)
#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION)
#define LZ4_MEMORY_USAGE 14
#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
#define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */
#define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16)
typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */
@ -173,7 +173,7 @@ static inline void LZ4_resetStream (LZ4_stream_t* streamPtr);
#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2)
#define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE)
#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */
#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */
typedef struct {
uint32_t hashTable[LZ4_HASH_SIZE_U32];
@ -192,14 +192,14 @@ typedef struct {
} LZ4_streamDecode_t_internal;
#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4)
#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long))
#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(unsigned long long))
union LZ4_stream_u {
unsigned long long table[LZ4_STREAMSIZE_U64];
LZ4_stream_t_internal internal_donotuse;
} ; /* previously typedef'd to LZ4_stream_t */
#define LZ4_STREAMDECODESIZE_U64 4
#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long))
#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long))
union LZ4_streamDecode_u {
unsigned long long table[LZ4_STREAMDECODESIZE_U64];
LZ4_streamDecode_t_internal internal_donotuse;
@ -224,8 +224,8 @@ union LZ4_streamDecode_u {
#endif
#define ALLOCATOR(n,s) calloc(n,s)
#define FREEMEM free
#define MEM_INIT memset
#define FREEMEM free
#define MEM_INIT memset
typedef uint8_t BYTE;
typedef uint16_t U16;
@ -257,50 +257,50 @@ static void LZ4_write32(void* memPtr, U32 value) { ((unalign*)memPtr)->u32 = val
#else /* safe and portable access through memcpy() */
static inline U16 LZ4_read16(const void* memPtr)
{
U16 val; ZT_FAST_MEMCPY(&val, memPtr, sizeof(val)); return val;
U16 val; memcpy(&val, memPtr, sizeof(val)); return val;
}
static inline U32 LZ4_read32(const void* memPtr)
{
U32 val; ZT_FAST_MEMCPY(&val, memPtr, sizeof(val)); return val;
U32 val; memcpy(&val, memPtr, sizeof(val)); return val;
}
static inline reg_t LZ4_read_ARCH(const void* memPtr)
{
reg_t val; ZT_FAST_MEMCPY(&val, memPtr, sizeof(val)); return val;
reg_t val; memcpy(&val, memPtr, sizeof(val)); return val;
}
static inline void LZ4_write16(void* memPtr, U16 value)
{
ZT_FAST_MEMCPY(memPtr, &value, sizeof(value));
memcpy(memPtr, &value, sizeof(value));
}
static inline void LZ4_write32(void* memPtr, U32 value)
{
ZT_FAST_MEMCPY(memPtr, &value, sizeof(value));
memcpy(memPtr, &value, sizeof(value));
}
#endif /* LZ4_FORCE_MEMORY_ACCESS */
static inline U16 LZ4_readLE16(const void* memPtr)
{
if (LZ4_isLittleEndian()) {
return LZ4_read16(memPtr);
return LZ4_read16(memPtr);
} else {
const BYTE* p = (const BYTE*)memPtr;
return (U16)((U16)p[0] + (p[1]<<8));
const BYTE* p = (const BYTE*)memPtr;
return (U16)((U16)p[0] + (p[1]<<8));
}
}
static inline void LZ4_writeLE16(void* memPtr, U16 value)
{
if (LZ4_isLittleEndian()) {
LZ4_write16(memPtr, value);
LZ4_write16(memPtr, value);
} else {
BYTE* p = (BYTE*)memPtr;
p[0] = (BYTE) value;
p[1] = (BYTE)(value>>8);
BYTE* p = (BYTE*)memPtr;
p[0] = (BYTE) value;
p[1] = (BYTE)(value>>8);
}
}
static inline void LZ4_copy8(void* dst, const void* src)
{
ZT_FAST_MEMCPY(dst,src,8);
memcpy(dst,src,8);
}
static inline void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd)
@ -330,63 +330,63 @@ static const int LZ4_minLength = (MFLIMIT+1);
#define RUN_BITS (8-ML_BITS)
#define RUN_MASK ((1U<<RUN_BITS)-1)
#define LZ4_STATIC_ASSERT(c) { enum { LZ4_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
#define LZ4_STATIC_ASSERT(c) { enum { LZ4_static_assert = 1/(int)(!!(c)) }; } /* use only *after* variable declarations */
static inline unsigned LZ4_NbCommonBytes (reg_t val)
{
if (LZ4_isLittleEndian()) {
if (sizeof(val)==8) {
# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)
unsigned long r = 0;
_BitScanForward64( &r, (U64)val );
return (int)(r>>3);
# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT)
return (__builtin_ctzll((U64)val) >> 3);
# else
static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };
return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
# endif
} else /* 32 bits */ {
# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
unsigned long r;
_BitScanForward( &r, (U32)val );
return (int)(r>>3);
# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT)
return (__builtin_ctz((U32)val) >> 3);
# else
static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
# endif
}
if (sizeof(val)==8) {
# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)
unsigned long r = 0;
_BitScanForward64( &r, (U64)val );
return (int)(r>>3);
# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT)
return (__builtin_ctzll((U64)val) >> 3);
# else
static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 };
return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58];
# endif
} else /* 32 bits */ {
# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
unsigned long r;
_BitScanForward( &r, (U32)val );
return (int)(r>>3);
# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT)
return (__builtin_ctz((U32)val) >> 3);
# else
static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 };
return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27];
# endif
}
} else /* Big Endian CPU */ {
if (sizeof(val)==8) {
# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)
unsigned long r = 0;
_BitScanReverse64( &r, val );
return (unsigned)(r>>3);
# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT)
return (__builtin_clzll((U64)val) >> 3);
# else
unsigned r;
if (!(val>>32)) { r=4; } else { r=0; val>>=32; }
if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
r += (!val);
return r;
# endif
} else /* 32 bits */ {
# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
unsigned long r = 0;
_BitScanReverse( &r, (unsigned long)val );
return (unsigned)(r>>3);
# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT)
return (__builtin_clz((U32)val) >> 3);
# else
unsigned r;
if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
r += (!val);
return r;
# endif
}
if (sizeof(val)==8) {
# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT)
unsigned long r = 0;
_BitScanReverse64( &r, val );
return (unsigned)(r>>3);
# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT)
return (__builtin_clzll((U64)val) >> 3);
# else
unsigned r;
if (!(val>>32)) { r=4; } else { r=0; val>>=32; }
if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; }
r += (!val);
return r;
# endif
} else /* 32 bits */ {
# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT)
unsigned long r = 0;
_BitScanReverse( &r, (unsigned long)val );
return (unsigned)(r>>3);
# elif (defined(__clang__) || (defined(__GNUC__) && (__GNUC__>=3))) && !defined(LZ4_FORCE_SW_BITCOUNT)
return (__builtin_clz((U32)val) >> 3);
# else
unsigned r;
if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; }
r += (!val);
return r;
# endif
}
}
}
@ -396,10 +396,10 @@ static inline unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE
const BYTE* const pStart = pIn;
while (likely(pIn<pInLimit-(STEPSIZE-1))) {
reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);
if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; }
pIn += LZ4_NbCommonBytes(diff);
return (unsigned)(pIn - pStart);
reg_t const diff = LZ4_read_ARCH(pMatch) ^ LZ4_read_ARCH(pIn);
if (!diff) { pIn+=STEPSIZE; pMatch+=STEPSIZE; continue; }
pIn += LZ4_NbCommonBytes(diff);
return (unsigned)(pIn - pStart);
}
if ((STEPSIZE==8) && (pIn<(pInLimit-3)) && (LZ4_read32(pMatch) == LZ4_read32(pIn))) { pIn+=4; pMatch+=4; }
@ -425,9 +425,9 @@ static inline int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize
static inline U32 LZ4_hash4(U32 sequence, tableType_t const tableType)
{
if (tableType == byU16)
return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1)));
return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1)));
else
return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG));
return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG));
}
static inline U32 LZ4_hash5(U64 sequence, tableType_t const tableType)
@ -436,9 +436,9 @@ static inline U32 LZ4_hash5(U64 sequence, tableType_t const tableType)
static const U64 prime8bytes = 11400714785074694791ULL;
const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG;
if (LZ4_isLittleEndian())
return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog));
return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog));
else
return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog));
return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog));
}
FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType)
@ -477,16 +477,16 @@ FORCE_INLINE const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableTy
}
FORCE_INLINE int LZ4_compress_generic(
LZ4_stream_t_internal* const cctx,
const char* const source,
char* const dest,
const int inputSize,
const int maxOutputSize,
const limitedOutput_directive outputLimited,
const tableType_t tableType,
const dict_directive dict,
const dictIssue_directive dictIssue,
const U32 acceleration)
LZ4_stream_t_internal* const cctx,
const char* const source,
char* const dest,
const int inputSize,
const int maxOutputSize,
const limitedOutput_directive outputLimited,
const tableType_t tableType,
const dict_directive dict,
const dictIssue_directive dictIssue,
const U32 acceleration)
{
const BYTE* ip = (const BYTE*) source;
const BYTE* base;
@ -511,20 +511,20 @@ FORCE_INLINE int LZ4_compress_generic(
{
case noDict:
default:
base = (const BYTE*)source;
lowLimit = (const BYTE*)source;
break;
base = (const BYTE*)source;
lowLimit = (const BYTE*)source;
break;
case withPrefix64k:
base = (const BYTE*)source - cctx->currentOffset;
lowLimit = (const BYTE*)source - cctx->dictSize;
break;
base = (const BYTE*)source - cctx->currentOffset;
lowLimit = (const BYTE*)source - cctx->dictSize;
break;
case usingExtDict:
base = (const BYTE*)source - cctx->currentOffset;
lowLimit = (const BYTE*)source;
break;
base = (const BYTE*)source - cctx->currentOffset;
lowLimit = (const BYTE*)source;
break;
}
if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */
if (inputSize<LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
if (inputSize<LZ4_minLength) goto _last_literals; /* Input too small, no compression (all literals) */
/* First Byte */
LZ4_putPosition(ip, cctx->hashTable, tableType, base);
@ -532,143 +532,143 @@ FORCE_INLINE int LZ4_compress_generic(
/* Main Loop */
for ( ; ; ) {
ptrdiff_t refDelta = 0;
const BYTE* match;
BYTE* token;
ptrdiff_t refDelta = 0;
const BYTE* match;
BYTE* token;
/* Find a match */
{ const BYTE* forwardIp = ip;
unsigned step = 1;
unsigned searchMatchNb = acceleration << LZ4_skipTrigger;
do {
U32 const h = forwardH;
ip = forwardIp;
forwardIp += step;
step = (searchMatchNb++ >> LZ4_skipTrigger);
/* Find a match */
{ const BYTE* forwardIp = ip;
unsigned step = 1;
unsigned searchMatchNb = acceleration << LZ4_skipTrigger;
do {
U32 const h = forwardH;
ip = forwardIp;
forwardIp += step;
step = (searchMatchNb++ >> LZ4_skipTrigger);
if (unlikely(forwardIp > mflimit)) goto _last_literals;
if (unlikely(forwardIp > mflimit)) goto _last_literals;
match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base);
if (dict==usingExtDict) {
if (match < (const BYTE*)source) {
refDelta = dictDelta;
lowLimit = dictionary;
} else {
refDelta = 0;
lowLimit = (const BYTE*)source;
} }
forwardH = LZ4_hashPosition(forwardIp, tableType);
LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base);
match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType, base);
if (dict==usingExtDict) {
if (match < (const BYTE*)source) {
refDelta = dictDelta;
lowLimit = dictionary;
} else {
refDelta = 0;
lowLimit = (const BYTE*)source;
} }
forwardH = LZ4_hashPosition(forwardIp, tableType);
LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType, base);
} while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0)
|| ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip))
|| (LZ4_read32(match+refDelta) != LZ4_read32(ip)) );
}
} while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0)
|| ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip))
|| (LZ4_read32(match+refDelta) != LZ4_read32(ip)) );
}
/* Catch up */
while (((ip>anchor) & (match+refDelta > lowLimit)) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; }
/* Catch up */
while (((ip>anchor) & (match+refDelta > lowLimit)) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; }
/* Encode Literals */
{ unsigned const litLength = (unsigned)(ip - anchor);
token = op++;
if ((outputLimited) && /* Check output buffer overflow */
(unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)))
return 0;
if (litLength >= RUN_MASK) {
int len = (int)litLength-RUN_MASK;
*token = (RUN_MASK<<ML_BITS);
for(; len >= 255 ; len-=255) *op++ = 255;
*op++ = (BYTE)len;
}
else *token = (BYTE)(litLength<<ML_BITS);
/* Encode Literals */
{ unsigned const litLength = (unsigned)(ip - anchor);
token = op++;
if ((outputLimited) && /* Check output buffer overflow */
(unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit)))
return 0;
if (litLength >= RUN_MASK) {
int len = (int)litLength-RUN_MASK;
*token = (RUN_MASK<<ML_BITS);
for(; len >= 255 ; len-=255) *op++ = 255;
*op++ = (BYTE)len;
}
else *token = (BYTE)(litLength<<ML_BITS);
/* Copy Literals */
LZ4_wildCopy(op, anchor, op+litLength);
op+=litLength;
}
/* Copy Literals */
LZ4_wildCopy(op, anchor, op+litLength);
op+=litLength;
}
_next_match:
/* Encode Offset */
LZ4_writeLE16(op, (U16)(ip-match)); op+=2;
/* Encode Offset */
LZ4_writeLE16(op, (U16)(ip-match)); op+=2;
/* Encode MatchLength */
{ unsigned matchCode;
/* Encode MatchLength */
{ unsigned matchCode;
if ((dict==usingExtDict) && (lowLimit==dictionary)) {
const BYTE* limit;
match += refDelta;
limit = ip + (dictEnd-match);
if (limit > matchlimit) limit = matchlimit;
matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit);
ip += MINMATCH + matchCode;
if (ip==limit) {
unsigned const more = LZ4_count(ip, (const BYTE*)source, matchlimit);
matchCode += more;
ip += more;
}
} else {
matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);
ip += MINMATCH + matchCode;
}
if ((dict==usingExtDict) && (lowLimit==dictionary)) {
const BYTE* limit;
match += refDelta;
limit = ip + (dictEnd-match);
if (limit > matchlimit) limit = matchlimit;
matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit);
ip += MINMATCH + matchCode;
if (ip==limit) {
unsigned const more = LZ4_count(ip, (const BYTE*)source, matchlimit);
matchCode += more;
ip += more;
}
} else {
matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit);
ip += MINMATCH + matchCode;
}
if ( outputLimited && /* Check output buffer overflow */
(unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) )
return 0;
if (matchCode >= ML_MASK) {
*token += ML_MASK;
matchCode -= ML_MASK;
LZ4_write32(op, 0xFFFFFFFF);
while (matchCode >= 4*255) op+=4, LZ4_write32(op, 0xFFFFFFFF), matchCode -= 4*255;
op += matchCode / 255;
*op++ = (BYTE)(matchCode % 255);
} else
*token += (BYTE)(matchCode);
}
if ( outputLimited && /* Check output buffer overflow */
(unlikely(op + (1 + LASTLITERALS) + (matchCode>>8) > olimit)) )
return 0;
if (matchCode >= ML_MASK) {
*token += ML_MASK;
matchCode -= ML_MASK;
LZ4_write32(op, 0xFFFFFFFF);
while (matchCode >= 4*255) op+=4, LZ4_write32(op, 0xFFFFFFFF), matchCode -= 4*255;
op += matchCode / 255;
*op++ = (BYTE)(matchCode % 255);
} else
*token += (BYTE)(matchCode);
}
anchor = ip;
anchor = ip;
/* Test end of chunk */
if (ip > mflimit) break;
/* Test end of chunk */
if (ip > mflimit) break;
/* Fill table */
LZ4_putPosition(ip-2, cctx->hashTable, tableType, base);
/* Fill table */
LZ4_putPosition(ip-2, cctx->hashTable, tableType, base);
/* Test next position */
match = LZ4_getPosition(ip, cctx->hashTable, tableType, base);
if (dict==usingExtDict) {
if (match < (const BYTE*)source) {
refDelta = dictDelta;
lowLimit = dictionary;
} else {
refDelta = 0;
lowLimit = (const BYTE*)source;
} }
LZ4_putPosition(ip, cctx->hashTable, tableType, base);
if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1)
&& (match+MAX_DISTANCE>=ip)
&& (LZ4_read32(match+refDelta)==LZ4_read32(ip)) )
{ token=op++; *token=0; goto _next_match; }
/* Test next position */
match = LZ4_getPosition(ip, cctx->hashTable, tableType, base);
if (dict==usingExtDict) {
if (match < (const BYTE*)source) {
refDelta = dictDelta;
lowLimit = dictionary;
} else {
refDelta = 0;
lowLimit = (const BYTE*)source;
} }
LZ4_putPosition(ip, cctx->hashTable, tableType, base);
if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1)
&& (match+MAX_DISTANCE>=ip)
&& (LZ4_read32(match+refDelta)==LZ4_read32(ip)) )
{ token=op++; *token=0; goto _next_match; }
/* Prepare next loop */
forwardH = LZ4_hashPosition(++ip, tableType);
/* Prepare next loop */
forwardH = LZ4_hashPosition(++ip, tableType);
}
_last_literals:
/* Encode Last Literals */
{ size_t const lastRun = (size_t)(iend - anchor);
if ( (outputLimited) && /* Check output buffer overflow */
((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) )
return 0;
if (lastRun >= RUN_MASK) {
size_t accumulator = lastRun - RUN_MASK;
*op++ = RUN_MASK << ML_BITS;
for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;
*op++ = (BYTE) accumulator;
} else {
*op++ = (BYTE)(lastRun<<ML_BITS);
}
ZT_FAST_MEMCPY(op, anchor, lastRun);
op += lastRun;
if ( (outputLimited) && /* Check output buffer overflow */
((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize) )
return 0;
if (lastRun >= RUN_MASK) {
size_t accumulator = lastRun - RUN_MASK;
*op++ = RUN_MASK << ML_BITS;
for(; accumulator >= 255 ; accumulator-=255) *op++ = 255;
*op++ = (BYTE) accumulator;
} else {
*op++ = (BYTE)(lastRun<<ML_BITS);
}
memcpy(op, anchor, lastRun);
op += lastRun;
}
/* End */
@ -682,15 +682,15 @@ static inline int LZ4_compress_fast_extState(void* state, const char* source, ch
//if (acceleration < 1) acceleration = ACCELERATION_DEFAULT;
if (maxOutputSize >= LZ4_compressBound(inputSize)) {
if (inputSize < LZ4_64Klimit)
return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration);
else
return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration);
if (inputSize < LZ4_64Klimit)
return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration);
else
return LZ4_compress_generic(ctx, source, dest, inputSize, 0, notLimited, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration);
} else {
if (inputSize < LZ4_64Klimit)
return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);
else
return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration);
if (inputSize < LZ4_64Klimit)
return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration);
else
return LZ4_compress_generic(ctx, source, dest, inputSize, maxOutputSize, limitedOutput, (sizeof(void*)==8) ? byU32 : byPtr, noDict, noDictIssue, acceleration);
}
}
@ -717,19 +717,19 @@ static inline void LZ4_resetStream (LZ4_stream_t* LZ4_stream)
}
FORCE_INLINE int LZ4_decompress_generic(
const char* const source,
char* const dest,
int inputSize,
int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */
const char* const source,
char* const dest,
int inputSize,
int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */
int endOnInput, /* endOnOutputSize, endOnInputSize */
int partialDecoding, /* full, partial */
int targetOutputSize, /* only used if partialDecoding==partial */
int dict, /* noDict, withPrefix64k, usingExtDict */
const BYTE* const lowPrefix, /* == dest when no prefix */
const BYTE* const dictStart, /* only if dict==usingExtDict */
const size_t dictSize /* note : = 0 if noDict */
)
int endOnInput, /* endOnOutputSize, endOnInputSize */
int partialDecoding, /* full, partial */
int targetOutputSize, /* only used if partialDecoding==partial */
int dict, /* noDict, withPrefix64k, usingExtDict */
const BYTE* const lowPrefix, /* == dest when no prefix */
const BYTE* const dictStart, /* only if dict==usingExtDict */
const size_t dictSize /* note : = 0 if noDict */
)
{
/* Local Variables */
const BYTE* ip = (const BYTE*) source;
@ -750,125 +750,125 @@ FORCE_INLINE int LZ4_decompress_generic(
/* Special cases */
if ((partialDecoding) && (oexit > oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */
if ((partialDecoding) && (oexit > oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */
if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */
if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1);
/* Main Loop : decode sequences */
while (1) {
size_t length;
const BYTE* match;
size_t offset;
size_t length;
const BYTE* match;
size_t offset;
/* get literal length */
unsigned const token = *ip++;
if ((length=(token>>ML_BITS)) == RUN_MASK) {
unsigned s;
do {
s = *ip++;
length += s;
} while ( likely(endOnInput ? ip<iend-RUN_MASK : 1) & (s==255) );
if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)(op))) goto _output_error; /* overflow detection */
if ((safeDecode) && unlikely((uptrval)(ip)+length<(uptrval)(ip))) goto _output_error; /* overflow detection */
}
/* get literal length */
unsigned const token = *ip++;
if ((length=(token>>ML_BITS)) == RUN_MASK) {
unsigned s;
do {
s = *ip++;
length += s;
} while ( likely(endOnInput ? ip<iend-RUN_MASK : 1) & (s==255) );
if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)(op))) goto _output_error; /* overflow detection */
if ((safeDecode) && unlikely((uptrval)(ip)+length<(uptrval)(ip))) goto _output_error; /* overflow detection */
}
/* copy literals */
cpy = op+length;
if ( ((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) )
|| ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) )
{
if (partialDecoding) {
if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */
if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */
} else {
if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */
if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */
}
ZT_FAST_MEMCPY(op, ip, length);
ip += length;
op += length;
break; /* Necessarily EOF, due to parsing restrictions */
}
LZ4_wildCopy(op, ip, cpy);
ip += length; op = cpy;
/* copy literals */
cpy = op+length;
if ( ((endOnInput) && ((cpy>(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) )
|| ((!endOnInput) && (cpy>oend-WILDCOPYLENGTH)) )
{
if (partialDecoding) {
if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */
if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */
} else {
if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */
if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */
}
memcpy(op, ip, length);
ip += length;
op += length;
break; /* Necessarily EOF, due to parsing restrictions */
}
LZ4_wildCopy(op, ip, cpy);
ip += length; op = cpy;
/* get offset */
offset = LZ4_readLE16(ip); ip+=2;
match = op - offset;
if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside buffers */
LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */
/* get offset */
offset = LZ4_readLE16(ip); ip+=2;
match = op - offset;
if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside buffers */
LZ4_write32(op, (U32)offset); /* costs ~1%; silence an msan warning when offset==0 */
/* get matchlength */
length = token & ML_MASK;
if (length == ML_MASK) {
unsigned s;
do {
s = *ip++;
if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error;
length += s;
} while (s==255);
if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */
}
length += MINMATCH;
/* get matchlength */
length = token & ML_MASK;
if (length == ML_MASK) {
unsigned s;
do {
s = *ip++;
if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error;
length += s;
} while (s==255);
if ((safeDecode) && unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */
}
length += MINMATCH;
/* check external dictionary */
if ((dict==usingExtDict) && (match < lowPrefix)) {
if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */
/* check external dictionary */
if ((dict==usingExtDict) && (match < lowPrefix)) {
if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */
if (length <= (size_t)(lowPrefix-match)) {
/* match can be copied as a single segment from external dictionary */
memmove(op, dictEnd - (lowPrefix-match), length);
op += length;
} else {
/* match encompass external dictionary and current block */
size_t const copySize = (size_t)(lowPrefix-match);
size_t const restSize = length - copySize;
ZT_FAST_MEMCPY(op, dictEnd - copySize, copySize);
op += copySize;
if (restSize > (size_t)(op-lowPrefix)) { /* overlap copy */
BYTE* const endOfMatch = op + restSize;
const BYTE* copyFrom = lowPrefix;
while (op < endOfMatch) *op++ = *copyFrom++;
} else {
ZT_FAST_MEMCPY(op, lowPrefix, restSize);
op += restSize;
} }
continue;
}
if (length <= (size_t)(lowPrefix-match)) {
/* match can be copied as a single segment from external dictionary */
memmove(op, dictEnd - (lowPrefix-match), length);
op += length;
} else {
/* match encompass external dictionary and current block */
size_t const copySize = (size_t)(lowPrefix-match);
size_t const restSize = length - copySize;
memcpy(op, dictEnd - copySize, copySize);
op += copySize;
if (restSize > (size_t)(op-lowPrefix)) { /* overlap copy */
BYTE* const endOfMatch = op + restSize;
const BYTE* copyFrom = lowPrefix;
while (op < endOfMatch) *op++ = *copyFrom++;
} else {
memcpy(op, lowPrefix, restSize);
op += restSize;
} }
continue;
}
/* copy match within block */
cpy = op + length;
if (unlikely(offset<8)) {
const int dec64 = dec64table[offset];
op[0] = match[0];
op[1] = match[1];
op[2] = match[2];
op[3] = match[3];
match += dec32table[offset];
ZT_FAST_MEMCPY(op+4, match, 4);
match -= dec64;
} else { LZ4_copy8(op, match); match+=8; }
op += 8;
/* copy match within block */
cpy = op + length;
if (unlikely(offset<8)) {
const int dec64 = dec64table[offset];
op[0] = match[0];
op[1] = match[1];
op[2] = match[2];
op[3] = match[3];
match += dec32table[offset];
memcpy(op+4, match, 4);
match -= dec64;
} else { LZ4_copy8(op, match); match+=8; }
op += 8;
if (unlikely(cpy>oend-12)) {
BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1);
if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */
if (op < oCopyLimit) {
LZ4_wildCopy(op, match, oCopyLimit);
match += oCopyLimit - op;
op = oCopyLimit;
}
while (op<cpy) *op++ = *match++;
} else {
LZ4_copy8(op, match);
if (length>16) LZ4_wildCopy(op+8, match+8, cpy);
}
op=cpy; /* correction */
if (unlikely(cpy>oend-12)) {
BYTE* const oCopyLimit = oend-(WILDCOPYLENGTH-1);
if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals (uncompressed) */
if (op < oCopyLimit) {
LZ4_wildCopy(op, match, oCopyLimit);
match += oCopyLimit - op;
op = oCopyLimit;
}
while (op<cpy) *op++ = *match++;
} else {
LZ4_copy8(op, match);
if (length>16) LZ4_wildCopy(op+8, match+8, cpy);
}
op=cpy; /* correction */
}
/* end of decoding */
if (endOnInput)
return (int) (((char*)op)-dest); /* Nb of output bytes decoded */
return (int) (((char*)op)-dest); /* Nb of output bytes decoded */
else
return (int) (((const char*)ip)-source); /* Nb of input bytes read */
@ -921,7 +921,7 @@ void Packet::armor(const void *key,bool encryptPayload)
s20.crypt12(payload,payload,payloadLen);
uint64_t mac[2];
Poly1305::compute(mac,payload,payloadLen,macKey);
ZT_FAST_MEMCPY(data + ZT_PACKET_IDX_MAC,mac,8);
memcpy(data + ZT_PACKET_IDX_MAC,mac,8);
}
}
@ -989,11 +989,11 @@ bool Packet::compress()
if ((!compressed())&&(size() > (ZT_PACKET_IDX_PAYLOAD + 64))) { // don't bother compressing tiny packets
int pl = (int)(size() - ZT_PACKET_IDX_PAYLOAD);
int cl = LZ4_compress_fast(data + ZT_PACKET_IDX_PAYLOAD,buf,pl,ZT_PROTO_MAX_PACKET_LENGTH * 2,2);
int cl = LZ4_compress_fast(data + ZT_PACKET_IDX_PAYLOAD,buf,pl,ZT_PROTO_MAX_PACKET_LENGTH * 2,1);
if ((cl > 0)&&(cl < pl)) {
data[ZT_PACKET_IDX_VERB] |= (char)ZT_PROTO_VERB_FLAG_COMPRESSED;
setSize((unsigned int)cl + ZT_PACKET_IDX_PAYLOAD);
ZT_FAST_MEMCPY(data + ZT_PACKET_IDX_PAYLOAD,buf,cl);
memcpy(data + ZT_PACKET_IDX_PAYLOAD,buf,cl);
return true;
}
}
@ -1013,7 +1013,7 @@ bool Packet::uncompress()
int ucl = LZ4_decompress_safe((const char *)data + ZT_PACKET_IDX_PAYLOAD,buf,compLen,sizeof(buf));
if ((ucl > 0)&&(ucl <= (int)(capacity() - ZT_PACKET_IDX_PAYLOAD))) {
setSize((unsigned int)ucl + ZT_PACKET_IDX_PAYLOAD);
ZT_FAST_MEMCPY(data + ZT_PACKET_IDX_PAYLOAD,buf,ucl);
memcpy(data + ZT_PACKET_IDX_PAYLOAD,buf,ucl);
} else {
return false;
}

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -45,33 +45,31 @@
/**
* Protocol version -- incremented only for major changes
*
* 1 - 0.2.0 ... 0.2.5
* 2 - 0.3.0 ... 0.4.5
* 1 - 0.2.0 ... 0.2.5
* 2 - 0.3.0 ... 0.4.5
* + Added signature and originating peer to multicast frame
* + Double size of multicast frame bloom filter
* 3 - 0.5.0 ... 0.6.0
* 3 - 0.5.0 ... 0.6.0
* + Yet another multicast redesign
* + New crypto completely changes key agreement cipher
* 4 - 0.6.0 ... 1.0.6
* 4 - 0.6.0 ... 1.0.6
* + BREAKING CHANGE: New identity format based on hashcash design
* 5 - 1.1.0 ... 1.1.5
* 5 - 1.1.0 ... 1.1.5
* + Supports echo
* + Supports in-band world (root server definition) updates
* + Clustering! (Though this will work with protocol v4 clients.)
* + Otherwise backward compatible with protocol v4
* 6 - 1.1.5 ... 1.1.10
* 6 - 1.1.5 ... 1.1.10
* + Network configuration format revisions including binary values
* 7 - 1.1.10 ... 1.1.17
* 7 - 1.1.10 ... 1.1.17
* + Introduce trusted paths for local SDN use
* 8 - 1.1.17 ... 1.2.0
* 8 - 1.1.17 ... 1.2.0
* + Multipart network configurations for large network configs
* + Tags and Capabilities
* + Inline push of CertificateOfMembership deprecated
* 9 - 1.2.0 ... 1.4.0
* + Trace for remote debugging or diagnostics
* 9 - 1.2.0 ... 1.2.14
* 10 - 1.4.0 ... CURRENT
* + Multipath support
* + Measurement of QoS metrics
* + Multipath capability and load balancing
*/
#define ZT_PROTO_VERSION 10
@ -759,7 +757,7 @@ public:
* For patches and other updates a NETWORK_CONFIG is sent instead.
*
* It would be valid and correct as of 1.2.0 to use NETWORK_CONFIG always,
* but OK(NTEWORK_CONFIG_REQUEST) should be sent for compatibility.
* but OK(NETWORK_CONFIG_REQUEST) should be sent for compatibility.
*
* OK response payload:
* <[8] 64-bit network ID>

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -79,10 +79,10 @@ public:
_k[1] = (uint64_t)reinterpret_cast<const struct sockaddr_in *>(&r)->sin_port;
_k[2] = (uint64_t)l;
} else if (r.ss_family == AF_INET6) {
ZT_FAST_MEMCPY(_k,reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,16);
memcpy(_k,reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_addr.s6_addr,16);
_k[2] = ((uint64_t)reinterpret_cast<const struct sockaddr_in6 *>(&r)->sin6_port << 32) ^ (uint64_t)l;
} else {
ZT_FAST_MEMCPY(_k,&r,std::min(sizeof(_k),sizeof(InetAddress)));
memcpy(_k,&r,std::min(sizeof(_k),sizeof(InetAddress)));
_k[2] += (uint64_t)l;
}
}
@ -125,7 +125,8 @@ public:
_lastComputedThroughputDistCoeff(0.0),
_lastAllocation(0)
{
prepareBuffers();
memset(_ifname, 0, 16);
memset(_addrString, 0, sizeof(_addrString));
}
Path(const int64_t localSocket,const InetAddress &addr) :
@ -157,20 +158,11 @@ public:
_lastComputedThroughputDistCoeff(0.0),
_lastAllocation(0)
{
prepareBuffers();
_phy->getIfName((PhySocket *)((uintptr_t)_localSocket), _ifname, 16);
}
~Path()
{
delete _throughputSamples;
delete _latencySamples;
delete _packetValiditySamples;
delete _throughputDisturbanceSamples;
_throughputSamples = NULL;
_latencySamples = NULL;
_packetValiditySamples = NULL;
_throughputDisturbanceSamples = NULL;
memset(_ifname, 0, 16);
memset(_addrString, 0, sizeof(_addrString));
if (_localSocket != -1) {
_phy->getIfName((PhySocket *) ((uintptr_t) _localSocket), _ifname, 16);
}
}
/**
@ -218,7 +210,7 @@ public:
else {
_latency = l;
}
_latencySamples->push(l);
_latencySamples.push(l);
}
/**
@ -349,7 +341,7 @@ public:
_inQoSRecords[packetId] = now;
_packetsReceivedSinceLastQoS++;
}
_packetValiditySamples->push(true);
_packetValiditySamples.push(true);
}
}
@ -366,8 +358,8 @@ public:
_unackedBytes = (ackedBytes > _unackedBytes) ? 0 : _unackedBytes - ackedBytes;
int64_t timeSinceThroughputEstimate = (now - _lastThroughputEstimation);
if (timeSinceThroughputEstimate >= ZT_PATH_THROUGHPUT_MEASUREMENT_INTERVAL) {
uint64_t throughput = (float)(_bytesAckedSinceLastThroughputEstimation * 8) / ((float)timeSinceThroughputEstimate / (float)1000);
_throughputSamples->push(throughput);
uint64_t throughput = (uint64_t)((float)(_bytesAckedSinceLastThroughputEstimation * 8) / ((float)timeSinceThroughputEstimate / (float)1000));
_throughputSamples.push(throughput);
_maxLifetimeThroughput = throughput > _maxLifetimeThroughput ? throughput : _maxLifetimeThroughput;
_lastThroughputEstimation = now;
_bytesAckedSinceLastThroughputEstimation = 0;
@ -433,7 +425,7 @@ public:
if (it != _outQoSRecords.end()) {
uint16_t rtt = (uint16_t)(now - it->second);
uint16_t rtt_compensated = rtt - rx_ts[j];
float latency = rtt_compensated / 2.0;
uint16_t latency = rtt_compensated / 2;
updateLatency(latency, now);
_outQoSRecords.erase(it);
}
@ -458,7 +450,7 @@ public:
uint64_t id = it->first;
memcpy(qosBuffer, &id, sizeof(uint64_t));
qosBuffer+=sizeof(uint64_t);
uint16_t holdingTime = (now - it->second);
uint16_t holdingTime = (uint16_t)(now - it->second);
memcpy(qosBuffer, &holdingTime, sizeof(uint16_t));
qosBuffer+=sizeof(uint16_t);
len+=sizeof(uint64_t)+sizeof(uint16_t);
@ -573,7 +565,7 @@ public:
* Record an invalid incoming packet. This packet failed MAC/compression/cipher checks and will now
* contribute to a Packet Error Ratio (PER).
*/
inline void recordInvalidPacket() { _packetValiditySamples->push(false); }
inline void recordInvalidPacket() { _packetValiditySamples.push(false); }
/**
* @return A pointer to a cached copy of the address string for this Path (For debugging only)
@ -591,36 +583,44 @@ public:
*
* @param now Current time
*/
inline void processBackgroundPathMeasurements(int64_t now) {
inline void processBackgroundPathMeasurements(const int64_t now)
{
if (now - _lastPathQualityComputeTime > ZT_PATH_QUALITY_COMPUTE_INTERVAL) {
DEBUG_INFO("");
Mutex::Lock _l(_statistics_m);
_lastPathQualityComputeTime = now;
address().toString(_addrString);
_lastComputedMeanLatency = _latencySamples->mean();
_lastComputedPacketDelayVariance = _latencySamples->stddev(); // Similar to "jitter" (SEE: RFC 3393, RFC 4689)
_lastComputedMeanThroughput = (uint64_t)_throughputSamples->mean();
_lastComputedMeanLatency = _latencySamples.mean();
_lastComputedPacketDelayVariance = _latencySamples.stddev(); // Similar to "jitter" (SEE: RFC 3393, RFC 4689)
_lastComputedMeanThroughput = (uint64_t)_throughputSamples.mean();
// If no packet validity samples, assume PER==0
_lastComputedPacketErrorRatio = 1 - (_packetValiditySamples->count() ? _packetValiditySamples->mean() : 1);
_lastComputedPacketErrorRatio = 1 - (_packetValiditySamples.count() ? _packetValiditySamples.mean() : 1);
// Compute path stability
// Normalize measurements with wildly different ranges into a reasonable range
float normalized_pdv = Utils::normalize(_lastComputedPacketDelayVariance, 0, ZT_PATH_MAX_PDV, 0, 10);
float normalized_la = Utils::normalize(_lastComputedMeanLatency, 0, ZT_PATH_MAX_MEAN_LATENCY, 0, 10);
float throughput_cv = _throughputSamples->mean() > 0 ? _throughputSamples->stddev() / _throughputSamples->mean() : 1;
float throughput_cv = _throughputSamples.mean() > 0 ? _throughputSamples.stddev() / _throughputSamples.mean() : 1;
// Form an exponential cutoff and apply contribution weights
float pdv_contrib = exp((-1)*normalized_pdv) * ZT_PATH_CONTRIB_PDV;
float latency_contrib = exp((-1)*normalized_la) * ZT_PATH_CONTRIB_LATENCY;
float pdv_contrib = expf((-1.0f)*normalized_pdv) * (float)ZT_PATH_CONTRIB_PDV;
float latency_contrib = expf((-1.0f)*normalized_la) * (float)ZT_PATH_CONTRIB_LATENCY;
// Throughput Disturbance Coefficient
float throughput_disturbance_contrib = exp((-1)*throughput_cv) * ZT_PATH_CONTRIB_THROUGHPUT_DISTURBANCE;
_throughputDisturbanceSamples->push(throughput_cv);
_lastComputedThroughputDistCoeff = _throughputDisturbanceSamples->mean();
float throughput_disturbance_contrib = expf((-1.0f)*throughput_cv) * (float)ZT_PATH_CONTRIB_THROUGHPUT_DISTURBANCE;
_throughputDisturbanceSamples.push(throughput_cv);
_lastComputedThroughputDistCoeff = _throughputDisturbanceSamples.mean();
// Obey user-defined ignored contributions
pdv_contrib = ZT_PATH_CONTRIB_PDV > 0.0 ? pdv_contrib : 1;
latency_contrib = ZT_PATH_CONTRIB_LATENCY > 0.0 ? latency_contrib : 1;
throughput_disturbance_contrib = ZT_PATH_CONTRIB_THROUGHPUT_DISTURBANCE > 0.0 ? throughput_disturbance_contrib : 1;
// Stability
_lastComputedStability = pdv_contrib + latency_contrib + throughput_disturbance_contrib;
_lastComputedStability *= 1 - _lastComputedPacketErrorRatio;
// Prevent QoS records from sticking around for too long
std::map<uint64_t,uint64_t>::iterator it = _outQoSRecords.begin();
while (it != _outQoSRecords.end()) {
@ -657,18 +657,6 @@ public:
*/
inline int64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; }
/**
* Initialize statistical buffers
*/
inline void prepareBuffers() {
_throughputSamples = new RingBuffer<uint64_t>(ZT_PATH_QUALITY_METRIC_WIN_SZ);
_latencySamples = new RingBuffer<uint32_t>(ZT_PATH_QUALITY_METRIC_WIN_SZ);
_packetValiditySamples = new RingBuffer<bool>(ZT_PATH_QUALITY_METRIC_WIN_SZ);
_throughputDisturbanceSamples = new RingBuffer<float>(ZT_PATH_QUALITY_METRIC_WIN_SZ);
memset(_ifname, 0, 16);
memset(_addrString, 0, sizeof(_addrString));
}
private:
Mutex _statistics_m;
@ -682,9 +670,9 @@ private:
InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often
AtomicCounter __refCount;
std::map<uint64_t, uint64_t> _outQoSRecords; // id:egress_time
std::map<uint64_t, uint64_t> _inQoSRecords; // id:now
std::map<uint64_t, uint16_t> _inACKRecords; // id:len
std::map<uint64_t,uint64_t> _outQoSRecords; // id:egress_time
std::map<uint64_t,uint64_t> _inQoSRecords; // id:now
std::map<uint64_t,uint16_t> _inACKRecords; // id:len
int64_t _lastAck;
int64_t _lastThroughputEstimation;
@ -712,16 +700,14 @@ private:
float _lastComputedThroughputDistCoeff;
unsigned char _lastAllocation;
// cached human-readable strings for tracing purposes
char _ifname[16];
char _addrString[256];
RingBuffer<uint64_t> *_throughputSamples;
RingBuffer<uint32_t> *_latencySamples;
RingBuffer<bool> *_packetValiditySamples;
RingBuffer<float> *_throughputDisturbanceSamples;
RingBuffer<uint64_t,ZT_PATH_QUALITY_METRIC_WIN_SZ> _throughputSamples;
RingBuffer<uint32_t,ZT_PATH_QUALITY_METRIC_WIN_SZ> _latencySamples;
RingBuffer<bool,ZT_PATH_QUALITY_METRIC_WIN_SZ> _packetValiditySamples;
RingBuffer<float,ZT_PATH_QUALITY_METRIC_WIN_SZ> _throughputDisturbanceSamples;
};
} // namespace ZeroTier

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -41,6 +41,8 @@
namespace ZeroTier {
static unsigned char s_freeRandomByteCounter = 0;
Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) :
RR(renv),
_lastReceive(0),
@ -51,15 +53,13 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
_lastCredentialRequestSent(0),
_lastWhoisRequestReceived(0),
_lastEchoRequestReceived(0),
_lastComRequestReceived(0),
_lastComRequestSent(0),
_lastCredentialsReceived(0),
_lastTrustEstablishedPacketReceived(0),
_lastSentFullHello(0),
_lastACKWindowReset(0),
_lastQoSWindowReset(0),
_lastMultipathCompatibilityCheck(0),
_freeRandomByte(0),
_freeRandomByte((unsigned char)((uintptr_t)this >> 4) ^ ++s_freeRandomByteCounter),
_uniqueAlivePathCount(0),
_localMultipathSupported(false),
_remoteMultipathSupported(false),
@ -77,10 +77,8 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
_lastAggregateStatsReport(0),
_lastAggregateAllocation(0)
{
Utils::getSecureRandom(&_freeRandomByte, 1);
if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH))
throw ZT_EXCEPTION_INVALID_ARGUMENT;
_pathChoiceHist = new RingBuffer<int>(ZT_MULTIPATH_PROPORTION_WIN_SZ);
}
void Peer::received(
@ -106,7 +104,8 @@ void Peer::received(
case Packet::VERB_MULTICAST_FRAME:
_lastNontrivialReceive = now;
break;
default: break;
default:
break;
}
if (trustEstablished) {
@ -162,12 +161,13 @@ void Peer::received(
break;
}
// If the path is the same address and port, simply assume this is a replacement
if ( (_paths[i].p->address().ipsEqual2(path->address()) && (_paths[i].p->address().port() == path->address().port()))) {
if ( (_paths[i].p->address().ipsEqual2(path->address()))) {
replacePath = i;
break;
}
} else break;
}
// If the path isn't a duplicate of the same localSocket AND we haven't already determined a replacePath,
// then find the worst path and replace it.
if (!redundant && replacePath == ZT_MAX_PEER_NETWORK_PATHS) {
@ -185,6 +185,7 @@ void Peer::received(
}
}
}
if (replacePath != ZT_MAX_PEER_NETWORK_PATHS) {
if (verb == Packet::VERB_OK) {
RR->t->peerLearnedNewPath(tPtr,networkId,*this,path,packetId);
@ -205,39 +206,20 @@ void Peer::received(
}
// If we have a trust relationship periodically push a message enumerating
// all known external addresses for ourselves. We now do this even if we
// have a current path since we'll want to use new ones too.
// all known external addresses for ourselves. If we already have a path this
// is done less frequently.
if (this->trustEstablished(now)) {
if ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) {
const int64_t sinceLastPush = now - _lastDirectPathPushSent;
if (sinceLastPush >= ((hops == 0) ? ZT_DIRECT_PATH_PUSH_INTERVAL_HAVEPATH : ZT_DIRECT_PATH_PUSH_INTERVAL)) {
_lastDirectPathPushSent = now;
std::vector<InetAddress> pathsToPush;
std::vector<InetAddress> dps(RR->node->directPaths());
for(std::vector<InetAddress>::const_iterator i(dps.begin());i!=dps.end();++i)
pathsToPush.push_back(*i);
// Do symmetric NAT prediction if we are communicating indirectly.
if (hops > 0) {
std::vector<InetAddress> sym(RR->sa->getSymmetricNatPredictions());
for(unsigned long i=0,added=0;i<sym.size();++i) {
InetAddress tmp(sym[(unsigned long)RR->node->prng() % sym.size()]);
if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) {
pathsToPush.push_back(tmp);
if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY)
break;
}
}
}
std::vector<InetAddress> pathsToPush(RR->node->directPaths());
if (pathsToPush.size() > 0) {
std::vector<InetAddress>::const_iterator p(pathsToPush.begin());
while (p != pathsToPush.end()) {
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS);
outp.addSize(2); // leave room for count
Packet *const outp = new Packet(_id.address(),RR->identity.address(),Packet::VERB_PUSH_DIRECT_PATHS);
outp->addSize(2); // leave room for count
unsigned int count = 0;
while ((p != pathsToPush.end())&&((outp.size() + 24) < 1200)) {
while ((p != pathsToPush.end())&&((outp->size() + 24) < 1200)) {
uint8_t addressType = 4;
switch(p->ss_family) {
case AF_INET:
@ -250,22 +232,23 @@ void Peer::received(
continue;
}
outp.append((uint8_t)0); // no flags
outp.append((uint16_t)0); // no extensions
outp.append(addressType);
outp.append((uint8_t)((addressType == 4) ? 6 : 18));
outp.append(p->rawIpData(),((addressType == 4) ? 4 : 16));
outp.append((uint16_t)p->port());
outp->append((uint8_t)0); // no flags
outp->append((uint16_t)0); // no extensions
outp->append(addressType);
outp->append((uint8_t)((addressType == 4) ? 6 : 18));
outp->append(p->rawIpData(),((addressType == 4) ? 4 : 16));
outp->append((uint16_t)p->port());
++count;
++p;
}
if (count) {
outp.setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count);
outp.armor(_key,true);
path->send(RR,tPtr,outp.data(),outp.size(),now);
outp->setAt(ZT_PACKET_IDX_PAYLOAD,(uint16_t)count);
outp->compress();
outp->armor(_key,true);
path->send(RR,tPtr,outp->data(),outp->size(),now);
}
delete outp;
}
}
}
@ -275,8 +258,7 @@ void Peer::received(
void Peer::recordOutgoingPacket(const SharedPtr<Path> &path, const uint64_t packetId,
uint16_t payloadLength, const Packet::Verb verb, int64_t now)
{
// Grab second byte from packetId to use as a source of entropy in the next path selection
_freeRandomByte = (packetId & 0xFF00) >> 8;
_freeRandomByte += (unsigned char)(packetId >> 8); // grab entropy to use in path selection logic for multipath
if (_canUseMultipath) {
path->recordOutgoingPacket(now, packetId, payloadLength, verb);
}
@ -307,7 +289,7 @@ void Peer::computeAggregateProportionalAllocation(int64_t now)
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
if (_paths[i].p) {
relStability[i] = _paths[i].p->lastComputedStability();
relThroughput[i] = _paths[i].p->maxLifetimeThroughput();
relThroughput[i] = (float)_paths[i].p->maxLifetimeThroughput();
maxStability = relStability[i] > maxStability ? relStability[i] : maxStability;
maxThroughput = relThroughput[i] > maxThroughput ? relThroughput[i] : maxThroughput;
maxScope = _paths[i].p->ipScope() > maxScope ? _paths[i].p->ipScope() : maxScope;
@ -318,17 +300,17 @@ void Peer::computeAggregateProportionalAllocation(int64_t now)
if (_paths[i].p) {
relStability[i] /= maxStability ? maxStability : 1;
relThroughput[i] /= maxThroughput ? maxThroughput : 1;
float normalized_ma = Utils::normalize(_paths[i].p->ackAge(now), 0, ZT_PATH_MAX_AGE, 0, 10);
float normalized_ma = Utils::normalize((float)_paths[i].p->ackAge(now), 0, ZT_PATH_MAX_AGE, 0, 10);
float age_contrib = exp((-1)*normalized_ma);
float relScope = ((float)(_paths[i].p->ipScope()+1) / (maxScope + 1));
float relQuality =
(relStability[i] * ZT_PATH_CONTRIB_STABILITY)
+ (fmax(1, relThroughput[i]) * ZT_PATH_CONTRIB_THROUGHPUT)
+ relScope * ZT_PATH_CONTRIB_SCOPE;
(relStability[i] * (float)ZT_PATH_CONTRIB_STABILITY)
+ (fmaxf(1.0f, relThroughput[i]) * (float)ZT_PATH_CONTRIB_THROUGHPUT)
+ relScope * (float)ZT_PATH_CONTRIB_SCOPE;
relQuality *= age_contrib;
// Arbitrary cutoffs
relQuality = relQuality > (1.00 / 100.0) ? relQuality : 0.0;
relQuality = relQuality < (99.0 / 100.0) ? relQuality : 1.0;
relQuality = relQuality > (1.00f / 100.0f) ? relQuality : 0.0f;
relQuality = relQuality < (99.0f / 100.0f) ? relQuality : 1.0f;
totalRelativeQuality += relQuality;
_paths[i].p->updateRelativeQuality(relQuality);
}
@ -336,7 +318,7 @@ void Peer::computeAggregateProportionalAllocation(int64_t now)
// Convert set of relative performances into an allocation set
for(uint16_t i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
if (_paths[i].p) {
_paths[i].p->updateComponentAllocationOfAggregateLink((_paths[i].p->relativeQuality() / totalRelativeQuality) * 255);
_paths[i].p->updateComponentAllocationOfAggregateLink((unsigned char)((_paths[i].p->relativeQuality() / totalRelativeQuality) * 255));
}
}
}
@ -349,7 +331,7 @@ int Peer::computeAggregateLinkPacketDelayVariance()
pdv += _paths[i].p->relativeQuality() * _paths[i].p->packetDelayVariance();
}
}
return pdv;
return (int)pdv;
}
int Peer::computeAggregateLinkMeanLatency()
@ -359,7 +341,7 @@ int Peer::computeAggregateLinkMeanLatency()
for(unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {
if (_paths[i].p) {
pathCount++;
ml += _paths[i].p->relativeQuality() * _paths[i].p->meanLatency();
ml += (int)(_paths[i].p->relativeQuality() * _paths[i].p->meanLatency());
}
}
return ml / pathCount;
@ -475,7 +457,7 @@ SharedPtr<Path> Peer::getAppropriatePath(int64_t now, bool includeExpired)
if (_paths[i].p) {
if (rf < _paths[i].p->allocation()) {
bestPath = i;
_pathChoiceHist->push(bestPath); // Record which path we chose
_pathChoiceHist.push(bestPath); // Record which path we chose
break;
}
rf -= _paths[i].p->allocation();
@ -501,10 +483,10 @@ char *Peer::interfaceListStr()
if (_paths[i].p && _paths[i].p->alive(now)) {
int ipv = _paths[i].p->address().isV4();
// If this is acting as an aggregate link, check allocations
float targetAllocation = 1.0 / alivePathCount;
float currentAllocation = 1.0;
float targetAllocation = 1.0f / (float)alivePathCount;
float currentAllocation = 1.0f;
if (alivePathCount > 1) {
currentAllocation = (float)_pathChoiceHist->countValue(i) / (float)_pathChoiceHist->count();
currentAllocation = (float)_pathChoiceHist.countValue(i) / (float)_pathChoiceHist.count();
if (fabs(targetAllocation - currentAllocation) > ZT_PATH_IMBALANCE_THRESHOLD) {
imbalanced = true;
}
@ -652,10 +634,11 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
}
}
inline void Peer::processBackgroundPeerTasks(int64_t now)
inline void Peer::processBackgroundPeerTasks(const int64_t now)
{
// Determine current multipath compatibility with other peer
if ((now - _lastMultipathCompatibilityCheck) >= ZT_PATH_QUALITY_COMPUTE_INTERVAL) {
//
// Cache number of available paths so that we can short-circuit multipath logic elsewhere
//
// We also take notice of duplicate paths (same IP only) because we may have
@ -665,6 +648,7 @@ inline void Peer::processBackgroundPeerTasks(int64_t now)
//
// This is done to support the behavior of auto multipath enable/disable
// without user intervention.
//
int currAlivePathCount = 0;
int duplicatePathsFound = 0;
for (unsigned int i=0;i<ZT_MAX_PEER_NETWORK_PATHS;++i) {

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -60,11 +60,7 @@ private:
Peer() {} // disabled to prevent bugs -- should not be constructed uninitialized
public:
~Peer() {
Utils::burn(_key,sizeof(_key));
delete _pathChoiceHist;
_pathChoiceHist = NULL;
}
~Peer() { Utils::burn(_key,sizeof(_key)); }
/**
* Construct a new peer
@ -423,7 +419,7 @@ public:
*
* @param now Current time
*/
inline void processBackgroundPeerTasks(int64_t now);
inline void processBackgroundPeerTasks(const int64_t now);
/**
* Record that the remote peer does have multipath enabled. As is evident by the receipt of a VERB_ACK
@ -513,30 +509,6 @@ public:
return false;
}
/**
* Rate gate incoming requests for network COM
*/
inline bool rateGateIncomingComRequest(const int64_t now)
{
if ((now - _lastComRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) {
_lastComRequestReceived = now;
return true;
}
return false;
}
/**
* Rate gate outgoing requests for network COM
*/
inline bool rateGateOutgoingComRequest(const int64_t now)
{
if ((now - _lastComRequestSent) >= ZT_PEER_GENERAL_RATE_LIMIT) {
_lastComRequestSent = now;
return true;
}
return false;
}
/**
* Rate limit gate for VERB_ACK
*/
@ -665,8 +637,6 @@ private:
int64_t _lastCredentialRequestSent;
int64_t _lastWhoisRequestReceived;
int64_t _lastEchoRequestReceived;
int64_t _lastComRequestReceived;
int64_t _lastComRequestSent;
int64_t _lastCredentialsReceived;
int64_t _lastTrustEstablishedPacketReceived;
int64_t _lastSentFullHello;
@ -700,7 +670,7 @@ private:
AtomicCounter __refCount;
RingBuffer<int> *_pathChoiceHist;
RingBuffer<int,ZT_MULTIPATH_PROPORTION_WIN_SZ> _pathChoiceHist;
bool _linkIsBalanced;
bool _linkIsRedundant;

View file

@ -18,115 +18,6 @@ Public domain.
namespace ZeroTier {
#if 0
// "Naive" implementation, which is slower... might still want this on some older
// or weird platforms if the later versions have issues.
static inline void add(unsigned int h[17],const unsigned int c[17])
{
unsigned int j;
unsigned int u;
u = 0;
for (j = 0;j < 17;++j) { u += h[j] + c[j]; h[j] = u & 255; u >>= 8; }
}
static inline void squeeze(unsigned int h[17])
{
unsigned int j;
unsigned int u;
u = 0;
for (j = 0;j < 16;++j) { u += h[j]; h[j] = u & 255; u >>= 8; }
u += h[16]; h[16] = u & 3;
u = 5 * (u >> 2);
for (j = 0;j < 16;++j) { u += h[j]; h[j] = u & 255; u >>= 8; }
u += h[16]; h[16] = u;
}
static const unsigned int minusp[17] = {
5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 252
} ;
static inline void freeze(unsigned int h[17])
{
unsigned int horig[17];
unsigned int j;
unsigned int negative;
for (j = 0;j < 17;++j) horig[j] = h[j];
add(h,minusp);
negative = -(h[16] >> 7);
for (j = 0;j < 17;++j) h[j] ^= negative & (horig[j] ^ h[j]);
}
static inline void mulmod(unsigned int h[17],const unsigned int r[17])
{
unsigned int hr[17];
unsigned int i;
unsigned int j;
unsigned int u;
for (i = 0;i < 17;++i) {
u = 0;
for (j = 0;j <= i;++j) u += h[j] * r[i - j];
for (j = i + 1;j < 17;++j) u += 320 * h[j] * r[i + 17 - j];
hr[i] = u;
}
for (i = 0;i < 17;++i) h[i] = hr[i];
squeeze(h);
}
static inline int crypto_onetimeauth(unsigned char *out,const unsigned char *in,unsigned long long inlen,const unsigned char *k)
{
unsigned int j;
unsigned int r[17];
unsigned int h[17];
unsigned int c[17];
r[0] = k[0];
r[1] = k[1];
r[2] = k[2];
r[3] = k[3] & 15;
r[4] = k[4] & 252;
r[5] = k[5];
r[6] = k[6];
r[7] = k[7] & 15;
r[8] = k[8] & 252;
r[9] = k[9];
r[10] = k[10];
r[11] = k[11] & 15;
r[12] = k[12] & 252;
r[13] = k[13];
r[14] = k[14];
r[15] = k[15] & 15;
r[16] = 0;
for (j = 0;j < 17;++j) h[j] = 0;
while (inlen > 0) {
for (j = 0;j < 17;++j) c[j] = 0;
for (j = 0;(j < 16) && (j < inlen);++j) c[j] = in[j];
c[j] = 1;
in += j; inlen -= j;
add(h,c);
mulmod(h,r);
}
freeze(h);
for (j = 0;j < 16;++j) c[j] = k[j + 16];
c[16] = 0;
add(h,c);
for (j = 0;j < 16;++j) out[j] = h[j];
return 0;
}
void Poly1305::compute(void *auth,const void *data,unsigned int len,const void *key)
{
crypto_onetimeauth((unsigned char *)auth,(const unsigned char *)data,len,(const unsigned char *)key);
}
#endif
namespace {
typedef struct poly1305_context {
@ -215,8 +106,7 @@ static inline void U64TO8(unsigned char *p, unsigned long long v)
#define U64TO8(p,v) ((*reinterpret_cast<unsigned long long *>(p)) = (v))
#endif
static inline void
poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
static inline void poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
unsigned long long t0,t1;
@ -241,8 +131,7 @@ poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
st->final = 0;
}
static inline void
poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t bytes) {
static inline 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 */
unsigned long long r0,r1,r2;
unsigned long long s1,s2;
@ -293,8 +182,7 @@ poly1305_blocks(poly1305_state_internal_t *st, const unsigned char *m, size_t by
st->h[2] = h2;
}
static inline void
poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
static inline void poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
unsigned long long h0,h1,h2,c;
unsigned long long g0,g1,g2;
@ -582,8 +470,7 @@ poly1305_finish(poly1305_context *ctx, unsigned char mac[16]) {
#endif // MSC/GCC or not
static inline void
poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) {
static inline void poly1305_update(poly1305_context *ctx, const unsigned char *m, size_t bytes) {
poly1305_state_internal_t *st = (poly1305_state_internal_t *)ctx;
size_t i;

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -58,9 +58,17 @@ class Revocation : public Credential
public:
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_REVOCATION; }
Revocation()
Revocation() :
_id(0),
_credentialId(0),
_networkId(0),
_threshold(0),
_flags(0),
_target(),
_signedBy(),
_type(Credential::CREDENTIAL_TYPE_NULL)
{
memset(this,0,sizeof(Revocation));
memset(_signature.data,0,sizeof(_signature.data));
}
/**
@ -80,7 +88,10 @@ public:
_flags(fl),
_target(tgt),
_signedBy(),
_type(ct) {}
_type(ct)
{
memset(_signature.data,0,sizeof(_signature.data));
}
inline uint32_t id() const { return _id; }
inline uint32_t credentialId() const { return _credentialId; }
@ -148,7 +159,7 @@ public:
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{
memset(this,0,sizeof(Revocation));
*this = Revocation();
unsigned int p = startAt;
@ -166,7 +177,7 @@ public:
if (b[p++] == 1) {
if (b.template at<uint16_t>(p) == ZT_C25519_SIGNATURE_LEN) {
p += 2;
ZT_FAST_MEMCPY(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN);
p += ZT_C25519_SIGNATURE_LEN;
} else throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
} else {

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -47,35 +47,28 @@ namespace ZeroTier {
* to reduce the complexity of code needed to interact with this type of buffer.
*/
template <class T>
template <class T,size_t S>
class RingBuffer
{
private:
T * buf;
size_t size;
T buf[S];
size_t begin;
size_t end;
bool wrap;
public:
/**
* create a RingBuffer with space for up to size elements.
*/
explicit RingBuffer(size_t size)
: size(size),
RingBuffer() :
begin(0),
end(0),
wrap(false)
{
buf = new T[size];
memset(buf, 0, sizeof(T) * size);
memset(buf,0,sizeof(T)*S);
}
/**
* @return A pointer to the underlying buffer
*/
T* get_buf()
inline T *get_buf()
{
return buf + begin;
}
@ -85,17 +78,17 @@ public:
* @param n Number of elements to copy in
* @return Number of elements we copied in
*/
size_t produce(size_t n)
inline size_t produce(size_t n)
{
n = std::min(n, getFree());
if (n == 0) {
return n;
}
const size_t first_chunk = std::min(n, size - end);
end = (end + first_chunk) % size;
const size_t first_chunk = std::min(n, S - end);
end = (end + first_chunk) % S;
if (first_chunk < n) {
const size_t second_chunk = n - first_chunk;
end = (end + second_chunk) % size;
end = (end + second_chunk) % S;
}
if (begin == end) {
wrap = true;
@ -107,17 +100,14 @@ public:
* Fast erase, O(1).
* Merely reset the buffer pointer, doesn't erase contents
*/
void reset()
{
consume(count());
}
inline void reset() { consume(count()); }
/**
* adjust buffer index pointer as if we copied data out
* @param n Number of elements we copied from the buffer
* @return Number of elements actually available from the buffer
*/
size_t consume(size_t n)
inline size_t consume(size_t n)
{
n = std::min(n, count());
if (n == 0) {
@ -126,11 +116,11 @@ public:
if (wrap) {
wrap = false;
}
const size_t first_chunk = std::min(n, size - begin);
begin = (begin + first_chunk) % size;
const size_t first_chunk = std::min(n, S - begin);
begin = (begin + first_chunk) % S;
if (first_chunk < n) {
const size_t second_chunk = n - first_chunk;
begin = (begin + second_chunk) % size;
begin = (begin + second_chunk) % S;
}
return n;
}
@ -139,19 +129,19 @@ public:
* @param data Buffer that is to be written to the ring
* @param n Number of elements to write to the buffer
*/
size_t write(const T * data, size_t n)
inline size_t write(const T * data, size_t n)
{
n = std::min(n, getFree());
if (n == 0) {
return n;
}
const size_t first_chunk = std::min(n, size - end);
const size_t first_chunk = std::min(n, S - end);
memcpy(buf + end, data, first_chunk * sizeof(T));
end = (end + first_chunk) % size;
end = (end + first_chunk) % S;
if (first_chunk < n) {
const size_t second_chunk = n - first_chunk;
memcpy(buf + end, data + first_chunk, second_chunk * sizeof(T));
end = (end + second_chunk) % size;
end = (end + second_chunk) % S;
}
if (begin == end) {
wrap = true;
@ -164,14 +154,14 @@ public:
*
* @param value A single value to be placed in the buffer
*/
void push(const T value)
inline void push(const T value)
{
if (count() == size) {
if (count() == S) {
consume(1);
}
const size_t first_chunk = std::min((size_t)1, size - end);
const size_t first_chunk = std::min((size_t)1, S - end);
*(buf + end) = value;
end = (end + first_chunk) % size;
end = (end + first_chunk) % S;
if (begin == end) {
wrap = true;
}
@ -180,14 +170,14 @@ public:
/**
* @return The most recently pushed element on the buffer
*/
T get_most_recent() { return *(buf + end); }
inline T get_most_recent() { return *(buf + end); }
/**
* @param dest Destination buffer
* @param n Size (in terms of number of elements) of the destination buffer
* @return Number of elements read from the buffer
*/
size_t read(T * dest, size_t n)
inline size_t read(T *dest,size_t n)
{
n = std::min(n, count());
if (n == 0) {
@ -196,13 +186,13 @@ public:
if (wrap) {
wrap = false;
}
const size_t first_chunk = std::min(n, size - begin);
const size_t first_chunk = std::min(n, S - begin);
memcpy(dest, buf + begin, first_chunk * sizeof(T));
begin = (begin + first_chunk) % size;
begin = (begin + first_chunk) % S;
if (first_chunk < n) {
const size_t second_chunk = n - first_chunk;
memcpy(dest + first_chunk, buf + begin, second_chunk * sizeof(T));
begin = (begin + second_chunk) % size;
begin = (begin + second_chunk) % S;
}
return n;
}
@ -212,34 +202,34 @@ public:
*
* @return The number of elements in the buffer
*/
size_t count()
inline size_t count()
{
if (end == begin) {
return wrap ? size : 0;
return wrap ? S : 0;
}
else if (end > begin) {
return end - begin;
}
else {
return size + end - begin;
return S + end - begin;
}
}
/**
* @return The number of slots that are unused in the buffer
*/
size_t getFree() { return size - count(); }
inline size_t getFree() { return S - count(); }
/**
* @return The arithmetic mean of the contents of the buffer
*/
float mean()
inline float mean()
{
size_t iterator = begin;
float subtotal = 0;
size_t curr_cnt = count();
for (size_t i=0; i<curr_cnt; i++) {
iterator = (iterator + size - 1) % curr_cnt;
iterator = (iterator + S - 1) % curr_cnt;
subtotal += (float)*(buf + iterator);
}
return curr_cnt ? subtotal / (float)curr_cnt : 0;
@ -248,14 +238,14 @@ public:
/**
* @return The arithmetic mean of the most recent 'n' elements of the buffer
*/
float mean(size_t n)
inline float mean(size_t n)
{
n = n < size ? n : size;
n = n < S ? n : S;
size_t iterator = begin;
float subtotal = 0;
size_t curr_cnt = count();
for (size_t i=0; i<n; i++) {
iterator = (iterator + size - 1) % curr_cnt;
iterator = (iterator + S - 1) % curr_cnt;
subtotal += (float)*(buf + iterator);
}
return curr_cnt ? subtotal / (float)curr_cnt : 0;
@ -264,39 +254,36 @@ public:
/**
* @return The sample standard deviation of element values
*/
float stddev() { return sqrt(variance()); }
inline float stddev() { return sqrt(variance()); }
/**
* @return The variance of element values
*/
float variance()
inline float variance()
{
size_t iterator = begin;
float cached_mean = mean();
size_t curr_cnt = count();
if (size) {
T sum_of_squared_deviations = 0;
for (size_t i=0; i<curr_cnt; i++) {
iterator = (iterator + size - 1) % curr_cnt;
float deviation = (buf[i] - cached_mean);
sum_of_squared_deviations += (deviation*deviation);
}
float variance = (float)sum_of_squared_deviations / (float)(size - 1);
return variance;
T sum_of_squared_deviations = 0;
for (size_t i=0; i<curr_cnt; i++) {
iterator = (iterator + S - 1) % curr_cnt;
float deviation = (buf[i] - cached_mean);
sum_of_squared_deviations += (T)(deviation*deviation);
}
return 0;
float variance = (float)sum_of_squared_deviations / (float)(S - 1);
return variance;
}
/**
* @return The number of elements of zero value
*/
size_t zeroCount()
inline size_t zeroCount()
{
size_t iterator = begin;
size_t zeros = 0;
size_t curr_cnt = count();
for (size_t i=0; i<curr_cnt; i++) {
iterator = (iterator + size - 1) % curr_cnt;
iterator = (iterator + S - 1) % curr_cnt;
if (*(buf + iterator) == 0) {
zeros++;
}
@ -308,13 +295,13 @@ public:
* @param value Value to match against in buffer
* @return The number of values held in the ring buffer which match a given value
*/
size_t countValue(T value)
inline size_t countValue(T value)
{
size_t iterator = begin;
size_t cnt = 0;
size_t curr_cnt = count();
for (size_t i=0; i<curr_cnt; i++) {
iterator = (iterator + size - 1) % curr_cnt;
iterator = (iterator + S - 1) % curr_cnt;
if (*(buf + iterator) == value) {
cnt++;
}
@ -325,11 +312,12 @@ public:
/**
* Print the contents of the buffer
*/
void dump()
/*
inline void dump()
{
size_t iterator = begin;
for (size_t i=0; i<size; i++) {
iterator = (iterator + size - 1) % size;
for (size_t i=0; i<S; i++) {
iterator = (iterator + S - 1) % S;
if (typeid(T) == typeid(int)) {
//DEBUG_INFO("buf[%2zu]=%2d", iterator, (int)*(buf + iterator));
}
@ -338,6 +326,7 @@ public:
}
}
}
*/
};
} // namespace ZeroTier

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -124,87 +124,4 @@ void SelfAwareness::clean(int64_t now)
}
}
std::vector<InetAddress> SelfAwareness::getSymmetricNatPredictions()
{
/* This is based on ideas and strategies found here:
* https://tools.ietf.org/html/draft-takeda-symmetric-nat-traversal-00
*
* For each IP address reported by a trusted (upstream) peer, we find
* the external port most recently reported by ANY peer for that IP.
*
* We only do any of this for global IPv4 addresses since private IPs
* and IPv6 are not going to have symmetric NAT.
*
* SECURITY NOTE:
*
* We never use IPs reported by non-trusted peers, since this could lead
* to a minor vulnerability whereby a peer could poison our cache with
* bad external surface reports via OK(HELLO) and then possibly coax us
* into suggesting their IP to other peers via PUSH_DIRECT_PATHS. This
* in turn could allow them to MITM flows.
*
* Since flows are encrypted and authenticated they could not actually
* read or modify traffic, but they could gather meta-data for forensics
* purposes or use this as a DOS attack vector. */
std::map< uint32_t,unsigned int > maxPortByIp;
InetAddress theOneTrueSurface;
{
Mutex::Lock _l(_phy_m);
// First check to see if this is a symmetric NAT and enumerate external IPs learned from trusted peers
bool symmetric = false;
{
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);
PhySurfaceKey *k = (PhySurfaceKey *)0;
PhySurfaceEntry *e = (PhySurfaceEntry *)0;
while (i.next(k,e)) {
if ((e->trusted)&&(e->mySurface.ss_family == AF_INET)&&(e->mySurface.ipScope() == InetAddress::IP_SCOPE_GLOBAL)) {
if (!theOneTrueSurface)
theOneTrueSurface = e->mySurface;
else if (theOneTrueSurface != e->mySurface)
symmetric = true;
maxPortByIp[reinterpret_cast<const struct sockaddr_in *>(&(e->mySurface))->sin_addr.s_addr] = e->mySurface.port();
}
}
}
if (!symmetric)
return std::vector<InetAddress>();
{ // Then find the highest issued port per IP
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);
PhySurfaceKey *k = (PhySurfaceKey *)0;
PhySurfaceEntry *e = (PhySurfaceEntry *)0;
while (i.next(k,e)) {
if ((e->mySurface.ss_family == AF_INET)&&(e->mySurface.ipScope() == InetAddress::IP_SCOPE_GLOBAL)) {
const unsigned int port = e->mySurface.port();
std::map< uint32_t,unsigned int >::iterator mp(maxPortByIp.find(reinterpret_cast<const struct sockaddr_in *>(&(e->mySurface))->sin_addr.s_addr));
if ((mp != maxPortByIp.end())&&(mp->second < port))
mp->second = port;
}
}
}
}
std::vector<InetAddress> r;
// Try next port up from max for each
for(std::map< uint32_t,unsigned int >::iterator i(maxPortByIp.begin());i!=maxPortByIp.end();++i) {
unsigned int p = i->second + 1;
if (p > 65535) p -= 64511;
const InetAddress pred(&(i->first),4,p);
if (std::find(r.begin(),r.end(),pred) == r.end())
r.push_back(pred);
}
// Try a random port for each -- there are only 65535 so eventually it should work
for(std::map< uint32_t,unsigned int >::iterator i(maxPortByIp.begin());i!=maxPortByIp.end();++i) {
const InetAddress pred(&(i->first),4,1024 + ((unsigned int)RR->node->prng() % 64511));
if (std::find(r.begin(),r.end(),pred) == r.end())
r.push_back(pred);
}
return r;
}
} // namespace ZeroTier

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -64,13 +64,6 @@ public:
*/
void clean(int64_t now);
/**
* If we appear to be behind a symmetric NAT, get predictions for possible external endpoints
*
* @return Symmetric NAT predictions or empty vector if none
*/
std::vector<InetAddress> getSymmetricNatPredictions();
private:
struct PhySurfaceKey
{

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -417,6 +417,8 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
return;
}
network->pushCredentialsIfNeeded(tPtr,toZT,RR->node->now());
if (fromBridged) {
Packet outp(toZT,RR->identity.address(),Packet::VERB_EXT_FRAME);
outp.append(network->id());
@ -437,7 +439,6 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
outp.compress();
aqm_enqueue(tPtr,network,outp,true,qosBucket);
}
} else {
// Destination is bridged behind a remote peer
@ -502,7 +503,7 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr<Network> &network,const
void Switch::aqm_enqueue(void *tPtr, const SharedPtr<Network> &network, Packet &packet,bool encrypt,int qosBucket)
{
if(!network->QoSEnabled()) {
if(!network->qosEnabled()) {
send(tPtr, packet, encrypt);
return;
}
@ -532,7 +533,7 @@ void Switch::aqm_enqueue(void *tPtr, const SharedPtr<Network> &network, Packet &
TXQueueEntry *txEntry = new TXQueueEntry(dest,RR->node->now(),packet,encrypt);
ManagedQueue *selectedQueue = nullptr;
for (int i=0; i<ZT_QOS_NUM_BUCKETS; i++) {
for (size_t i=0; i<ZT_QOS_NUM_BUCKETS; i++) {
if (i < nqcb->oldQueues.size()) { // search old queues first (I think this is best since old would imply most recent usage of the queue)
if (nqcb->oldQueues[i]->id == qosBucket) {
selectedQueue = nqcb->oldQueues[i];
@ -568,7 +569,7 @@ void Switch::aqm_enqueue(void *tPtr, const SharedPtr<Network> &network, Packet &
{
// DEBUG_INFO("too many enqueued packets (%d), finding packet to drop", nqcb->_currEnqueuedPackets);
int maxQueueLength = 0;
for (int i=0; i<ZT_QOS_NUM_BUCKETS; i++) {
for (size_t i=0; i<ZT_QOS_NUM_BUCKETS; i++) {
if (i < nqcb->oldQueues.size()) {
if (nqcb->oldQueues[i]->byteLength > maxQueueLength) {
maxQueueLength = nqcb->oldQueues[i]->byteLength;
@ -601,7 +602,7 @@ void Switch::aqm_enqueue(void *tPtr, const SharedPtr<Network> &network, Packet &
uint64_t Switch::control_law(uint64_t t, int count)
{
return t + ZT_QOS_INTERVAL / sqrt(count);
return (uint64_t)(t + ZT_QOS_INTERVAL / sqrt(count));
}
Switch::dqr Switch::dodequeue(ManagedQueue *q, uint64_t now)
@ -816,7 +817,6 @@ void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr<Peer> &peer)
{
Mutex::Lock _l(_txQueue_m);
for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) {
if (txi->dest == peer->address()) {
if (_trySend(tPtr,txi->packet,txi->encrypt)) {

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -44,6 +44,16 @@
#include "IncomingPacket.hpp"
#include "Hashtable.hpp"
/* Ethernet frame types that might be relevant to us */
#define ZT_ETHERTYPE_IPV4 0x0800
#define ZT_ETHERTYPE_ARP 0x0806
#define ZT_ETHERTYPE_RARP 0x8035
#define ZT_ETHERTYPE_ATALK 0x809b
#define ZT_ETHERTYPE_AARP 0x80f3
#define ZT_ETHERTYPE_IPX_A 0x8137
#define ZT_ETHERTYPE_IPX_B 0x8138
#define ZT_ETHERTYPE_IPV6 0x86dd
namespace ZeroTier {
class RuntimeEnvironment;

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -65,9 +65,13 @@ class Tag : public Credential
public:
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_TAG; }
Tag()
Tag() :
_id(0),
_value(0),
_networkId(0),
_ts(0)
{
memset(this,0,sizeof(Tag));
memset(_signature.data,0,sizeof(_signature.data));
}
/**
@ -85,6 +89,7 @@ public:
_issuedTo(issuedTo),
_signedBy()
{
memset(_signature.data,0,sizeof(_signature.data));
}
inline uint32_t id() const { return _id; }
@ -149,7 +154,7 @@ public:
{
unsigned int p = startAt;
memset(this,0,sizeof(Tag));
*this = Tag();
_networkId = b.template at<uint64_t>(p); p += 8;
_ts = b.template at<uint64_t>(p); p += 8;
@ -163,7 +168,7 @@ public:
if (b.template at<uint16_t>(p) != ZT_C25519_SIGNATURE_LEN)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
p += 2;
ZT_FAST_MEMCPY(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
} else {
p += 2 + b.template at<uint16_t>(p);
}

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -40,6 +40,7 @@
#include "Tag.hpp"
#include "Capability.hpp"
#include "Revocation.hpp"
#include "../include/ZeroTierDebug.h"
namespace ZeroTier {

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -38,45 +38,11 @@
#include <vector>
#include <map>
#include "Constants.hpp"
#if defined(__FreeBSD__)
#include <sys/endian.h>
#endif
#ifdef __LINUX__
//#if (defined(_MSC_VER) || defined(__GNUC__)) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
#if 0
#include <emmintrin.h>
static inline void ZT_FAST_MEMCPY(void *a,const void *b,unsigned long k)
{
char *aa = reinterpret_cast<char *>(a);
const char *bb = reinterpret_cast<const char *>(b);
while (k >= 64) {
__m128 t1 = _mm_loadu_ps(reinterpret_cast<const float *>(bb));
__m128 t2 = _mm_loadu_ps(reinterpret_cast<const float *>(bb + 16));
__m128 t3 = _mm_loadu_ps(reinterpret_cast<const float *>(bb + 32));
__m128 t4 = _mm_loadu_ps(reinterpret_cast<const float *>(bb + 48));
_mm_storeu_ps(reinterpret_cast<float *>(aa),t1);
_mm_storeu_ps(reinterpret_cast<float *>(aa + 16),t2);
_mm_storeu_ps(reinterpret_cast<float *>(aa + 32),t3);
_mm_storeu_ps(reinterpret_cast<float *>(aa + 48),t4);
bb += 64;
aa += 64;
k -= 64;
}
while (k >= 16) {
__m128 t1 = _mm_loadu_ps(reinterpret_cast<const float *>(bb));
_mm_storeu_ps(reinterpret_cast<float *>(aa),t1);
bb += 16;
aa += 16;
k -= 16;
}
for(unsigned long i=0;i<k;++i)
aa[i] = bb[i];
}
#else
#define ZT_FAST_MEMCPY(a,b,c) memcpy(a,b,c)
#endif
#else
#define ZT_FAST_MEMCPY(a,b,c) memcpy(a,b,c)
#endif
#include "Constants.hpp"
namespace ZeroTier {
@ -263,10 +229,10 @@ public:
static inline float normalize(float value, int64_t bigMin, int64_t bigMax, int32_t targetMin, int32_t targetMax)
{
int64_t bigSpan = bigMax - bigMin;
int64_t smallSpan = targetMax - targetMin;
float valueScaled = (value - (float)bigMin) / (float)bigSpan;
return (float)targetMin + valueScaled * (float)smallSpan;
int64_t bigSpan = bigMax - bigMin;
int64_t smallSpan = targetMax - targetMin;
float valueScaled = (value - (float)bigMin) / (float)bigSpan;
return (float)targetMin + valueScaled * (float)smallSpan;
}
/**
@ -419,8 +385,12 @@ public:
static inline uint64_t hton(uint64_t n)
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
#if defined(__GNUC__) && (!defined(__OpenBSD__))
#if defined(__GNUC__)
#if defined(__FreeBSD__)
return bswap64(n);
#elif (!defined(__OpenBSD__))
return __builtin_bswap64(n);
#endif
#else
return (
((n & 0x00000000000000FFULL) << 56) |
@ -448,8 +418,12 @@ public:
static inline uint64_t ntoh(uint64_t n)
{
#if __BYTE_ORDER == __LITTLE_ENDIAN
#if defined(__GNUC__) && !defined(__OpenBSD__)
#if defined(__GNUC__)
#if defined(__FreeBSD__)
return bswap64(n);
#elif (!defined(__OpenBSD__))
return __builtin_bswap64(n);
#endif
#else
return (
((n & 0x00000000000000FFULL) << 56) |

View file

@ -1,6 +1,6 @@
/*
* ZeroTier One - Network Virtualization Everywhere
* Copyright (C) 2011-2018 ZeroTier, Inc. https://www.zerotier.com/
* Copyright (C) 2011-2019 ZeroTier, Inc. https://www.zerotier.com/
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@ -13,7 +13,7 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* --
*
@ -217,8 +217,8 @@ public:
_id = b.template at<uint64_t>(p); p += 8;
_ts = b.template at<uint64_t>(p); p += 8;
ZT_FAST_MEMCPY(_updatesMustBeSignedBy.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN); p += ZT_C25519_PUBLIC_KEY_LEN;
ZT_FAST_MEMCPY(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
memcpy(_updatesMustBeSignedBy.data,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN); p += ZT_C25519_PUBLIC_KEY_LEN;
memcpy(_signature.data,b.field(p,ZT_C25519_SIGNATURE_LEN),ZT_C25519_SIGNATURE_LEN); p += ZT_C25519_SIGNATURE_LEN;
const unsigned int numRoots = (unsigned int)b[p++];
if (numRoots > ZT_WORLD_MAX_ROOTS)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;