mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-07 13:03:45 +02:00
Create a container for identity hashes, replace some "volatile" hacky junk with std::atomic, clean up some security checks, rename raw data in Buf to unsafeData to permit search for unsafe.
This commit is contained in:
parent
46d3780e89
commit
1e0a930d23
18 changed files with 743 additions and 470 deletions
243
node/Buf.hpp
243
node/Buf.hpp
|
@ -147,7 +147,7 @@ public:
|
||||||
if (l <= ZT_BUF_MEM_SIZE) {
|
if (l <= ZT_BUF_MEM_SIZE) {
|
||||||
r.b.move(s->b);
|
r.b.move(s->b);
|
||||||
if (s->s > 0)
|
if (s->s > 0)
|
||||||
memmove(r.b->b,r.b->b + s->s,l);
|
memmove(r.b->unsafeData,r.b->unsafeData + s->s,l);
|
||||||
r.e = l;
|
r.e = l;
|
||||||
|
|
||||||
while (++s != fcv.end()) {
|
while (++s != fcv.end()) {
|
||||||
|
@ -157,7 +157,7 @@ public:
|
||||||
r.e = 0;
|
r.e = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
memcpy(r.b->b + r.e,s->b->b + s->s,l);
|
memcpy(r.b->unsafeData + r.e,s->b->unsafeData + s->s,l);
|
||||||
s->b.zero(); // let go of buffer in vector as soon as possible
|
s->b.zero(); // let go of buffer in vector as soon as possible
|
||||||
r.e += l;
|
r.e += l;
|
||||||
}
|
}
|
||||||
|
@ -171,12 +171,12 @@ public:
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE Buf() noexcept {}
|
ZT_ALWAYS_INLINE Buf() noexcept {}
|
||||||
|
|
||||||
ZT_ALWAYS_INLINE Buf(const Buf &b2) noexcept { memcpy(b,b2.b,ZT_BUF_MEM_SIZE); }
|
ZT_ALWAYS_INLINE Buf(const Buf &b2) noexcept { memcpy(unsafeData,b2.unsafeData,ZT_BUF_MEM_SIZE); }
|
||||||
|
|
||||||
ZT_ALWAYS_INLINE Buf &operator=(const Buf &b2) noexcept
|
ZT_ALWAYS_INLINE Buf &operator=(const Buf &b2) noexcept
|
||||||
{
|
{
|
||||||
if (this != &b2)
|
if (this != &b2)
|
||||||
memcpy(b,b2.b,ZT_BUF_MEM_SIZE);
|
memcpy(unsafeData,b2.unsafeData,ZT_BUF_MEM_SIZE);
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,29 +206,29 @@ public:
|
||||||
/**
|
/**
|
||||||
* Set all memory to zero
|
* Set all memory to zero
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE void clear() noexcept { memset(b,0,ZT_BUF_MEM_SIZE); }
|
ZT_ALWAYS_INLINE void clear() noexcept { memset(unsafeData,0,ZT_BUF_MEM_SIZE); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Zero security critical data using Utils::burn() to ensure it's never optimized out.
|
* Zero security critical data using Utils::burn() to ensure it's never optimized out.
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE void burn() noexcept { Utils::burn(b,ZT_BUF_MEM_SIZE); }
|
ZT_ALWAYS_INLINE void burn() noexcept { Utils::burn(unsafeData,ZT_BUF_MEM_SIZE); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a byte
|
* Read a byte
|
||||||
*
|
*
|
||||||
* @param ii Iterator
|
* @param ii Index value-result parameter (incremented by 1)
|
||||||
* @return Byte (undefined on overflow)
|
* @return Byte (undefined on overflow)
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE uint8_t rI8(int &ii) const noexcept
|
ZT_ALWAYS_INLINE uint8_t rI8(int &ii) const noexcept
|
||||||
{
|
{
|
||||||
const int s = ii++;
|
const int s = ii++;
|
||||||
return b[(unsigned int)s & ZT_BUF_MEM_MASK];
|
return unsafeData[(unsigned int)s & ZT_BUF_MEM_MASK];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a 16-bit integer
|
* Read a 16-bit integer
|
||||||
*
|
*
|
||||||
* @param ii Integer
|
* @param ii Index value-result parameter (incremented by 2)
|
||||||
* @return Integer (undefined on overflow)
|
* @return Integer (undefined on overflow)
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE uint16_t rI16(int &ii) const noexcept
|
ZT_ALWAYS_INLINE uint16_t rI16(int &ii) const noexcept
|
||||||
|
@ -240,14 +240,14 @@ public:
|
||||||
((uint16_t)data.bytes[s] << 8U) |
|
((uint16_t)data.bytes[s] << 8U) |
|
||||||
(uint16_t)data.bytes[s + 1]);
|
(uint16_t)data.bytes[s + 1]);
|
||||||
#else
|
#else
|
||||||
return Utils::ntoh(*reinterpret_cast<const uint16_t *>(b + s));
|
return Utils::ntoh(*reinterpret_cast<const uint16_t *>(unsafeData + s));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a 32-bit integer
|
* Read a 32-bit integer
|
||||||
*
|
*
|
||||||
* @param ii Integer
|
* @param ii Index value-result parameter (incremented by 4)
|
||||||
* @return Integer (undefined on overflow)
|
* @return Integer (undefined on overflow)
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE uint32_t rI32(int &ii) const noexcept
|
ZT_ALWAYS_INLINE uint32_t rI32(int &ii) const noexcept
|
||||||
|
@ -261,14 +261,14 @@ public:
|
||||||
((uint32_t)data.bytes[s + 2] << 8U) |
|
((uint32_t)data.bytes[s + 2] << 8U) |
|
||||||
(uint32_t)data.bytes[s + 3]);
|
(uint32_t)data.bytes[s + 3]);
|
||||||
#else
|
#else
|
||||||
return Utils::ntoh(*reinterpret_cast<const uint32_t *>(b + s));
|
return Utils::ntoh(*reinterpret_cast<const uint32_t *>(unsafeData + s));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read a 64-bit integer
|
* Read a 64-bit integer
|
||||||
*
|
*
|
||||||
* @param ii Integer
|
* @param ii Index value-result parameter (incremented by 8)
|
||||||
* @return Integer (undefined on overflow)
|
* @return Integer (undefined on overflow)
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE uint64_t rI64(int &ii) const noexcept
|
ZT_ALWAYS_INLINE uint64_t rI64(int &ii) const noexcept
|
||||||
|
@ -286,7 +286,7 @@ public:
|
||||||
((uint64_t)data.bytes[s + 6] << 8U) |
|
((uint64_t)data.bytes[s + 6] << 8U) |
|
||||||
(uint64_t)data.bytes[s + 7]);
|
(uint64_t)data.bytes[s + 7]);
|
||||||
#else
|
#else
|
||||||
return Utils::ntoh(*reinterpret_cast<const uint64_t *>(b + s));
|
return Utils::ntoh(*reinterpret_cast<const uint64_t *>(unsafeData + s));
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,7 +301,7 @@ public:
|
||||||
* indicates.
|
* indicates.
|
||||||
*
|
*
|
||||||
* @tparam T Object type
|
* @tparam T Object type
|
||||||
* @param ii Iterator
|
* @param ii Index value-result parameter (incremented by object's size in bytes)
|
||||||
* @param obj Object to read
|
* @param obj Object to read
|
||||||
* @return Bytes read or a negative value on unmarshal error (passed from object) or overflow
|
* @return Bytes read or a negative value on unmarshal error (passed from object) or overflow
|
||||||
*/
|
*/
|
||||||
|
@ -309,7 +309,7 @@ public:
|
||||||
ZT_ALWAYS_INLINE int rO(int &ii,T &obj) const noexcept
|
ZT_ALWAYS_INLINE int rO(int &ii,T &obj) const noexcept
|
||||||
{
|
{
|
||||||
if (ii < ZT_BUF_MEM_SIZE) {
|
if (ii < ZT_BUF_MEM_SIZE) {
|
||||||
int ms = obj.unmarshal(b + ii,ZT_BUF_MEM_SIZE - ii);
|
int ms = obj.unmarshal(unsafeData + ii,ZT_BUF_MEM_SIZE - ii);
|
||||||
if (ms > 0)
|
if (ms > 0)
|
||||||
ii += ms;
|
ii += ms;
|
||||||
return ms;
|
return ms;
|
||||||
|
@ -323,17 +323,17 @@ public:
|
||||||
* Use this if the buffer's memory may get changed between reading and processing
|
* Use this if the buffer's memory may get changed between reading and processing
|
||||||
* what is read.
|
* what is read.
|
||||||
*
|
*
|
||||||
* @param ii Iterator
|
* @param ii Index value-result parameter (incremented by length of string)
|
||||||
* @param buf Buffer to receive string
|
* @param buf Buffer to receive string
|
||||||
* @param bufSize Capacity of buffer in bytes
|
* @param bufSize Capacity of buffer in bytes
|
||||||
* @return Pointer to buf or NULL on overflow or error
|
* @return Pointer to buf or NULL on overflow or error
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE char *rS(int &ii,char *const buf,const unsigned int bufSize) const noexcept
|
ZT_ALWAYS_INLINE char *rS(int &ii,char *const buf,const unsigned int bufSize) const noexcept
|
||||||
{
|
{
|
||||||
const char *const s = (const char *)(b + ii);
|
const char *const s = (const char *)(unsafeData + ii);
|
||||||
const int sii = ii;
|
const int sii = ii;
|
||||||
while (ii < ZT_BUF_MEM_SIZE) {
|
while (ii < ZT_BUF_MEM_SIZE) {
|
||||||
if (b[ii++] == 0) {
|
if (unsafeData[ii++] == 0) {
|
||||||
memcpy(buf,s,ii - sii);
|
memcpy(buf,s,ii - sii);
|
||||||
return buf;
|
return buf;
|
||||||
}
|
}
|
||||||
|
@ -351,14 +351,14 @@ public:
|
||||||
* This version avoids a copy and so is faster if the buffer won't be modified between
|
* This version avoids a copy and so is faster if the buffer won't be modified between
|
||||||
* reading and processing.
|
* reading and processing.
|
||||||
*
|
*
|
||||||
* @param ii Iterator
|
* @param ii Index value-result parameter (incremented by length of string)
|
||||||
* @return Pointer to null-terminated C-style string or NULL on overflow or error
|
* @return Pointer to null-terminated C-style string or NULL on overflow or error
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE const char *rSnc(int &ii) const noexcept
|
ZT_ALWAYS_INLINE const char *rSnc(int &ii) const noexcept
|
||||||
{
|
{
|
||||||
const char *const s = (const char *)(b + ii);
|
const char *const s = (const char *)(unsafeData + ii);
|
||||||
while (ii < ZT_BUF_MEM_SIZE) {
|
while (ii < ZT_BUF_MEM_SIZE) {
|
||||||
if (b[ii++] == 0)
|
if (unsafeData[ii++] == 0)
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -370,15 +370,15 @@ public:
|
||||||
* Use this if the buffer's memory may get changed between reading and processing
|
* Use this if the buffer's memory may get changed between reading and processing
|
||||||
* what is read.
|
* what is read.
|
||||||
*
|
*
|
||||||
* @param ii Iterator
|
* @param ii Index value-result parameter (incremented by len)
|
||||||
* @param bytes Buffer to contain data to read
|
* @param bytes Buffer to contain data to read
|
||||||
* @param len Length of buffer
|
* @param len Length of buffer
|
||||||
* @return Pointer to data or NULL on overflow or error
|
* @return Pointer to data or NULL on overflow or error
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE uint8_t *rB(int &ii,void *bytes,unsigned int len) const noexcept
|
ZT_ALWAYS_INLINE uint8_t *rB(int &ii,void *const bytes,const unsigned int len) const noexcept
|
||||||
{
|
{
|
||||||
if ((ii += (int)len) <= ZT_BUF_MEM_SIZE) {
|
if ((ii += (int)len) <= ZT_BUF_MEM_SIZE) {
|
||||||
memcpy(bytes,b + ii,len);
|
memcpy(bytes,unsafeData + ii,len);
|
||||||
return reinterpret_cast<uint8_t *>(bytes);
|
return reinterpret_cast<uint8_t *>(bytes);
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -393,7 +393,7 @@ public:
|
||||||
* This version avoids a copy and so is faster if the buffer won't be modified between
|
* This version avoids a copy and so is faster if the buffer won't be modified between
|
||||||
* reading and processing.
|
* reading and processing.
|
||||||
*
|
*
|
||||||
* @param ii Iterator
|
* @param ii Index value-result parameter (incremented by len)
|
||||||
* @param len Length of data field to obtain a pointer to
|
* @param len Length of data field to obtain a pointer to
|
||||||
* @return Pointer to field or NULL on overflow
|
* @return Pointer to field or NULL on overflow
|
||||||
*/
|
*/
|
||||||
|
@ -403,25 +403,102 @@ public:
|
||||||
return ((ii += (int)len) <= ZT_BUF_MEM_SIZE) ? b : nullptr;
|
return ((ii += (int)len) <= ZT_BUF_MEM_SIZE) ? b : nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a value at an index without advancing the index
|
||||||
|
*
|
||||||
|
* Note that unlike the rI??() methods this does not increment ii and therefore
|
||||||
|
* will not necessarily result in a 'true' return from readOverflow(). It does
|
||||||
|
* however subject 'ii' to soft bounds masking like the gI??() methods.
|
||||||
|
*/
|
||||||
|
ZT_ALWAYS_INLINE uint8_t lI8(const int ii) const noexcept
|
||||||
|
{
|
||||||
|
return unsafeData[(unsigned int)ii & ZT_BUF_MEM_MASK];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a value at an index without advancing the index
|
||||||
|
*
|
||||||
|
* Note that unlike the rI??() methods this does not increment ii and therefore
|
||||||
|
* will not necessarily result in a 'true' return from readOverflow(). It does
|
||||||
|
* however subject 'ii' to soft bounds masking like the gI??() methods.
|
||||||
|
*/
|
||||||
|
ZT_ALWAYS_INLINE uint16_t lI16(const int ii) const noexcept
|
||||||
|
{
|
||||||
|
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
|
||||||
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
|
return (
|
||||||
|
((uint16_t)data.bytes[s] << 8U) |
|
||||||
|
(uint16_t)data.bytes[s + 1]);
|
||||||
|
#else
|
||||||
|
return Utils::ntoh(*reinterpret_cast<const uint16_t *>(unsafeData + s));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a value at an index without advancing the index
|
||||||
|
*
|
||||||
|
* Note that unlike the rI??() methods this does not increment ii and therefore
|
||||||
|
* will not necessarily result in a 'true' return from readOverflow(). It does
|
||||||
|
* however subject 'ii' to soft bounds masking like the gI??() methods.
|
||||||
|
*/
|
||||||
|
ZT_ALWAYS_INLINE uint32_t lI32(const int ii) const noexcept
|
||||||
|
{
|
||||||
|
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
|
||||||
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
|
return (
|
||||||
|
((uint32_t)data.bytes[s] << 24U) |
|
||||||
|
((uint32_t)data.bytes[s + 1] << 16U) |
|
||||||
|
((uint32_t)data.bytes[s + 2] << 8U) |
|
||||||
|
(uint32_t)data.bytes[s + 3]);
|
||||||
|
#else
|
||||||
|
return Utils::ntoh(*reinterpret_cast<const uint32_t *>(unsafeData + s));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Load a value at an index without advancing the index
|
||||||
|
*
|
||||||
|
* Note that unlike the rI??() methods this does not increment ii and therefore
|
||||||
|
* will not necessarily result in a 'true' return from readOverflow(). It does
|
||||||
|
* however subject 'ii' to soft bounds masking like the gI??() methods.
|
||||||
|
*/
|
||||||
|
ZT_ALWAYS_INLINE uint8_t lI64(const int ii) const noexcept
|
||||||
|
{
|
||||||
|
const unsigned int s = (unsigned int)ii & ZT_BUF_MEM_MASK;
|
||||||
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
|
return (
|
||||||
|
((uint64_t)data.bytes[s] << 56U) |
|
||||||
|
((uint64_t)data.bytes[s + 1] << 48U) |
|
||||||
|
((uint64_t)data.bytes[s + 2] << 40U) |
|
||||||
|
((uint64_t)data.bytes[s + 3] << 32U) |
|
||||||
|
((uint64_t)data.bytes[s + 4] << 24U) |
|
||||||
|
((uint64_t)data.bytes[s + 5] << 16U) |
|
||||||
|
((uint64_t)data.bytes[s + 6] << 8U) |
|
||||||
|
(uint64_t)data.bytes[s + 7]);
|
||||||
|
#else
|
||||||
|
return Utils::ntoh(*reinterpret_cast<const uint64_t *>(unsafeData + s));
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a byte
|
* Write a byte
|
||||||
*
|
*
|
||||||
* @param ii Iterator
|
* @param ii Index value-result parameter (incremented by 1)
|
||||||
* @param n Byte
|
* @param n Byte
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE void wI(int &ii,uint8_t n) noexcept
|
ZT_ALWAYS_INLINE void wI8(int &ii,const uint8_t n) noexcept
|
||||||
{
|
{
|
||||||
const int s = ii++;
|
const int s = ii++;
|
||||||
b[(unsigned int)s & ZT_BUF_MEM_MASK] = n;
|
unsafeData[(unsigned int)s & ZT_BUF_MEM_MASK] = n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a 16-bit integer in big-endian byte order
|
* Write a 16-bit integer in big-endian byte order
|
||||||
*
|
*
|
||||||
* @param ii Iterator
|
* @param ii Index value-result parameter (incremented by 2)
|
||||||
* @param n Integer
|
* @param n Integer
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE void wI(int &ii,uint16_t n) noexcept
|
ZT_ALWAYS_INLINE void wI16(int &ii,const uint16_t n) noexcept
|
||||||
{
|
{
|
||||||
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
|
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
|
||||||
ii += 2;
|
ii += 2;
|
||||||
|
@ -429,17 +506,17 @@ public:
|
||||||
b[s] = (uint8_t)(n >> 8U);
|
b[s] = (uint8_t)(n >> 8U);
|
||||||
b[s + 1] = (uint8_t)n;
|
b[s + 1] = (uint8_t)n;
|
||||||
#else
|
#else
|
||||||
*reinterpret_cast<uint16_t *>(b + s) = Utils::hton(n);
|
*reinterpret_cast<uint16_t *>(unsafeData + s) = Utils::hton(n);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a 32-bit integer in big-endian byte order
|
* Write a 32-bit integer in big-endian byte order
|
||||||
*
|
*
|
||||||
* @param ii Iterator
|
* @param ii Index value-result parameter (incremented by 4)
|
||||||
* @param n Integer
|
* @param n Integer
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE void wI(int &ii,uint32_t n) noexcept
|
ZT_ALWAYS_INLINE void wI32(int &ii,const uint32_t n) noexcept
|
||||||
{
|
{
|
||||||
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
|
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
|
||||||
ii += 4;
|
ii += 4;
|
||||||
|
@ -449,17 +526,17 @@ public:
|
||||||
b[s + 2] = (uint8_t)(n >> 8U);
|
b[s + 2] = (uint8_t)(n >> 8U);
|
||||||
b[s + 3] = (uint8_t)n;
|
b[s + 3] = (uint8_t)n;
|
||||||
#else
|
#else
|
||||||
*reinterpret_cast<uint32_t *>(b + s) = Utils::hton(n);
|
*reinterpret_cast<uint32_t *>(unsafeData + s) = Utils::hton(n);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a 64-bit integer in big-endian byte order
|
* Write a 64-bit integer in big-endian byte order
|
||||||
*
|
*
|
||||||
* @param ii Iterator
|
* @param ii Index value-result parameter (incremented by 8)
|
||||||
* @param n Integer
|
* @param n Integer
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE void wI(int &ii,uint64_t n) noexcept
|
ZT_ALWAYS_INLINE void wI64(int &ii,const uint64_t n) noexcept
|
||||||
{
|
{
|
||||||
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
|
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
|
||||||
ii += 8;
|
ii += 8;
|
||||||
|
@ -473,7 +550,7 @@ public:
|
||||||
b[s + 6] = (uint8_t)(n >> 8U);
|
b[s + 6] = (uint8_t)(n >> 8U);
|
||||||
b[s + 7] = (uint8_t)n;
|
b[s + 7] = (uint8_t)n;
|
||||||
#else
|
#else
|
||||||
*reinterpret_cast<uint64_t *>(b + s) = Utils::hton(n);
|
*reinterpret_cast<uint64_t *>(unsafeData + s) = Utils::hton(n);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -481,7 +558,7 @@ public:
|
||||||
* Write an object implementing the marshal interface
|
* Write an object implementing the marshal interface
|
||||||
*
|
*
|
||||||
* @tparam T Object type
|
* @tparam T Object type
|
||||||
* @param ii Iterator
|
* @param ii Index value-result parameter (incremented by size of object)
|
||||||
* @param t Object to write
|
* @param t Object to write
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
@ -489,7 +566,7 @@ public:
|
||||||
{
|
{
|
||||||
const int s = ii;
|
const int s = ii;
|
||||||
if ((s + T::marshalSizeMax()) <= ZT_BUF_MEM_SIZE) {
|
if ((s + T::marshalSizeMax()) <= ZT_BUF_MEM_SIZE) {
|
||||||
int ms = t.marshal(b + s);
|
int ms = t.marshal(unsafeData + s);
|
||||||
if (ms > 0)
|
if (ms > 0)
|
||||||
ii += ms;
|
ii += ms;
|
||||||
} else {
|
} else {
|
||||||
|
@ -500,7 +577,7 @@ public:
|
||||||
/**
|
/**
|
||||||
* Write a C-style null-terminated string (including the trailing zero)
|
* Write a C-style null-terminated string (including the trailing zero)
|
||||||
*
|
*
|
||||||
* @param ii Iterator
|
* @param ii Index value-result parameter (incremented by length of string)
|
||||||
* @param s String to write (writes an empty string if this is NULL)
|
* @param s String to write (writes an empty string if this is NULL)
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE void wS(int &ii,const char *s) noexcept
|
ZT_ALWAYS_INLINE void wS(int &ii,const char *s) noexcept
|
||||||
|
@ -509,17 +586,17 @@ public:
|
||||||
char c;
|
char c;
|
||||||
do {
|
do {
|
||||||
c = *(s++);
|
c = *(s++);
|
||||||
wI(ii,(uint8_t)c);
|
wI8(ii,(uint8_t)c);
|
||||||
} while (c);
|
} while (c);
|
||||||
} else {
|
} else {
|
||||||
wI(ii,(uint8_t)0);
|
wI8(ii,0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write a byte array
|
* Write a byte array
|
||||||
*
|
*
|
||||||
* @param ii Iterator
|
* @param ii Index value-result parameter (incremented by len)
|
||||||
* @param bytes Bytes to write
|
* @param bytes Bytes to write
|
||||||
* @param len Size of data in bytes
|
* @param len Size of data in bytes
|
||||||
*/
|
*/
|
||||||
|
@ -527,7 +604,65 @@ public:
|
||||||
{
|
{
|
||||||
const int s = ii;
|
const int s = ii;
|
||||||
if ((ii += (int)len) <= ZT_BUF_MEM_SIZE)
|
if ((ii += (int)len) <= ZT_BUF_MEM_SIZE)
|
||||||
memcpy(b + s,bytes,len);
|
memcpy(unsafeData + s,bytes,len);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store a byte without advancing the index
|
||||||
|
*/
|
||||||
|
ZT_ALWAYS_INLINE void sI8(const int ii,const uint8_t n) noexcept
|
||||||
|
{
|
||||||
|
unsafeData[(unsigned int)ii & ZT_BUF_MEM_MASK] = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store an integer without advancing the index
|
||||||
|
*/
|
||||||
|
ZT_ALWAYS_INLINE void sI16(const int ii,const uint16_t n) noexcept
|
||||||
|
{
|
||||||
|
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
|
||||||
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
|
b[s] = (uint8_t)(n >> 8U);
|
||||||
|
b[s + 1] = (uint8_t)n;
|
||||||
|
#else
|
||||||
|
*reinterpret_cast<uint16_t *>(unsafeData + s) = Utils::hton(n);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store an integer without advancing the index
|
||||||
|
*/
|
||||||
|
ZT_ALWAYS_INLINE void sI32(const int ii,const uint32_t n) noexcept
|
||||||
|
{
|
||||||
|
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
|
||||||
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
|
b[s] = (uint8_t)(n >> 24U);
|
||||||
|
b[s + 1] = (uint8_t)(n >> 16U);
|
||||||
|
b[s + 2] = (uint8_t)(n >> 8U);
|
||||||
|
b[s + 3] = (uint8_t)n;
|
||||||
|
#else
|
||||||
|
*reinterpret_cast<uint32_t *>(unsafeData + s) = Utils::hton(n);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Store an integer without advancing the index
|
||||||
|
*/
|
||||||
|
ZT_ALWAYS_INLINE void sI64(const int ii,const uint64_t n) noexcept
|
||||||
|
{
|
||||||
|
const unsigned int s = ((unsigned int)ii) & ZT_BUF_MEM_MASK;
|
||||||
|
#ifdef ZT_NO_UNALIGNED_ACCESS
|
||||||
|
b[s] = (uint8_t)(n >> 56U);
|
||||||
|
b[s + 1] = (uint8_t)(n >> 48U);
|
||||||
|
b[s + 2] = (uint8_t)(n >> 40U);
|
||||||
|
b[s + 3] = (uint8_t)(n >> 32U);
|
||||||
|
b[s + 4] = (uint8_t)(n >> 24U);
|
||||||
|
b[s + 5] = (uint8_t)(n >> 16U);
|
||||||
|
b[s + 6] = (uint8_t)(n >> 8U);
|
||||||
|
b[s + 7] = (uint8_t)n;
|
||||||
|
#else
|
||||||
|
*reinterpret_cast<uint64_t *>(unsafeData + s) = Utils::hton(n);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -547,7 +682,7 @@ public:
|
||||||
* @return Reference to 'b' cast to type T
|
* @return Reference to 'b' cast to type T
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ZT_ALWAYS_INLINE T &as(const unsigned int i = 0) noexcept { return *reinterpret_cast<T *>(b + i); }
|
ZT_ALWAYS_INLINE T &as(const unsigned int i = 0) noexcept { return *reinterpret_cast<T *>(unsafeData + i); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cast data in 'b' to a (usually packed) structure type (const)
|
* Cast data in 'b' to a (usually packed) structure type (const)
|
||||||
|
@ -561,14 +696,14 @@ public:
|
||||||
* @return Reference to 'b' cast to type T
|
* @return Reference to 'b' cast to type T
|
||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ZT_ALWAYS_INLINE const T &as(const unsigned int i = 0) const noexcept { return *reinterpret_cast<const T *>(b + i); }
|
ZT_ALWAYS_INLINE const T &as(const unsigned int i = 0) const noexcept { return *reinterpret_cast<const T *>(unsafeData + i); }
|
||||||
|
|
||||||
ZT_ALWAYS_INLINE bool operator==(const Buf &b2) const noexcept { return (memcmp(b,b2.b,ZT_BUF_MEM_SIZE) == 0); }
|
ZT_ALWAYS_INLINE bool operator==(const Buf &b2) const noexcept { return (memcmp(unsafeData,b2.unsafeData,ZT_BUF_MEM_SIZE) == 0); }
|
||||||
ZT_ALWAYS_INLINE bool operator!=(const Buf &b2) const noexcept { return (memcmp(b,b2.b,ZT_BUF_MEM_SIZE) != 0); }
|
ZT_ALWAYS_INLINE bool operator!=(const Buf &b2) const noexcept { return (memcmp(unsafeData,b2.unsafeData,ZT_BUF_MEM_SIZE) != 0); }
|
||||||
ZT_ALWAYS_INLINE bool operator<(const Buf &b2) const noexcept { return (memcmp(b,b2.b,ZT_BUF_MEM_SIZE) < 0); }
|
ZT_ALWAYS_INLINE bool operator<(const Buf &b2) const noexcept { return (memcmp(unsafeData,b2.unsafeData,ZT_BUF_MEM_SIZE) < 0); }
|
||||||
ZT_ALWAYS_INLINE bool operator<=(const Buf &b2) const noexcept { return (memcmp(b,b2.b,ZT_BUF_MEM_SIZE) <= 0); }
|
ZT_ALWAYS_INLINE bool operator<=(const Buf &b2) const noexcept { return (memcmp(unsafeData,b2.unsafeData,ZT_BUF_MEM_SIZE) <= 0); }
|
||||||
ZT_ALWAYS_INLINE bool operator>(const Buf &b2) const noexcept { return (memcmp(b,b2.b,ZT_BUF_MEM_SIZE) > 0); }
|
ZT_ALWAYS_INLINE bool operator>(const Buf &b2) const noexcept { return (memcmp(unsafeData,b2.unsafeData,ZT_BUF_MEM_SIZE) > 0); }
|
||||||
ZT_ALWAYS_INLINE bool operator>=(const Buf &b2) const noexcept { return (memcmp(b,b2.b,ZT_BUF_MEM_SIZE) >= 0); }
|
ZT_ALWAYS_INLINE bool operator>=(const Buf &b2) const noexcept { return (memcmp(unsafeData,b2.unsafeData,ZT_BUF_MEM_SIZE) >= 0); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Raw data held in buffer
|
* Raw data held in buffer
|
||||||
|
@ -577,7 +712,7 @@ public:
|
||||||
* They exist to allow reads and writes of integer types to silently overflow if a
|
* They exist to allow reads and writes of integer types to silently overflow if a
|
||||||
* read or write is performed at the end of the buffer.
|
* read or write is performed at the end of the buffer.
|
||||||
*/
|
*/
|
||||||
uint8_t b[ZT_BUF_MEM_SIZE + 8];
|
uint8_t unsafeData[ZT_BUF_MEM_SIZE + 8];
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Next item in free buffer pool linked list if Buf is placed in pool, undefined and unused otherwise
|
// Next item in free buffer pool linked list if Buf is placed in pool, undefined and unused otherwise
|
||||||
|
|
|
@ -16,6 +16,7 @@ set(core_headers
|
||||||
ECC384.hpp
|
ECC384.hpp
|
||||||
Expect.hpp
|
Expect.hpp
|
||||||
FCV.hpp
|
FCV.hpp
|
||||||
|
H.hpp
|
||||||
Hashtable.hpp
|
Hashtable.hpp
|
||||||
Identity.hpp
|
Identity.hpp
|
||||||
InetAddress.hpp
|
InetAddress.hpp
|
||||||
|
|
|
@ -66,16 +66,6 @@
|
||||||
*/
|
*/
|
||||||
#define ZT_MAX_NETWORK_CONFIG_BYTES 131072
|
#define ZT_MAX_NETWORK_CONFIG_BYTES 131072
|
||||||
|
|
||||||
/**
|
|
||||||
* Size of RX queue in packets
|
|
||||||
*/
|
|
||||||
#define ZT_RX_QUEUE_SIZE 32
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Size of TX queue in packets
|
|
||||||
*/
|
|
||||||
#define ZT_TX_QUEUE_SIZE 32
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Length of peer shared secrets (256-bit, do not change)
|
* Length of peer shared secrets (256-bit, do not change)
|
||||||
*/
|
*/
|
||||||
|
@ -109,16 +99,6 @@
|
||||||
*/
|
*/
|
||||||
#define ZT_WHOIS_RETRY_DELAY 500
|
#define ZT_WHOIS_RETRY_DELAY 500
|
||||||
|
|
||||||
/**
|
|
||||||
* Transmit queue entry timeout
|
|
||||||
*/
|
|
||||||
#define ZT_TRANSMIT_QUEUE_TIMEOUT 5000
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Receive queue entry timeout
|
|
||||||
*/
|
|
||||||
#define ZT_RECEIVE_QUEUE_TIMEOUT 5000
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum number of ZT hops allowed (this is not IP hops/TTL)
|
* Maximum number of ZT hops allowed (this is not IP hops/TTL)
|
||||||
*
|
*
|
||||||
|
@ -156,6 +136,15 @@
|
||||||
*/
|
*/
|
||||||
#define ZT_PEER_ACTIVITY_TIMEOUT (ZT_PEER_PING_PERIOD + 5000)
|
#define ZT_PEER_ACTIVITY_TIMEOUT (ZT_PEER_PING_PERIOD + 5000)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global timeout for peers in milliseconds
|
||||||
|
*
|
||||||
|
* This is global as in "entire world," and this value is 30 days. In this
|
||||||
|
* code the global timeout is used to determine when to ignore cached
|
||||||
|
* peers and their identity<>address mappings.
|
||||||
|
*/
|
||||||
|
#define ZT_PEER_GLOBAL_TIMEOUT 2592000000LL
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maximum interval between sort/prioritize of paths for a peer
|
* Maximum interval between sort/prioritize of paths for a peer
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -20,13 +20,12 @@ bool Endpoint::operator==(const Endpoint &ep) const
|
||||||
if (_t == ep._t) {
|
if (_t == ep._t) {
|
||||||
switch(_t) {
|
switch(_t) {
|
||||||
default: return true;
|
default: return true;
|
||||||
case INETADDR_V4:
|
case TYPE_ZEROTIER: return ((_v.zt.a == ep._v.zt.a)&&(memcmp(_v.zt.idh,ep._v.zt.idh,sizeof(_v.zt.idh)) == 0));
|
||||||
case INETADDR_V6: return (inetAddr() == ep.inetAddr());
|
case TYPE_DNSNAME: return ((_v.dns.port == ep._v.dns.port)&&(strcmp(_v.dns.name,ep._v.dns.name) == 0));
|
||||||
case DNSNAME: return ((_v.dns.port == ep._v.dns.port)&&(strcmp(_v.dns.name,ep._v.dns.name) == 0));
|
case TYPE_URL: return (strcmp(_v.url,ep._v.url) == 0);
|
||||||
case ZEROTIER: return ((_v.zt.a == ep._v.zt.a)&&(memcmp(_v.zt.idh,ep._v.zt.idh,sizeof(_v.zt.idh)) == 0));
|
case TYPE_ETHERNET: return (_v.eth == ep._v.eth);
|
||||||
case URL: return (strcmp(_v.url,ep._v.url) == 0);
|
case TYPE_INETADDR_V4:
|
||||||
case ETHERNET: return (_v.eth == ep._v.eth);
|
case TYPE_INETADDR_V6: return (inetAddr() == ep.inetAddr());
|
||||||
case WEBRTC: return ((_v.webrtc.offerLen == ep._v.webrtc.offerLen)&&(memcmp(_v.webrtc.offer,ep._v.webrtc.offer,_v.webrtc.offerLen) == 0));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -39,20 +38,14 @@ bool Endpoint::operator<(const Endpoint &ep) const
|
||||||
} else if (_t == ep._t) {
|
} else if (_t == ep._t) {
|
||||||
int ncmp;
|
int ncmp;
|
||||||
switch(_t) {
|
switch(_t) {
|
||||||
case INETADDR_V4:
|
case TYPE_ZEROTIER: return (_v.zt.a < ep._v.zt.a) ? true : ((_v.zt.a == ep._v.zt.a)&&(memcmp(_v.zt.idh,ep._v.zt.idh,sizeof(_v.zt.idh)) < 0));
|
||||||
case INETADDR_V6:
|
case TYPE_DNSNAME:
|
||||||
return (inetAddr() < ep.inetAddr());
|
|
||||||
case DNSNAME:
|
|
||||||
ncmp = strcmp(_v.dns.name,ep._v.dns.name);
|
ncmp = strcmp(_v.dns.name,ep._v.dns.name);
|
||||||
return ((ncmp < 0) ? true : (ncmp == 0)&&(_v.dns.port < ep._v.dns.port));
|
return ((ncmp < 0) ? true : (ncmp == 0)&&(_v.dns.port < ep._v.dns.port));
|
||||||
case ZEROTIER: return (_v.zt.a < ep._v.zt.a) ? true : ((_v.zt.a == ep._v.zt.a)&&(memcmp(_v.zt.idh,ep._v.zt.idh,sizeof(_v.zt.idh)) < 0));
|
case TYPE_URL: return (strcmp(_v.url,ep._v.url) < 0);
|
||||||
case URL: return (strcmp(_v.url,ep._v.url) < 0);
|
case TYPE_ETHERNET: return (_v.eth < ep._v.eth);
|
||||||
case ETHERNET: return (_v.eth < ep._v.eth);
|
case TYPE_INETADDR_V4:
|
||||||
case WEBRTC:
|
case TYPE_INETADDR_V6: return (inetAddr() < ep.inetAddr());
|
||||||
if (_v.webrtc.offerLen < ep._v.webrtc.offerLen)
|
|
||||||
return true;
|
|
||||||
else if (_v.webrtc.offerLen == ep._v.webrtc.offerLen)
|
|
||||||
return memcmp(_v.webrtc.offer,ep._v.webrtc.offer,_v.webrtc.offerLen) < 0;
|
|
||||||
default: return false;
|
default: return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -67,10 +60,15 @@ int Endpoint::marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept
|
||||||
Utils::storeBigEndian(data + 3,(int16_t)_l[1]);
|
Utils::storeBigEndian(data + 3,(int16_t)_l[1]);
|
||||||
Utils::storeBigEndian(data + 5,(int16_t)_l[2]);
|
Utils::storeBigEndian(data + 5,(int16_t)_l[2]);
|
||||||
switch(_t) {
|
switch(_t) {
|
||||||
case INETADDR_V4:
|
case TYPE_ZEROTIER:
|
||||||
case INETADDR_V6:
|
data[7] = (uint8_t)(_v.zt.a >> 32U);
|
||||||
return 7 + reinterpret_cast<const InetAddress *>(&_v.sa)->marshal(data+1);
|
data[8] = (uint8_t)(_v.zt.a >> 24U);
|
||||||
case DNSNAME:
|
data[9] = (uint8_t)(_v.zt.a >> 16U);
|
||||||
|
data[10] = (uint8_t)(_v.zt.a >> 8U);
|
||||||
|
data[11] = (uint8_t)_v.zt.a;
|
||||||
|
memcpy(data + 12,_v.zt.idh,ZT_IDENTITY_HASH_SIZE);
|
||||||
|
return ZT_IDENTITY_HASH_SIZE + 12;
|
||||||
|
case TYPE_DNSNAME:
|
||||||
p = 7;
|
p = 7;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if ((data[p] = (uint8_t)_v.dns.name[p-1]) == 0)
|
if ((data[p] = (uint8_t)_v.dns.name[p-1]) == 0)
|
||||||
|
@ -82,15 +80,7 @@ int Endpoint::marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept
|
||||||
data[p++] = (uint8_t)(_v.dns.port >> 8U);
|
data[p++] = (uint8_t)(_v.dns.port >> 8U);
|
||||||
data[p++] = (uint8_t)_v.dns.port;
|
data[p++] = (uint8_t)_v.dns.port;
|
||||||
return p;
|
return p;
|
||||||
case ZEROTIER:
|
case TYPE_URL:
|
||||||
data[7] = (uint8_t)(_v.zt.a >> 32U);
|
|
||||||
data[8] = (uint8_t)(_v.zt.a >> 24U);
|
|
||||||
data[9] = (uint8_t)(_v.zt.a >> 16U);
|
|
||||||
data[10] = (uint8_t)(_v.zt.a >> 8U);
|
|
||||||
data[11] = (uint8_t)_v.zt.a;
|
|
||||||
memcpy(data + 12,_v.zt.idh,ZT_IDENTITY_HASH_SIZE);
|
|
||||||
return ZT_IDENTITY_HASH_SIZE + 12;
|
|
||||||
case URL:
|
|
||||||
p = 7;
|
p = 7;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if ((data[p] = (uint8_t)_v.url[p-1]) == 0)
|
if ((data[p] = (uint8_t)_v.url[p-1]) == 0)
|
||||||
|
@ -100,7 +90,7 @@ int Endpoint::marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
case ETHERNET:
|
case TYPE_ETHERNET:
|
||||||
data[7] = (uint8_t)(_v.eth >> 40U);
|
data[7] = (uint8_t)(_v.eth >> 40U);
|
||||||
data[8] = (uint8_t)(_v.eth >> 32U);
|
data[8] = (uint8_t)(_v.eth >> 32U);
|
||||||
data[9] = (uint8_t)(_v.eth >> 24U);
|
data[9] = (uint8_t)(_v.eth >> 24U);
|
||||||
|
@ -108,12 +98,14 @@ int Endpoint::marshal(uint8_t data[ZT_ENDPOINT_MARSHAL_SIZE_MAX]) const noexcept
|
||||||
data[11] = (uint8_t)(_v.eth >> 8U);
|
data[11] = (uint8_t)(_v.eth >> 8U);
|
||||||
data[12] = (uint8_t)_v.eth;
|
data[12] = (uint8_t)_v.eth;
|
||||||
return 13;
|
return 13;
|
||||||
case WEBRTC:
|
case TYPE_INETADDR_V4:
|
||||||
Utils::storeBigEndian(data + 7,(uint16_t)_v.webrtc.offerLen);
|
case TYPE_INETADDR_V6:
|
||||||
memcpy(data + 9,_v.webrtc.offer,_v.webrtc.offerLen);
|
p = asInetAddress(_v.sa).marshal(data + 7);
|
||||||
return 9 + _v.webrtc.offerLen;
|
if (p < 0)
|
||||||
|
return p;
|
||||||
|
return 7 + p;
|
||||||
default:
|
default:
|
||||||
data[0] = (uint8_t)NIL;
|
data[0] = (uint8_t)TYPE_NIL;
|
||||||
return 7;
|
return 7;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -128,12 +120,19 @@ int Endpoint::unmarshal(const uint8_t *restrict data,const int len) noexcept
|
||||||
_l[1] = Utils::loadBigEndian<int16_t>(data + 3);
|
_l[1] = Utils::loadBigEndian<int16_t>(data + 3);
|
||||||
_l[2] = Utils::loadBigEndian<int16_t>(data + 5);
|
_l[2] = Utils::loadBigEndian<int16_t>(data + 5);
|
||||||
switch(_t) {
|
switch(_t) {
|
||||||
case NIL:
|
case TYPE_NIL:
|
||||||
return 7;
|
return 7;
|
||||||
case INETADDR_V4:
|
case TYPE_ZEROTIER:
|
||||||
case INETADDR_V6:
|
if (len < (12 + ZT_IDENTITY_HASH_SIZE))
|
||||||
return 7 + reinterpret_cast<InetAddress *>(&_v.sa)->unmarshal(data+7,len-7);
|
return -1;
|
||||||
case DNSNAME:
|
_v.zt.a = ((uint64_t)data[7]) << 32U;
|
||||||
|
_v.zt.a |= ((uint64_t)data[8]) << 24U;
|
||||||
|
_v.zt.a |= ((uint64_t)data[9]) << 16U;
|
||||||
|
_v.zt.a |= ((uint64_t)data[10]) << 8U;
|
||||||
|
_v.zt.a |= (uint64_t)data[11];
|
||||||
|
memcpy(_v.zt.idh,data + 12,ZT_IDENTITY_HASH_SIZE);
|
||||||
|
return 60;
|
||||||
|
case TYPE_DNSNAME:
|
||||||
if (len < 10)
|
if (len < 10)
|
||||||
return -1;
|
return -1;
|
||||||
p = 7;
|
p = 7;
|
||||||
|
@ -149,17 +148,7 @@ int Endpoint::unmarshal(const uint8_t *restrict data,const int len) noexcept
|
||||||
_v.dns.port = (uint16_t)(((unsigned int)data[p++]) << 8U);
|
_v.dns.port = (uint16_t)(((unsigned int)data[p++]) << 8U);
|
||||||
_v.dns.port |= (uint16_t)data[p++];
|
_v.dns.port |= (uint16_t)data[p++];
|
||||||
return p;
|
return p;
|
||||||
case ZEROTIER:
|
case TYPE_URL:
|
||||||
if (len < 60)
|
|
||||||
return -1;
|
|
||||||
_v.zt.a = ((uint64_t)data[7]) << 32U;
|
|
||||||
_v.zt.a |= ((uint64_t)data[8]) << 24U;
|
|
||||||
_v.zt.a |= ((uint64_t)data[9]) << 16U;
|
|
||||||
_v.zt.a |= ((uint64_t)data[10]) << 8U;
|
|
||||||
_v.zt.a |= (uint64_t)data[11];
|
|
||||||
memcpy(_v.zt.idh,data + 12,48);
|
|
||||||
return 60;
|
|
||||||
case URL:
|
|
||||||
if (len < 8)
|
if (len < 8)
|
||||||
return -1;
|
return -1;
|
||||||
p = 7;
|
p = 7;
|
||||||
|
@ -173,7 +162,7 @@ int Endpoint::unmarshal(const uint8_t *restrict data,const int len) noexcept
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return p;
|
return p;
|
||||||
case ETHERNET:
|
case TYPE_ETHERNET:
|
||||||
if (len < 13)
|
if (len < 13)
|
||||||
return -1;
|
return -1;
|
||||||
_v.eth = ((uint64_t)data[7]) << 40U;
|
_v.eth = ((uint64_t)data[7]) << 40U;
|
||||||
|
@ -183,20 +172,19 @@ int Endpoint::unmarshal(const uint8_t *restrict data,const int len) noexcept
|
||||||
_v.eth |= ((uint64_t)data[11]) << 8U;
|
_v.eth |= ((uint64_t)data[11]) << 8U;
|
||||||
_v.eth |= (uint64_t)data[12];
|
_v.eth |= (uint64_t)data[12];
|
||||||
return 13;
|
return 13;
|
||||||
case WEBRTC:
|
case TYPE_INETADDR_V4:
|
||||||
|
case TYPE_INETADDR_V6:
|
||||||
|
p = asInetAddress(_v.sa).unmarshal(data + 7,len - 7);
|
||||||
|
if (p <= 0)
|
||||||
|
return -1;
|
||||||
|
return 7 + p;
|
||||||
|
default:
|
||||||
|
// Unrecognized endpoint types not yet specified must start with a 16-bit
|
||||||
|
// length so that older versions of ZeroTier can skip them.
|
||||||
if (len < 9)
|
if (len < 9)
|
||||||
return -1;
|
return -1;
|
||||||
_v.webrtc.offerLen = Utils::loadBigEndian<uint16_t>(data + 7);
|
p = 9 + (int)Utils::loadBigEndian<uint16_t>(data + 7);
|
||||||
if ((len < (9 + _v.webrtc.offerLen))||(_v.webrtc.offerLen > ZT_ENDPOINT_MAX_NAME_SIZE))
|
return (p > len) ? -1 : p;
|
||||||
return -1;
|
|
||||||
memcpy(_v.webrtc.offer,data + 9,_v.webrtc.offerLen);
|
|
||||||
return 9 + _v.webrtc.offerLen;
|
|
||||||
default:
|
|
||||||
// Unrecognized endpoint types not yet specified must start with a byte
|
|
||||||
// length size so that older versions of ZeroTier can skip them.
|
|
||||||
if (len < 8)
|
|
||||||
return -1;
|
|
||||||
return 8 + (int)data[7];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,99 +39,96 @@ namespace ZeroTier {
|
||||||
class Endpoint : public TriviallyCopyable
|
class Endpoint : public TriviallyCopyable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* Endpoint type
|
||||||
|
*/
|
||||||
enum Type
|
enum Type
|
||||||
{
|
{
|
||||||
NIL = 0, // NIL value
|
TYPE_NIL = 0, // NIL value
|
||||||
INETADDR_V4 = 1, // IPv4
|
TYPE_ZEROTIER = 1, // ZeroTier Address (for relaying and meshy behavior)
|
||||||
INETADDR_V6 = 2, // IPv6
|
TYPE_DNSNAME = 2, // DNS name and port that resolves to InetAddress
|
||||||
DNSNAME = 3, // DNS name and port that resolves to InetAddress
|
TYPE_URL = 3, // URL for HTTP or Web Sockets transport
|
||||||
ZEROTIER = 4, // ZeroTier Address (for relaying and meshy behavior)
|
TYPE_INETADDR_V4 = 4, // IPv4
|
||||||
URL = 5, // URL for http/https/ws/etc. (not implemented yet)
|
TYPE_ETHERNET = 5, // 48-bit LAN-local Ethernet address
|
||||||
ETHERNET = 6, // 48-bit LAN-local Ethernet address
|
TYPE_INETADDR_V6 = 6 // IPv6
|
||||||
WEBRTC = 7, // WebRTC data channels
|
|
||||||
UNRECOGNIZED = 255 // Unrecognized endpoint type encountered in stream
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ZT_ALWAYS_INLINE Endpoint() noexcept { memoryZero(this); }
|
ZT_ALWAYS_INLINE Endpoint() noexcept { memoryZero(this); }
|
||||||
|
|
||||||
explicit ZT_ALWAYS_INLINE Endpoint(const InetAddress &sa) { *this = sa; }
|
ZT_ALWAYS_INLINE Endpoint(const InetAddress &sa)
|
||||||
|
{
|
||||||
|
switch (sa.ss_family) {
|
||||||
|
case AF_INET:
|
||||||
|
_t = TYPE_INETADDR_V4;
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
_t = TYPE_INETADDR_V6;
|
||||||
|
default:
|
||||||
|
_t = TYPE_NIL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
asInetAddress(_v.sa) = sa;
|
||||||
|
}
|
||||||
|
|
||||||
ZT_ALWAYS_INLINE Endpoint(const Address &zt,const uint8_t identityHash[ZT_IDENTITY_HASH_SIZE]) :
|
ZT_ALWAYS_INLINE Endpoint(const Address &zt,const uint8_t identityHash[ZT_IDENTITY_HASH_SIZE]) :
|
||||||
_t(ZEROTIER)
|
_t(TYPE_ZEROTIER)
|
||||||
{
|
{
|
||||||
_v.zt.a = zt.toInt();
|
_v.zt.a = zt.toInt();
|
||||||
memcpy(_v.zt.idh,identityHash,ZT_IDENTITY_HASH_SIZE);
|
memcpy(_v.zt.idh,identityHash,ZT_IDENTITY_HASH_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
ZT_ALWAYS_INLINE Endpoint(const char *name,const int port) :
|
ZT_ALWAYS_INLINE Endpoint(const char *name,const int port) :
|
||||||
_t(DNSNAME)
|
_t(TYPE_DNSNAME)
|
||||||
{
|
{
|
||||||
_v.dns.port = port;
|
_v.dns.port = port;
|
||||||
Utils::scopy(_v.dns.name,sizeof(_v.dns.name),name);
|
Utils::scopy(_v.dns.name,sizeof(_v.dns.name),name);
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit ZT_ALWAYS_INLINE Endpoint(const char *url) :
|
explicit ZT_ALWAYS_INLINE Endpoint(const char *url) :
|
||||||
_t(URL)
|
_t(TYPE_URL)
|
||||||
{ Utils::scopy(_v.url,sizeof(_v.url),url); }
|
{ Utils::scopy(_v.url,sizeof(_v.url),url); }
|
||||||
|
|
||||||
ZT_ALWAYS_INLINE Endpoint &operator=(const InetAddress &sa)
|
|
||||||
{
|
|
||||||
switch(sa.ss_family) {
|
|
||||||
case AF_INET:
|
|
||||||
_t = INETADDR_V4;
|
|
||||||
break;
|
|
||||||
case AF_INET6:
|
|
||||||
_t = INETADDR_V6;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
_t = NIL;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
_v.sa = sa;
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return InetAddress or NIL if not of this type
|
* @return InetAddress or NIL if not of this type
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE const InetAddress &inetAddr() const noexcept { return ((_t == INETADDR_V4)||(_t == INETADDR_V6)) ? *reinterpret_cast<const InetAddress *>(&_v.sa) : InetAddress::NIL; }
|
ZT_ALWAYS_INLINE const InetAddress &inetAddr() const noexcept { return ((_t == TYPE_INETADDR_V4)||(_t == TYPE_INETADDR_V6)) ? asInetAddress(_v.sa) : InetAddress::NIL; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return DNS name or empty string if not of this type
|
* @return DNS name or empty string if not of this type
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE const char *dnsName() const noexcept { return (_t == DNSNAME) ? _v.dns.name : ""; }
|
ZT_ALWAYS_INLINE const char *dnsName() const noexcept { return (_t == TYPE_DNSNAME) ? _v.dns.name : ""; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Port associated with DNS name or -1 if not of this type
|
* @return Port associated with DNS name or -1 if not of this type
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE int dnsPort() const noexcept { return (_t == DNSNAME) ? _v.dns.port : -1; }
|
ZT_ALWAYS_INLINE int dnsPort() const noexcept { return (_t == TYPE_DNSNAME) ? _v.dns.port : -1; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return ZeroTier address or NIL if not of this type
|
* @return ZeroTier address or NIL if not of this type
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE Address ztAddress() const noexcept { return Address((_t == ZEROTIER) ? _v.zt.a : (uint64_t)0); }
|
ZT_ALWAYS_INLINE Address ztAddress() const noexcept { return Address((_t == TYPE_ZEROTIER) ? _v.zt.a : (uint64_t)0); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return 384-bit hash of identity keys or NULL if not of this type
|
* @return 384-bit hash of identity keys or NULL if not of this type
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE const uint8_t *ztIdentityHash() const noexcept { return (_t == ZEROTIER) ? _v.zt.idh : nullptr; }
|
ZT_ALWAYS_INLINE const uint8_t *ztIdentityHash() const noexcept { return (_t == TYPE_ZEROTIER) ? _v.zt.idh : nullptr; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return URL or empty string if not of this type
|
* @return URL or empty string if not of this type
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE const char *url() const noexcept { return (_t == URL) ? _v.url : ""; }
|
ZT_ALWAYS_INLINE const char *url() const noexcept { return (_t == TYPE_URL) ? _v.url : ""; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Ethernet address or NIL if not of this type
|
* @return Ethernet address or NIL if not of this type
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE MAC ethernet() const noexcept { return (_t == ETHERNET) ? MAC(_v.eth) : MAC(); }
|
ZT_ALWAYS_INLINE MAC ethernet() const noexcept { return (_t == TYPE_ETHERNET) ? MAC(_v.eth) : MAC(); }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Endpoint type or NIL if unset/empty
|
* @return Endpoint type or NIL if unset/empty
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE Type type() const noexcept { return _t; }
|
ZT_ALWAYS_INLINE Type type() const noexcept { return _t; }
|
||||||
|
|
||||||
explicit ZT_ALWAYS_INLINE operator bool() const noexcept { return _t != NIL; }
|
explicit ZT_ALWAYS_INLINE operator bool() const noexcept { return _t != TYPE_NIL; }
|
||||||
|
|
||||||
bool operator==(const Endpoint &ep) const;
|
bool operator==(const Endpoint &ep) const;
|
||||||
ZT_ALWAYS_INLINE bool operator!=(const Endpoint &ep) const { return (!(*this == ep)); }
|
ZT_ALWAYS_INLINE bool operator!=(const Endpoint &ep) const { return (!(*this == ep)); }
|
||||||
|
@ -153,10 +150,6 @@ private:
|
||||||
uint16_t port;
|
uint16_t port;
|
||||||
char name[ZT_ENDPOINT_MAX_NAME_SIZE];
|
char name[ZT_ENDPOINT_MAX_NAME_SIZE];
|
||||||
} dns;
|
} dns;
|
||||||
struct {
|
|
||||||
uint16_t offerLen;
|
|
||||||
uint8_t offer[ZT_ENDPOINT_MAX_NAME_SIZE];
|
|
||||||
} webrtc;
|
|
||||||
struct {
|
struct {
|
||||||
uint64_t a;
|
uint64_t a;
|
||||||
uint8_t idh[ZT_IDENTITY_HASH_SIZE];
|
uint8_t idh[ZT_IDENTITY_HASH_SIZE];
|
||||||
|
|
86
node/H.hpp
Normal file
86
node/H.hpp
Normal file
|
@ -0,0 +1,86 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c)2013-2020 ZeroTier, Inc.
|
||||||
|
*
|
||||||
|
* Use of this software is governed by the Business Source License included
|
||||||
|
* in the LICENSE.TXT file in the project's root directory.
|
||||||
|
*
|
||||||
|
* Change Date: 2024-01-01
|
||||||
|
*
|
||||||
|
* On the date above, in accordance with the Business Source License, use
|
||||||
|
* of this software will be governed by version 2.0 of the Apache License.
|
||||||
|
*/
|
||||||
|
/****/
|
||||||
|
|
||||||
|
#ifndef ZT_H_HPP
|
||||||
|
#define ZT_H_HPP
|
||||||
|
|
||||||
|
#include "Constants.hpp"
|
||||||
|
#include "TriviallyCopyable.hpp"
|
||||||
|
|
||||||
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Container for cryptographic hashes
|
||||||
|
*
|
||||||
|
* The size of the hash used with this container must be a multiple of 64 bits.
|
||||||
|
* Currently it's used as H<384> and H<512>.
|
||||||
|
*
|
||||||
|
* Warning: the [] operator is not bounds checked.
|
||||||
|
*
|
||||||
|
* @tparam BITS Bits in hash, must be a multiple of 64
|
||||||
|
*/
|
||||||
|
template<unsigned int BITS>
|
||||||
|
class H : public TriviallyCopyable
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ZT_ALWAYS_INLINE H() noexcept {}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param h Hash value of size BITS / 8
|
||||||
|
*/
|
||||||
|
explicit ZT_ALWAYS_INLINE H(const void *h) noexcept { memcpy(_h,h,BITS / 8); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param h Hash value of size BITS / 8
|
||||||
|
*/
|
||||||
|
ZT_ALWAYS_INLINE void set(const void *h) noexcept { memcpy(_h,h,BITS / 8); }
|
||||||
|
|
||||||
|
ZT_ALWAYS_INLINE void zero() noexcept
|
||||||
|
{
|
||||||
|
for(int i=0;i<(BITS / sizeof(unsigned long));++i)
|
||||||
|
_h[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZT_ALWAYS_INLINE uint8_t *data() noexcept { return reinterpret_cast<uint8_t *>(_h); }
|
||||||
|
ZT_ALWAYS_INLINE const uint8_t *data() const noexcept { return reinterpret_cast<const uint8_t *>(_h); }
|
||||||
|
|
||||||
|
ZT_ALWAYS_INLINE uint8_t operator[](const unsigned int i) const noexcept { return reinterpret_cast<const uint8_t *>(_h)[i]; }
|
||||||
|
ZT_ALWAYS_INLINE uint8_t &operator[](const unsigned int i) noexcept { return reinterpret_cast<uint8_t *>(_h)[i]; }
|
||||||
|
|
||||||
|
static constexpr unsigned int size() noexcept { return BITS / 8; }
|
||||||
|
|
||||||
|
ZT_ALWAYS_INLINE unsigned long hashCode() const noexcept { return _h[0]; }
|
||||||
|
|
||||||
|
ZT_ALWAYS_INLINE operator bool() const noexcept
|
||||||
|
{
|
||||||
|
for(int i=0;i<(BITS / sizeof(unsigned long));++i) {
|
||||||
|
if (_h[i] != 0)
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZT_ALWAYS_INLINE bool operator==(const H &h) const noexcept { return memcmp(_h,h._h,BITS / 8) == 0; }
|
||||||
|
ZT_ALWAYS_INLINE bool operator!=(const H &h) const noexcept { return memcmp(_h,h._h,BITS / 8) != 0; }
|
||||||
|
ZT_ALWAYS_INLINE bool operator<(const H &h) const noexcept { return memcmp(_h,h._h,BITS / 8) < 0; }
|
||||||
|
ZT_ALWAYS_INLINE bool operator>(const H &h) const noexcept { return memcmp(_h,h._h,BITS / 8) > 0; }
|
||||||
|
ZT_ALWAYS_INLINE bool operator<=(const H &h) const noexcept { return memcmp(_h,h._h,BITS / 8) <= 0; }
|
||||||
|
ZT_ALWAYS_INLINE bool operator>=(const H &h) const noexcept { return memcmp(_h,h._h,BITS / 8) >= 0; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned long _h[BITS / sizeof(unsigned long)];
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ZeroTier
|
||||||
|
|
||||||
|
#endif
|
|
@ -93,7 +93,6 @@ bool Identity::generate(const Type t)
|
||||||
|
|
||||||
_type = t;
|
_type = t;
|
||||||
_hasPrivate = true;
|
_hasPrivate = true;
|
||||||
_hash[0] = 0; // force hash recompute
|
|
||||||
|
|
||||||
switch(t) {
|
switch(t) {
|
||||||
case C25519: {
|
case C25519: {
|
||||||
|
@ -103,32 +102,28 @@ bool Identity::generate(const Type t)
|
||||||
_address.setTo(digest + 59); // last 5 bytes are address
|
_address.setTo(digest + 59); // last 5 bytes are address
|
||||||
} while (_address.isReserved());
|
} while (_address.isReserved());
|
||||||
delete[] genmem;
|
delete[] genmem;
|
||||||
|
_computeHash();
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
case P384: {
|
case P384: {
|
||||||
|
AES c;
|
||||||
do {
|
do {
|
||||||
C25519::generate(_pub.c25519,_priv.c25519);
|
C25519::generate(_pub.c25519,_priv.c25519);
|
||||||
ECC384GenerateKey(_pub.p384,_priv.p384);
|
ECC384GenerateKey(_pub.p384,_priv.p384);
|
||||||
|
|
||||||
// This is just an intentionally complex hash function for use with a simple hashcash
|
|
||||||
// design to slow down identity generation as a defense in depth against brute force
|
|
||||||
// collision searches. V0 used a somewhat more overkill memory intensive design that's
|
|
||||||
// not really necessary and makes verifications too slow, so V1 uses this instead.
|
|
||||||
|
|
||||||
SHA384(digest,&_pub,sizeof(_pub));
|
SHA384(digest,&_pub,sizeof(_pub));
|
||||||
AES c(digest);
|
c.init(digest);
|
||||||
SHA384(digest,digest,48);
|
|
||||||
std::sort(digest,digest + 48);
|
|
||||||
c.encrypt(digest,digest);
|
c.encrypt(digest,digest);
|
||||||
c.encrypt(digest + 16,digest + 16);
|
c.encrypt(digest + 16,digest + 16);
|
||||||
c.encrypt(digest + 32,digest + 32);
|
c.encrypt(digest + 32,digest + 32);
|
||||||
SHA384(digest,digest,48);
|
|
||||||
|
|
||||||
if (digest[47] != 0)
|
if (digest[47] != 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
_address.setTo(digest);
|
_address.setTo(digest);
|
||||||
} while (_address.isReserved());
|
} while (_address.isReserved());
|
||||||
|
|
||||||
|
_hash.set(digest); // P384 uses the same hash for hash() and address generation
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -143,6 +138,7 @@ bool Identity::locallyValidate() const
|
||||||
if ((_address.isReserved())||(!_address))
|
if ((_address.isReserved())||(!_address))
|
||||||
return false;
|
return false;
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
|
|
||||||
case C25519:
|
case C25519:
|
||||||
try {
|
try {
|
||||||
uint8_t digest[64];
|
uint8_t digest[64];
|
||||||
|
@ -153,51 +149,30 @@ bool Identity::locallyValidate() const
|
||||||
} catch ( ... ) {}
|
} catch ( ... ) {}
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case P384: {
|
|
||||||
const uint8_t *hash = this->hash();
|
|
||||||
return ((hash[47] == 0)&&(Address(hash) == _address));
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const uint8_t *Identity::hash() const
|
|
||||||
{
|
|
||||||
uint8_t *const hash = const_cast<uint8_t *>(reinterpret_cast<const uint8_t *>(_hash));
|
|
||||||
switch(_type) {
|
|
||||||
default:
|
|
||||||
memset(hash,0,48);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case C25519:
|
|
||||||
if (_hash[0] == 0)
|
|
||||||
SHA384(hash,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case P384:
|
case P384:
|
||||||
if (_hash[0] == 0) {
|
return ((_hash[47] == 0)&&(Address(_hash.data()) == _address));
|
||||||
SHA384(hash,&_pub,sizeof(_pub));
|
|
||||||
AES c(hash);
|
|
||||||
std::sort(hash,hash + 48);
|
|
||||||
c.encrypt(hash,hash);
|
|
||||||
c.encrypt(hash + 16,hash + 16);
|
|
||||||
c.encrypt(hash + 32,hash + 32);
|
|
||||||
SHA384(hash,hash,48);
|
|
||||||
}
|
}
|
||||||
break;
|
return false;
|
||||||
}
|
|
||||||
return hash;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Identity::hashWithPrivate(uint8_t h[48]) const
|
void Identity::hashWithPrivate(uint8_t h[48]) const
|
||||||
{
|
{
|
||||||
|
if (_hasPrivate) {
|
||||||
switch (_type) {
|
switch (_type) {
|
||||||
case C25519: SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN); break;
|
|
||||||
case P384: SHA384(h,&_pub,sizeof(_pub),&_priv,sizeof(_priv)); break;
|
case C25519:
|
||||||
default: memset(h,0,48);
|
SHA384(h,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case P384:
|
||||||
|
SHA384(h,&_pub,sizeof(_pub),&_priv,sizeof(_priv));
|
||||||
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memset(h,0,48);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int Identity::sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const
|
unsigned int Identity::sign(const void *data,unsigned int len,void *sig,unsigned int siglen) const
|
||||||
|
@ -213,9 +188,11 @@ unsigned int Identity::sign(const void *data,unsigned int len,void *sig,unsigned
|
||||||
|
|
||||||
case P384:
|
case P384:
|
||||||
if (siglen >= ZT_ECC384_SIGNATURE_SIZE) {
|
if (siglen >= ZT_ECC384_SIGNATURE_SIZE) {
|
||||||
// When signing with P-384 we also include the C25519 public key in the hash.
|
// For P384 we sign SHA384(data | public keys) for added defense against any attack
|
||||||
|
// that attempted to decouple the two keys in some way. Otherwise this has no impact
|
||||||
|
// on the security of the signature (unless SHA384 had some serious flaw).
|
||||||
uint8_t h[48];
|
uint8_t h[48];
|
||||||
SHA384(h,data,len,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
|
SHA384(h,data,len,&_pub,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
|
||||||
ECC384ECDSASign(_priv.p384,h,(uint8_t *)sig);
|
ECC384ECDSASign(_priv.p384,h,(uint8_t *)sig);
|
||||||
return ZT_ECC384_SIGNATURE_SIZE;
|
return ZT_ECC384_SIGNATURE_SIZE;
|
||||||
}
|
}
|
||||||
|
@ -235,7 +212,7 @@ bool Identity::verify(const void *data,unsigned int len,const void *sig,unsigned
|
||||||
case P384:
|
case P384:
|
||||||
if (siglen == ZT_ECC384_SIGNATURE_SIZE) {
|
if (siglen == ZT_ECC384_SIGNATURE_SIZE) {
|
||||||
uint8_t h[48];
|
uint8_t h[48];
|
||||||
SHA384(h,data,len,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
|
SHA384(h,data,len,&_pub,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
|
||||||
return ECC384ECDSAVerify(_pub.p384,h,(const uint8_t *)sig);
|
return ECC384ECDSAVerify(_pub.p384,h,(const uint8_t *)sig);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -263,6 +240,11 @@ bool Identity::agree(const Identity &id,uint8_t key[ZT_PEER_SECRET_KEY_LENGTH])
|
||||||
} else if (_type == P384) {
|
} else if (_type == P384) {
|
||||||
|
|
||||||
if (id._type == P384) {
|
if (id._type == P384) {
|
||||||
|
// For another P384 identity we execute DH agreement with BOTH keys and then
|
||||||
|
// hash the results together. For those (cough FIPS cough) who only consider
|
||||||
|
// P384 to be kosher, the C25519 secret can be considered a "salt"
|
||||||
|
// or something. For those who don't trust P384 this means the privacy of
|
||||||
|
// your traffic is also protected by C25519.
|
||||||
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
|
C25519::agree(_priv.c25519,id._pub.c25519,rawkey);
|
||||||
ECC384ECDH(id._pub.p384,_priv.p384,rawkey + ZT_C25519_SHARED_KEY_LEN);
|
ECC384ECDH(id._pub.p384,_priv.p384,rawkey + ZT_C25519_SHARED_KEY_LEN);
|
||||||
SHA384(h,rawkey,ZT_C25519_SHARED_KEY_LEN + ZT_ECC384_SHARED_SECRET_SIZE);
|
SHA384(h,rawkey,ZT_C25519_SHARED_KEY_LEN + ZT_ECC384_SHARED_SECRET_SIZE);
|
||||||
|
@ -283,13 +265,14 @@ bool Identity::agree(const Identity &id,uint8_t key[ZT_PEER_SECRET_KEY_LENGTH])
|
||||||
|
|
||||||
char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const
|
char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_LENGTH]) const
|
||||||
{
|
{
|
||||||
|
char *p = buf;
|
||||||
|
_address.toString(p);
|
||||||
|
p += 10;
|
||||||
|
*(p++) = ':';
|
||||||
|
|
||||||
switch(_type) {
|
switch(_type) {
|
||||||
|
|
||||||
case C25519: {
|
case C25519: {
|
||||||
char *p = buf;
|
|
||||||
Utils::hex10(_address.toInt(),p);
|
|
||||||
p += 10;
|
|
||||||
*(p++) = ':';
|
|
||||||
*(p++) = '0';
|
*(p++) = '0';
|
||||||
*(p++) = ':';
|
*(p++) = ':';
|
||||||
Utils::hex(_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN,p);
|
Utils::hex(_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN,p);
|
||||||
|
@ -304,10 +287,6 @@ char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_
|
||||||
}
|
}
|
||||||
|
|
||||||
case P384: {
|
case P384: {
|
||||||
char *p = buf;
|
|
||||||
Utils::hex10(_address.toInt(),p);
|
|
||||||
p += 10;
|
|
||||||
*(p++) = ':';
|
|
||||||
*(p++) = '1';
|
*(p++) = '1';
|
||||||
*(p++) = ':';
|
*(p++) = ':';
|
||||||
int el = Utils::b32e((const uint8_t *)(&_pub),sizeof(_pub),p,(int)(ZT_IDENTITY_STRING_BUFFER_LENGTH - (uintptr_t)(p - buf)));
|
int el = Utils::b32e((const uint8_t *)(&_pub),sizeof(_pub),p,(int)(ZT_IDENTITY_STRING_BUFFER_LENGTH - (uintptr_t)(p - buf)));
|
||||||
|
@ -324,13 +303,14 @@ char *Identity::toString(bool includePrivate,char buf[ZT_IDENTITY_STRING_BUFFER_
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Identity::fromString(const char *str)
|
bool Identity::fromString(const char *str)
|
||||||
{
|
{
|
||||||
|
_hash.zero();
|
||||||
_hasPrivate = false;
|
_hasPrivate = false;
|
||||||
_hash[0] = 0; // force hash recompute
|
|
||||||
|
|
||||||
if (!str) {
|
if (!str) {
|
||||||
_address.zero();
|
_address.zero();
|
||||||
|
@ -421,6 +401,8 @@ bool Identity::fromString(const char *str)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_computeHash();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -430,50 +412,67 @@ int Identity::marshal(uint8_t data[ZT_IDENTITY_MARSHAL_SIZE_MAX],const bool incl
|
||||||
switch(_type) {
|
switch(_type) {
|
||||||
case C25519:
|
case C25519:
|
||||||
data[ZT_ADDRESS_LENGTH] = (uint8_t)C25519;
|
data[ZT_ADDRESS_LENGTH] = (uint8_t)C25519;
|
||||||
|
|
||||||
memcpy(data + ZT_ADDRESS_LENGTH + 1,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
|
memcpy(data + ZT_ADDRESS_LENGTH + 1,_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
|
||||||
|
|
||||||
if ((includePrivate)&&(_hasPrivate)) {
|
if ((includePrivate)&&(_hasPrivate)) {
|
||||||
data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = ZT_C25519_PRIVATE_KEY_LEN;
|
data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = ZT_C25519_PRIVATE_KEY_LEN;
|
||||||
memcpy(data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
|
memcpy(data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1,_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
|
||||||
return (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN);
|
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN;
|
||||||
}
|
} else {
|
||||||
data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = 0;
|
data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN] = 0;
|
||||||
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1;
|
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1;
|
||||||
|
}
|
||||||
|
|
||||||
case P384:
|
case P384:
|
||||||
data[ZT_ADDRESS_LENGTH] = (uint8_t)P384;
|
data[ZT_ADDRESS_LENGTH] = (uint8_t)P384;
|
||||||
memcpy(data + 1 + ZT_ADDRESS_LENGTH,&_pub,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
|
|
||||||
|
memcpy(data + ZT_ADDRESS_LENGTH + 1,&_pub,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
|
||||||
|
|
||||||
if ((includePrivate)&&(_hasPrivate)) {
|
if ((includePrivate)&&(_hasPrivate)) {
|
||||||
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
|
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
|
||||||
memcpy(data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,&_priv,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE);
|
memcpy(data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,&_priv,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE);
|
||||||
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
|
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
|
||||||
}
|
} else {
|
||||||
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = 0;
|
data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE] = 0;
|
||||||
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1;
|
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int Identity::unmarshal(const uint8_t *data,const int len) noexcept
|
int Identity::unmarshal(const uint8_t *data,const int len) noexcept
|
||||||
{
|
{
|
||||||
|
_hash.zero();
|
||||||
|
_hasPrivate = false;
|
||||||
|
|
||||||
if (len < (ZT_ADDRESS_LENGTH + 1))
|
if (len < (ZT_ADDRESS_LENGTH + 1))
|
||||||
return -1;
|
return -1;
|
||||||
_hash[0] = 0; // force hash recompute
|
|
||||||
unsigned int privlen;
|
unsigned int privlen;
|
||||||
switch((_type = (Type)data[ZT_ADDRESS_LENGTH])) {
|
switch((_type = (Type)data[ZT_ADDRESS_LENGTH])) {
|
||||||
|
|
||||||
case C25519:
|
case C25519:
|
||||||
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1))
|
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
memcpy(_pub.c25519,data + ZT_ADDRESS_LENGTH + 1,ZT_C25519_PUBLIC_KEY_LEN);
|
memcpy(_pub.c25519,data + ZT_ADDRESS_LENGTH + 1,ZT_C25519_PUBLIC_KEY_LEN);
|
||||||
|
|
||||||
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN];
|
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN];
|
||||||
if (privlen == ZT_C25519_PRIVATE_KEY_LEN) {
|
if (privlen == ZT_C25519_PRIVATE_KEY_LEN) {
|
||||||
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN))
|
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
_hasPrivate = true;
|
_hasPrivate = true;
|
||||||
memcpy(_priv.c25519,data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1,ZT_C25519_PRIVATE_KEY_LEN);
|
memcpy(_priv.c25519,data + ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1,ZT_C25519_PRIVATE_KEY_LEN);
|
||||||
|
|
||||||
|
_computeHash();
|
||||||
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN;
|
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1 + ZT_C25519_PRIVATE_KEY_LEN;
|
||||||
} else if (privlen == 0) {
|
} else if (privlen == 0) {
|
||||||
_hasPrivate = false;
|
_hasPrivate = false;
|
||||||
|
|
||||||
|
_computeHash();
|
||||||
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1;
|
return ZT_ADDRESS_LENGTH + 1 + ZT_C25519_PUBLIC_KEY_LEN + 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -481,26 +480,61 @@ int Identity::unmarshal(const uint8_t *data,const int len) noexcept
|
||||||
case P384:
|
case P384:
|
||||||
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1))
|
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
memcpy(&_pub,data + ZT_ADDRESS_LENGTH + 1,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
|
memcpy(&_pub,data + ZT_ADDRESS_LENGTH + 1,ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE);
|
||||||
|
|
||||||
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE];
|
privlen = data[ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE];
|
||||||
if (privlen == ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE) {
|
if (privlen == ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE) {
|
||||||
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE))
|
if (len < (ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE))
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
_hasPrivate = true;
|
_hasPrivate = true;
|
||||||
memcpy(&_priv,data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE);
|
memcpy(&_priv,data + ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1,ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE);
|
||||||
|
_computeHash();
|
||||||
if (!this->locallyValidate()) // for P384 we do this always
|
if (!this->locallyValidate()) // for P384 we do this always
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
|
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1 + ZT_IDENTITY_P384_COMPOUND_PRIVATE_KEY_SIZE;
|
||||||
} else if (privlen == 0) {
|
} else if (privlen == 0) {
|
||||||
_hasPrivate = false;
|
_hasPrivate = false;
|
||||||
|
|
||||||
|
_computeHash();
|
||||||
|
if (!this->locallyValidate()) // for P384 we do this always
|
||||||
|
return -1;
|
||||||
|
|
||||||
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1;
|
return ZT_ADDRESS_LENGTH + 1 + ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE + 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Identity::_computeHash()
|
||||||
|
{
|
||||||
|
switch(_type) {
|
||||||
|
default:
|
||||||
|
_hash.zero();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case C25519:
|
||||||
|
SHA384(_hash.data(),_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case P384:
|
||||||
|
if (!_hash) {
|
||||||
|
uint8_t *const h = _hash.data();
|
||||||
|
SHA384(h,&_pub,sizeof(_pub));
|
||||||
|
AES c(h);
|
||||||
|
c.encrypt(h,h);
|
||||||
|
c.encrypt(h + 16,h + 16);
|
||||||
|
c.encrypt(h + 32,h + 32);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "SHA512.hpp"
|
#include "SHA512.hpp"
|
||||||
#include "ECC384.hpp"
|
#include "ECC384.hpp"
|
||||||
#include "TriviallyCopyable.hpp"
|
#include "TriviallyCopyable.hpp"
|
||||||
|
#include "H.hpp"
|
||||||
|
|
||||||
#define ZT_IDENTITY_STRING_BUFFER_LENGTH 1024
|
#define ZT_IDENTITY_STRING_BUFFER_LENGTH 1024
|
||||||
#define ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE (ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE)
|
#define ZT_IDENTITY_P384_COMPOUND_PUBLIC_KEY_SIZE (ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE)
|
||||||
|
@ -96,7 +97,11 @@ public:
|
||||||
bool generate(Type t);
|
bool generate(Type t);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check the validity of this identity's pairing of key to address
|
* Check the validity of this identity's address
|
||||||
|
*
|
||||||
|
* For type 0 identities this is slightly time consuming. For type 1 identities it's
|
||||||
|
* instantaneous. It should be done when a new identity is accepted for the very first
|
||||||
|
* time.
|
||||||
*
|
*
|
||||||
* @return True if validation check passes
|
* @return True if validation check passes
|
||||||
*/
|
*/
|
||||||
|
@ -108,7 +113,7 @@ public:
|
||||||
ZT_ALWAYS_INLINE bool hasPrivate() const noexcept { return _hasPrivate; }
|
ZT_ALWAYS_INLINE bool hasPrivate() const noexcept { return _hasPrivate; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This gets (computing if needed) a hash of this identity's public key(s).
|
* Get hash of this identity's public key(s)
|
||||||
*
|
*
|
||||||
* The hash returned by this function differs by identity type. For C25519 (type 0)
|
* The hash returned by this function differs by identity type. For C25519 (type 0)
|
||||||
* identities this returns a simple SHA384 of the public key, which is NOT the same
|
* identities this returns a simple SHA384 of the public key, which is NOT the same
|
||||||
|
@ -117,12 +122,18 @@ public:
|
||||||
* and address computation. This difference is because the v0 hash is expensive while
|
* and address computation. This difference is because the v0 hash is expensive while
|
||||||
* the v1 hash is fast.
|
* the v1 hash is fast.
|
||||||
*
|
*
|
||||||
* @return 384-bit/48-byte hash (pointer remains valid as long as Identity object exists)
|
* While addresses can technically collide (though this is rare and hard to create),
|
||||||
|
* the full hash of an identity's keys is unique to within cryptographic strength
|
||||||
|
* bounds of the keys themselves.
|
||||||
|
*
|
||||||
|
* @return 384-bit/48-byte hash
|
||||||
*/
|
*/
|
||||||
const uint8_t *hash() const;
|
ZT_ALWAYS_INLINE const H<384> &hash() const noexcept { return _hash; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compute a hash of this identity's public and private keys
|
* Compute a hash of this identity's public and private keys.
|
||||||
|
*
|
||||||
|
* If there is no private key or the identity is NIL the buffer is filled with zero.
|
||||||
*
|
*
|
||||||
* @param h Buffer to store SHA384 hash
|
* @param h Buffer to store SHA384 hash
|
||||||
*/
|
*/
|
||||||
|
@ -234,10 +245,10 @@ public:
|
||||||
int unmarshal(const uint8_t *data,int len) noexcept;
|
int unmarshal(const uint8_t *data,int len) noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void _computeHash();
|
||||||
|
|
||||||
Address _address;
|
Address _address;
|
||||||
uint64_t _hash[6]; // hash of public key memo-ized for performance, recalculated when _hash[0] == 0
|
H<384> _hash;
|
||||||
Type _type; // _type determines which fields in _priv and _pub are used
|
|
||||||
bool _hasPrivate;
|
|
||||||
ZT_PACKED_STRUCT(struct { // don't re-order these
|
ZT_PACKED_STRUCT(struct { // don't re-order these
|
||||||
uint8_t c25519[ZT_C25519_PRIVATE_KEY_LEN];
|
uint8_t c25519[ZT_C25519_PRIVATE_KEY_LEN];
|
||||||
uint8_t p384[ZT_ECC384_PRIVATE_KEY_SIZE];
|
uint8_t p384[ZT_ECC384_PRIVATE_KEY_SIZE];
|
||||||
|
@ -246,6 +257,8 @@ private:
|
||||||
uint8_t c25519[ZT_C25519_PUBLIC_KEY_LEN]; // Curve25519 and Ed25519 public keys
|
uint8_t c25519[ZT_C25519_PUBLIC_KEY_LEN]; // Curve25519 and Ed25519 public keys
|
||||||
uint8_t p384[ZT_ECC384_PUBLIC_KEY_SIZE]; // NIST P-384 public key
|
uint8_t p384[ZT_ECC384_PUBLIC_KEY_SIZE]; // NIST P-384 public key
|
||||||
}) _pub;
|
}) _pub;
|
||||||
|
Type _type; // _type determines which fields in _priv and _pub are used
|
||||||
|
bool _hasPrivate;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ZeroTier
|
} // namespace ZeroTier
|
||||||
|
|
|
@ -60,10 +60,10 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
|
||||||
sendCom = false;
|
sendCom = false;
|
||||||
outp->wO(outl,nconf.com);
|
outp->wO(outl,nconf.com);
|
||||||
}
|
}
|
||||||
outp->wI(outl,(uint8_t)0);
|
outp->wI8(outl,0);
|
||||||
|
|
||||||
if ((outl + ZT_CAPABILITY_MARSHAL_SIZE_MAX + 2) < ZT_PROTO_MAX_PACKET_LENGTH) {
|
if ((outl + ZT_CAPABILITY_MARSHAL_SIZE_MAX + 2) < ZT_PROTO_MAX_PACKET_LENGTH) {
|
||||||
void *const capCountAt = outp->b + outl;
|
void *const capCountAt = outp->unsafeData + outl;
|
||||||
outl += 2;
|
outl += 2;
|
||||||
unsigned int capCount = 0;
|
unsigned int capCount = 0;
|
||||||
while (capPtr < nconf.capabilityCount) {
|
while (capPtr < nconf.capabilityCount) {
|
||||||
|
@ -75,7 +75,7 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
|
||||||
Utils::storeBigEndian(capCountAt,(uint16_t)capCount);
|
Utils::storeBigEndian(capCountAt,(uint16_t)capCount);
|
||||||
|
|
||||||
if ((outl + ZT_TAG_MARSHAL_SIZE_MAX + 4) < ZT_PROTO_MAX_PACKET_LENGTH) {
|
if ((outl + ZT_TAG_MARSHAL_SIZE_MAX + 4) < ZT_PROTO_MAX_PACKET_LENGTH) {
|
||||||
void *const tagCountAt = outp->b + outl;
|
void *const tagCountAt = outp->unsafeData + outl;
|
||||||
outl += 2;
|
outl += 2;
|
||||||
unsigned int tagCount = 0;
|
unsigned int tagCount = 0;
|
||||||
while (tagPtr < nconf.tagCount) {
|
while (tagPtr < nconf.tagCount) {
|
||||||
|
@ -86,10 +86,10 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
|
||||||
}
|
}
|
||||||
Utils::storeBigEndian(tagCountAt,(uint16_t)tagCount);
|
Utils::storeBigEndian(tagCountAt,(uint16_t)tagCount);
|
||||||
|
|
||||||
outp->wI(outl,(uint16_t)0); // no revocations sent here as these propagate differently
|
outp->wI16(outl,0); // no revocations sent here as these propagate differently
|
||||||
|
|
||||||
if ((outl + ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX + 2) < ZT_PROTO_MAX_PACKET_LENGTH) {
|
if ((outl + ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX + 2) < ZT_PROTO_MAX_PACKET_LENGTH) {
|
||||||
void *const cooCountAt = outp->b + outl;
|
void *const cooCountAt = outp->unsafeData + outl;
|
||||||
outl += 2;
|
outl += 2;
|
||||||
unsigned int cooCount = 0;
|
unsigned int cooCount = 0;
|
||||||
while (cooPtr < nconf.certificateOfOwnershipCount) {
|
while (cooPtr < nconf.certificateOfOwnershipCount) {
|
||||||
|
@ -102,15 +102,14 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const i
|
||||||
|
|
||||||
complete = true;
|
complete = true;
|
||||||
} else {
|
} else {
|
||||||
outp->wI(outl,(uint16_t)0);
|
outp->wI16(outl,0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
outp->wI(outl,(uint16_t)0);
|
outp->wI32(outl,0);
|
||||||
outp->wI(outl,(uint16_t)0);
|
outp->wI16(outl,0); // three zero 16-bit integers
|
||||||
outp->wI(outl,(uint16_t)0);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
outp->wI(outl,(uint64_t)0); // four zero 16-bit integers
|
outp->wI64(outl,0); // four zero 16-bit integers
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outl > sizeof(Protocol::Header)) {
|
if (outl > sizeof(Protocol::Header)) {
|
||||||
|
|
|
@ -14,13 +14,6 @@
|
||||||
#ifndef ZT_NETWORK_HPP
|
#ifndef ZT_NETWORK_HPP
|
||||||
#define ZT_NETWORK_HPP
|
#define ZT_NETWORK_HPP
|
||||||
|
|
||||||
#include <cstdint>
|
|
||||||
#include <string>
|
|
||||||
#include <map>
|
|
||||||
#include <vector>
|
|
||||||
#include <algorithm>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
#include "Constants.hpp"
|
#include "Constants.hpp"
|
||||||
#include "Hashtable.hpp"
|
#include "Hashtable.hpp"
|
||||||
#include "Address.hpp"
|
#include "Address.hpp"
|
||||||
|
@ -34,6 +27,12 @@
|
||||||
#include "NetworkConfig.hpp"
|
#include "NetworkConfig.hpp"
|
||||||
#include "CertificateOfMembership.hpp"
|
#include "CertificateOfMembership.hpp"
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
#include <string>
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#define ZT_NETWORK_MAX_INCOMING_UPDATES 3
|
#define ZT_NETWORK_MAX_INCOMING_UPDATES 3
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
|
@ -122,7 +122,7 @@ void Peer::received(
|
||||||
RR->t->learnedNewPath(tPtr,0x582fabdd,packetId,_id,path->address(),old);
|
RR->t->learnedNewPath(tPtr,0x582fabdd,packetId,_id,path->address(),old);
|
||||||
} else {
|
} else {
|
||||||
if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id,path->localSocket(),path->address())) {
|
if (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id,path->localSocket(),path->address())) {
|
||||||
RR->t->tryingNewPath(tPtr,0xb7747ddd,_id,path->address(),path->address(),packetId,(uint8_t)verb,_id.address(),_id.hash(),ZT_TRACE_TRYING_NEW_PATH_REASON_PACKET_RECEIVED_FROM_UNKNOWN_PATH);
|
RR->t->tryingNewPath(tPtr,0xb7747ddd,_id,path->address(),path->address(),packetId,(uint8_t)verb,_id.address(),_id.hash().data(),ZT_TRACE_TRYING_NEW_PATH_REASON_PACKET_RECEIVED_FROM_UNKNOWN_PATH);
|
||||||
sendHELLO(tPtr,path->localSocket(),path->address(),now);
|
sendHELLO(tPtr,path->localSocket(),path->address(),now);
|
||||||
path->sent(now);
|
path->sent(now);
|
||||||
}
|
}
|
||||||
|
@ -241,7 +241,7 @@ void Peer::sendNOP(void *tPtr,const int64_t localSocket,const InetAddress &atAdd
|
||||||
ph.flags = 0;
|
ph.flags = 0;
|
||||||
ph.verb = Protocol::VERB_NOP;
|
ph.verb = Protocol::VERB_NOP;
|
||||||
Protocol::armor(outp,sizeof(Protocol::Header),_key,this->cipher());
|
Protocol::armor(outp,sizeof(Protocol::Header),_key,this->cipher());
|
||||||
RR->node->putPacket(tPtr,localSocket,atAddress,outp.b,sizeof(Protocol::Header));
|
RR->node->putPacket(tPtr,localSocket,atAddress,outp.unsafeData,sizeof(Protocol::Header));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Peer::ping(void *tPtr,int64_t now,const bool pingAllAddressTypes)
|
void Peer::ping(void *tPtr,int64_t now,const bool pingAllAddressTypes)
|
||||||
|
@ -337,24 +337,26 @@ void Peer::getAllPaths(std::vector< SharedPtr<Path> > &paths)
|
||||||
|
|
||||||
void Peer::save(void *tPtr) const
|
void Peer::save(void *tPtr) const
|
||||||
{
|
{
|
||||||
uint8_t *const buf = (uint8_t *)malloc(ZT_PEER_MARSHAL_SIZE_MAX);
|
uint8_t *const buf = (uint8_t *)malloc(8 + ZT_PEER_MARSHAL_SIZE_MAX);
|
||||||
if (!buf) return;
|
if (!buf) return;
|
||||||
|
|
||||||
|
Utils::storeBigEndian<uint64_t>(buf,(uint64_t)RR->node->now());
|
||||||
|
|
||||||
_lock.rlock();
|
_lock.rlock();
|
||||||
const int len = marshal(buf);
|
const int len = marshal(buf + 8);
|
||||||
_lock.runlock();
|
_lock.runlock();
|
||||||
|
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
uint64_t id[2];
|
uint64_t id[2];
|
||||||
id[0] = _id.address().toInt();
|
id[0] = _id.address().toInt();
|
||||||
id[1] = 0;
|
id[1] = 0;
|
||||||
RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER,id,buf,(unsigned int)len);
|
RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER,id,buf,(unsigned int)len + 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Peer::contact(void *tPtr,const Endpoint &ep,const int64_t now,const bool behindSymmetric,const bool bfg1024)
|
void Peer::contact(void *tPtr,const Endpoint &ep,const int64_t now,const bool bfg1024)
|
||||||
{
|
{
|
||||||
static uint8_t junk = 0;
|
static uint8_t junk = 0;
|
||||||
|
|
||||||
|
@ -376,7 +378,7 @@ void Peer::contact(void *tPtr,const Endpoint &ep,const int64_t now,const bool be
|
||||||
|
|
||||||
// If the peer indicates that they may be behind a symmetric NAT and there are no
|
// If the peer indicates that they may be behind a symmetric NAT and there are no
|
||||||
// living direct paths, try a few more aggressive things.
|
// living direct paths, try a few more aggressive things.
|
||||||
if ((behindSymmetric) && (phyAddr.ss_family == AF_INET) && (!direct(now))) {
|
if ((phyAddr.ss_family == AF_INET) && (!direct(now))) {
|
||||||
unsigned int port = phyAddr.port();
|
unsigned int port = phyAddr.port();
|
||||||
if ((bfg1024)&&(port < 1024)&&(RR->node->natMustDie())) {
|
if ((bfg1024)&&(port < 1024)&&(RR->node->natMustDie())) {
|
||||||
// If the other side is using a low-numbered port and has elected to
|
// If the other side is using a low-numbered port and has elected to
|
||||||
|
|
|
@ -170,7 +170,11 @@ public:
|
||||||
/**
|
/**
|
||||||
* @return Bootstrap address or NULL if none
|
* @return Bootstrap address or NULL if none
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE const Endpoint &bootstrap() const noexcept { return _bootstrap; }
|
ZT_ALWAYS_INLINE const Endpoint &bootstrap() const noexcept
|
||||||
|
{
|
||||||
|
RWMutex::RLock l(_lock);
|
||||||
|
return _bootstrap;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set bootstrap endpoint
|
* Set bootstrap endpoint
|
||||||
|
@ -179,9 +183,8 @@ public:
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE void setBootstrap(const Endpoint &ep) noexcept
|
ZT_ALWAYS_INLINE void setBootstrap(const Endpoint &ep) noexcept
|
||||||
{
|
{
|
||||||
_lock.lock();
|
RWMutex::Lock l(_lock);
|
||||||
_bootstrap = ep;
|
_bootstrap = ep;
|
||||||
_lock.unlock();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -315,17 +318,14 @@ public:
|
||||||
void save(void *tPtr) const;
|
void save(void *tPtr) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempt to contact this peer at a physical address
|
* Attempt to contact this peer at a physical address, subject to internal checks
|
||||||
*
|
|
||||||
* This checks rate limits, path usability, sometimes deploys advanced NAT-t techniques, etc.
|
|
||||||
*
|
*
|
||||||
* @param tPtr External user pointer we pass around
|
* @param tPtr External user pointer we pass around
|
||||||
* @param ep Endpoint to attempt to contact
|
* @param ep Endpoint to attempt to contact
|
||||||
* @param now Current time
|
* @param now Current time
|
||||||
* @param behindSymmetric This peer may be behind a symmetric NAT (only meaningful for IPv4)
|
|
||||||
* @param bfg1024 Use BFG1024 brute force symmetric NAT busting algorithm if applicable
|
* @param bfg1024 Use BFG1024 brute force symmetric NAT busting algorithm if applicable
|
||||||
*/
|
*/
|
||||||
void contact(void *tPtr,const Endpoint &ep,int64_t now,bool behindSymmetric,bool bfg1024);
|
void contact(void *tPtr,const Endpoint &ep,int64_t now,bool bfg1024);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by Node when an alarm set by this peer goes off
|
* Called by Node when an alarm set by this peer goes off
|
||||||
|
@ -348,20 +348,24 @@ private:
|
||||||
|
|
||||||
const RuntimeEnvironment *RR;
|
const RuntimeEnvironment *RR;
|
||||||
|
|
||||||
volatile int64_t _lastReceive;
|
// The last time various things happened, for rate limiting and periodic events.
|
||||||
volatile int64_t _lastWhoisRequestReceived;
|
std::atomic<int64_t> _lastReceive;
|
||||||
volatile int64_t _lastEchoRequestReceived;
|
std::atomic<int64_t> _lastWhoisRequestReceived;
|
||||||
volatile int64_t _lastPushDirectPathsReceived;
|
std::atomic<int64_t> _lastEchoRequestReceived;
|
||||||
volatile int64_t _lastProbeReceived;
|
std::atomic<int64_t> _lastPushDirectPathsReceived;
|
||||||
volatile int64_t _lastAttemptedP2PInit;
|
std::atomic<int64_t> _lastProbeReceived;
|
||||||
volatile int64_t _lastTriedStaticPath;
|
std::atomic<int64_t> _lastAttemptedP2PInit;
|
||||||
volatile int64_t _lastPrioritizedPaths;
|
std::atomic<int64_t> _lastTriedStaticPath;
|
||||||
volatile int64_t _lastAttemptedAggressiveNATTraversal;
|
std::atomic<int64_t> _lastPrioritizedPaths;
|
||||||
volatile unsigned int _latency;
|
std::atomic<int64_t> _lastAttemptedAggressiveNATTraversal;
|
||||||
|
|
||||||
|
// Latency in milliseconds
|
||||||
|
std::atomic<unsigned int> _latency;
|
||||||
|
|
||||||
|
// For SharedPtr<>
|
||||||
std::atomic<int> __refCount;
|
std::atomic<int> __refCount;
|
||||||
|
|
||||||
// Lock for non-volatile read/write fields
|
// Read/write mutex for non-atomic non-const fields.
|
||||||
RWMutex _lock;
|
RWMutex _lock;
|
||||||
|
|
||||||
// Number of paths current alive as of last _prioritizePaths
|
// Number of paths current alive as of last _prioritizePaths
|
||||||
|
|
|
@ -65,8 +65,8 @@ volatile uintptr_t _checkSizesIMeanIt = _checkSizes();
|
||||||
uint64_t createProbe(const Identity &sender,const Identity &recipient,const uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]) noexcept
|
uint64_t createProbe(const Identity &sender,const Identity &recipient,const uint8_t key[ZT_PEER_SECRET_KEY_LENGTH]) noexcept
|
||||||
{
|
{
|
||||||
uint8_t tmp[ZT_IDENTITY_HASH_SIZE + ZT_IDENTITY_HASH_SIZE];
|
uint8_t tmp[ZT_IDENTITY_HASH_SIZE + ZT_IDENTITY_HASH_SIZE];
|
||||||
memcpy(tmp,sender.hash(),ZT_IDENTITY_HASH_SIZE);
|
memcpy(tmp,sender.hash().data(),ZT_IDENTITY_HASH_SIZE);
|
||||||
memcpy(tmp + ZT_IDENTITY_HASH_SIZE,recipient.hash(),ZT_IDENTITY_HASH_SIZE);
|
memcpy(tmp + ZT_IDENTITY_HASH_SIZE,recipient.hash().data(),ZT_IDENTITY_HASH_SIZE);
|
||||||
uint64_t hash[6];
|
uint64_t hash[6];
|
||||||
SHA384(hash,tmp,sizeof(tmp),key,ZT_PEER_SECRET_KEY_LENGTH);
|
SHA384(hash,tmp,sizeof(tmp),key,ZT_PEER_SECRET_KEY_LENGTH);
|
||||||
return hash[0];
|
return hash[0];
|
||||||
|
@ -98,7 +98,7 @@ void armor(Buf &pkt,int packetSize,const uint8_t key[ZT_PEER_SECRET_KEY_LENGTH],
|
||||||
// only difference here is that we don't encrypt the payload
|
// only difference here is that we don't encrypt the payload
|
||||||
|
|
||||||
uint64_t mac[2];
|
uint64_t mac[2];
|
||||||
poly1305(mac,pkt.b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,macKey);
|
poly1305(mac,pkt.unsafeData + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,macKey);
|
||||||
ph.mac = mac[0];
|
ph.mac = mac[0];
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -111,10 +111,10 @@ void armor(Buf &pkt,int packetSize,const uint8_t key[ZT_PEER_SECRET_KEY_LENGTH],
|
||||||
s20.crypt12(Utils::ZERO256,macKey,ZT_POLY1305_KEY_LEN);
|
s20.crypt12(Utils::ZERO256,macKey,ZT_POLY1305_KEY_LEN);
|
||||||
|
|
||||||
const unsigned int encLen = packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START;
|
const unsigned int encLen = packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START;
|
||||||
s20.crypt12(pkt.b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,pkt.b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,encLen);
|
s20.crypt12(pkt.unsafeData + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,pkt.unsafeData + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,encLen);
|
||||||
|
|
||||||
uint64_t mac[2];
|
uint64_t mac[2];
|
||||||
poly1305(mac,pkt.b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,encLen,macKey);
|
poly1305(mac,pkt.unsafeData + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,encLen,macKey);
|
||||||
ph.mac = mac[0];
|
ph.mac = mac[0];
|
||||||
} break;
|
} break;
|
||||||
|
|
||||||
|
@ -132,9 +132,9 @@ int compress(SharedPtr<Buf> &pkt,int packetSize) noexcept
|
||||||
if (!pkt2) return packetSize;
|
if (!pkt2) return packetSize;
|
||||||
|
|
||||||
const int uncompressedLen = packetSize - ZT_PROTO_PACKET_PAYLOAD_START;
|
const int uncompressedLen = packetSize - ZT_PROTO_PACKET_PAYLOAD_START;
|
||||||
const int compressedLen = LZ4_compress_fast(reinterpret_cast<const char *>(pkt->b + ZT_PROTO_PACKET_PAYLOAD_START),reinterpret_cast<char *>(pkt2->b + ZT_PROTO_PACKET_PAYLOAD_START),uncompressedLen,ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START);
|
const int compressedLen = LZ4_compress_fast(reinterpret_cast<const char *>(pkt->unsafeData + ZT_PROTO_PACKET_PAYLOAD_START),reinterpret_cast<char *>(pkt2->unsafeData + ZT_PROTO_PACKET_PAYLOAD_START),uncompressedLen,ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START);
|
||||||
if ((compressedLen > 0)&&(compressedLen < uncompressedLen)) {
|
if ((compressedLen > 0)&&(compressedLen < uncompressedLen)) {
|
||||||
memcpy(pkt2->b,pkt->b,ZT_PROTO_PACKET_PAYLOAD_START);
|
memcpy(pkt2->unsafeData,pkt->unsafeData,ZT_PROTO_PACKET_PAYLOAD_START);
|
||||||
pkt.swap(pkt2);
|
pkt.swap(pkt2);
|
||||||
pkt->as<Protocol::Header>().verb |= ZT_PROTO_VERB_FLAG_COMPRESSED;
|
pkt->as<Protocol::Header>().verb |= ZT_PROTO_VERB_FLAG_COMPRESSED;
|
||||||
return compressedLen + ZT_PROTO_PACKET_PAYLOAD_START;
|
return compressedLen + ZT_PROTO_PACKET_PAYLOAD_START;
|
||||||
|
|
|
@ -640,13 +640,17 @@ enum Verb
|
||||||
* <[...] paths>
|
* <[...] paths>
|
||||||
*
|
*
|
||||||
* Path record format:
|
* Path record format:
|
||||||
* <[1] 8-bit path flags (always 0, currently unused)>
|
* <[1] 8-bit path flags>
|
||||||
* <[2] length of extended path characteristics or 0 for none>
|
* <[2] length of extended path characteristics or 0 for none>
|
||||||
* <[...] extended path characteristics>
|
* <[...] extended path characteristics>
|
||||||
* <[1] address type>
|
* <[1] address type>
|
||||||
* <[1] address length in bytes>
|
* <[1] address record length in bytes>
|
||||||
* <[...] address>
|
* <[...] address>
|
||||||
*
|
*
|
||||||
|
* Path flags:
|
||||||
|
* 0x01 - Sender is likely behind a symmetric NAT
|
||||||
|
* 0x02 - Use BFG1024 algorithm for symmetric NAT-t if conditions met
|
||||||
|
*
|
||||||
* The receiver may, upon receiving a push, attempt to establish a
|
* The receiver may, upon receiving a push, attempt to establish a
|
||||||
* direct link to one or more of the indicated addresses. It is the
|
* direct link to one or more of the indicated addresses. It is the
|
||||||
* responsibility of the sender to limit which peers it pushes direct
|
* responsibility of the sender to limit which peers it pushes direct
|
||||||
|
@ -965,21 +969,21 @@ ZT_PACKED_STRUCT(struct UNSUPPORTED_OPERATION__NETWORK_CONFIG_REQUEST
|
||||||
* @param packetSize Packet's actual size in bytes
|
* @param packetSize Packet's actual size in bytes
|
||||||
* @return Packet ID or 0 if packet size is less than 8
|
* @return Packet ID or 0 if packet size is less than 8
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE uint64_t packetId(const Buf &pkt,const unsigned int packetSize) noexcept { return (packetSize >= 8) ? Utils::loadBigEndian<uint64_t>(pkt.b) : 0ULL; }
|
ZT_ALWAYS_INLINE uint64_t packetId(const Buf &pkt,const unsigned int packetSize) noexcept { return (packetSize >= 8) ? Utils::loadBigEndian<uint64_t>(pkt.unsafeData) : 0ULL; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Packet to extract hops from
|
* @param Packet to extract hops from
|
||||||
* @param packetSize Packet's actual size in bytes
|
* @param packetSize Packet's actual size in bytes
|
||||||
* @return 3-bit hops field embedded in packet flags field
|
* @return 3-bit hops field embedded in packet flags field
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE uint8_t packetHops(const Buf &pkt,const unsigned int packetSize) noexcept { return (packetSize >= ZT_PROTO_PACKET_FLAGS_INDEX) ? (pkt.b[ZT_PROTO_PACKET_FLAGS_INDEX] & ZT_PROTO_FLAG_FIELD_HOPS_MASK) : 0; }
|
ZT_ALWAYS_INLINE uint8_t packetHops(const Buf &pkt,const unsigned int packetSize) noexcept { return (packetSize >= ZT_PROTO_PACKET_FLAGS_INDEX) ? (pkt.unsafeData[ZT_PROTO_PACKET_FLAGS_INDEX] & ZT_PROTO_FLAG_FIELD_HOPS_MASK) : 0; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Packet to extract cipher ID from
|
* @param Packet to extract cipher ID from
|
||||||
* @param packetSize Packet's actual size in bytes
|
* @param packetSize Packet's actual size in bytes
|
||||||
* @return 3-bit cipher field embedded in packet flags field
|
* @return 3-bit cipher field embedded in packet flags field
|
||||||
*/
|
*/
|
||||||
ZT_ALWAYS_INLINE uint8_t packetCipher(const Buf &pkt,const unsigned int packetSize) noexcept { return (packetSize >= ZT_PROTO_PACKET_FLAGS_INDEX) ? ((pkt.b[ZT_PROTO_PACKET_FLAGS_INDEX] >> 3U) & 0x07U) : 0; }
|
ZT_ALWAYS_INLINE uint8_t packetCipher(const Buf &pkt,const unsigned int packetSize) noexcept { return (packetSize >= ZT_PROTO_PACKET_FLAGS_INDEX) ? ((pkt.unsafeData[ZT_PROTO_PACKET_FLAGS_INDEX] >> 3U) & 0x07U) : 0; }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return 3-bit hops field embedded in packet flags field
|
* @return 3-bit hops field embedded in packet flags field
|
||||||
|
@ -1009,14 +1013,14 @@ ZT_ALWAYS_INLINE void salsa2012DeriveKey(const uint8_t *const in,uint8_t *const
|
||||||
for(int i=0;i<18;++i)
|
for(int i=0;i<18;++i)
|
||||||
out[i] = in[i] ^ packet.b[i];
|
out[i] = in[i] ^ packet.b[i];
|
||||||
#else
|
#else
|
||||||
*reinterpret_cast<uint64_t *>(out) = *reinterpret_cast<const uint64_t *>(in) ^ *reinterpret_cast<const uint64_t *>(packet.b);
|
*reinterpret_cast<uint64_t *>(out) = *reinterpret_cast<const uint64_t *>(in) ^ *reinterpret_cast<const uint64_t *>(packet.unsafeData);
|
||||||
*reinterpret_cast<uint64_t *>(out + 8) = *reinterpret_cast<const uint64_t *>(in + 8) ^ *reinterpret_cast<const uint64_t *>(packet.b + 8);
|
*reinterpret_cast<uint64_t *>(out + 8) = *reinterpret_cast<const uint64_t *>(in + 8) ^ *reinterpret_cast<const uint64_t *>(packet.unsafeData + 8);
|
||||||
*reinterpret_cast<uint16_t *>(out + 16) = *reinterpret_cast<const uint16_t *>(in + 16) ^ *reinterpret_cast<const uint16_t *>(packet.b + 16);
|
*reinterpret_cast<uint16_t *>(out + 16) = *reinterpret_cast<const uint16_t *>(in + 16) ^ *reinterpret_cast<const uint16_t *>(packet.unsafeData + 16);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Flags, but with hop count masked off. Hop count is altered by forwarding
|
// Flags, but with hop count masked off. Hop count is altered by forwarding
|
||||||
// nodes and is the only field that is mutable by unauthenticated third parties.
|
// nodes and is the only field that is mutable by unauthenticated third parties.
|
||||||
out[18] = in[18] ^ (packet.b[18] & 0xf8U);
|
out[18] = in[18] ^ (packet.unsafeData[18] & 0xf8U);
|
||||||
|
|
||||||
// Raw packet size in bytes -- thus each packet size defines a new key space.
|
// Raw packet size in bytes -- thus each packet size defines a new key space.
|
||||||
out[19] = in[19] ^ (uint8_t)packetSize;
|
out[19] = in[19] ^ (uint8_t)packetSize;
|
||||||
|
|
|
@ -38,8 +38,10 @@ Topology::Topology(const RuntimeEnvironment *renv,const Identity &myId,void *tPt
|
||||||
RR(renv),
|
RR(renv),
|
||||||
_myIdentity(myId),
|
_myIdentity(myId),
|
||||||
_numConfiguredPhysicalPaths(0),
|
_numConfiguredPhysicalPaths(0),
|
||||||
_peers(128),
|
_peers(256),
|
||||||
_paths(256)
|
_peersByIncomingProbe(256),
|
||||||
|
_peersByIdentityHash(256),
|
||||||
|
_paths(1024)
|
||||||
{
|
{
|
||||||
uint64_t idtmp[2]; idtmp[0] = 0; idtmp[1] = 0;
|
uint64_t idtmp[2]; idtmp[0] = 0; idtmp[1] = 0;
|
||||||
std::vector<uint8_t> data(RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_ROOTS,idtmp));
|
std::vector<uint8_t> data(RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_ROOTS,idtmp));
|
||||||
|
@ -65,6 +67,9 @@ Topology::Topology(const RuntimeEnvironment *renv,const Identity &myId,void *tPt
|
||||||
p->init(*r);
|
p->init(*r);
|
||||||
}
|
}
|
||||||
_rootPeers.push_back(p);
|
_rootPeers.push_back(p);
|
||||||
|
_peers[p->address()] = p;
|
||||||
|
_peersByIncomingProbe[p->incomingProbe()] = p;
|
||||||
|
_peersByIdentityHash[p->identity().hash()] = p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,11 +88,13 @@ SharedPtr<Peer> Topology::add(void *tPtr,const SharedPtr<Peer> &peer)
|
||||||
_loadCached(tPtr,peer->address(),hp);
|
_loadCached(tPtr,peer->address(),hp);
|
||||||
if (hp) {
|
if (hp) {
|
||||||
_peersByIncomingProbe[peer->incomingProbe()] = hp;
|
_peersByIncomingProbe[peer->incomingProbe()] = hp;
|
||||||
|
_peersByIdentityHash[peer->identity().hash()] = hp;
|
||||||
return hp;
|
return hp;
|
||||||
}
|
}
|
||||||
|
|
||||||
hp = peer;
|
hp = peer;
|
||||||
_peersByIncomingProbe[peer->incomingProbe()] = peer;
|
_peersByIncomingProbe[peer->incomingProbe()] = peer;
|
||||||
|
_peersByIdentityHash[peer->identity().hash()] = peer;
|
||||||
|
|
||||||
return peer;
|
return peer;
|
||||||
}
|
}
|
||||||
|
@ -150,6 +157,8 @@ void Topology::addRoot(void *tPtr,const Identity &id,const InetAddress &bootstra
|
||||||
p->init(id);
|
p->init(id);
|
||||||
if (bootstrap)
|
if (bootstrap)
|
||||||
p->setBootstrap(Endpoint(bootstrap));
|
p->setBootstrap(Endpoint(bootstrap));
|
||||||
|
_peersByIncomingProbe[p->incomingProbe()] = p;
|
||||||
|
_peersByIdentityHash[p->identity().hash()] = p;
|
||||||
}
|
}
|
||||||
_rootPeers.push_back(p);
|
_rootPeers.push_back(p);
|
||||||
|
|
||||||
|
@ -204,6 +213,7 @@ void Topology::doPeriodicTasks(void *tPtr,const int64_t now)
|
||||||
if ( (!(*p)->alive(now)) && (_roots.count((*p)->identity()) == 0) ) {
|
if ( (!(*p)->alive(now)) && (_roots.count((*p)->identity()) == 0) ) {
|
||||||
(*p)->save(tPtr);
|
(*p)->save(tPtr);
|
||||||
_peersByIncomingProbe.erase((*p)->incomingProbe());
|
_peersByIncomingProbe.erase((*p)->incomingProbe());
|
||||||
|
_peersByIdentityHash.erase((*p)->identity().hash());
|
||||||
_peers.erase(*a);
|
_peers.erase(*a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -226,11 +236,8 @@ void Topology::saveAll(void *tPtr)
|
||||||
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
|
Hashtable< Address,SharedPtr<Peer> >::Iterator i(_peers);
|
||||||
Address *a = nullptr;
|
Address *a = nullptr;
|
||||||
SharedPtr<Peer> *p = nullptr;
|
SharedPtr<Peer> *p = nullptr;
|
||||||
while (i.next(a,p)) {
|
while (i.next(a,p))
|
||||||
if ( (!(*p)->alive(RR->node->now())) && (_roots.count((*p)->identity()) == 0) ) {
|
(*p)->save(tPtr);
|
||||||
(*p)->save((void *)0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Topology::_loadCached(void *tPtr,const Address &zta,SharedPtr<Peer> &peer)
|
void Topology::_loadCached(void *tPtr,const Address &zta,SharedPtr<Peer> &peer)
|
||||||
|
@ -240,19 +247,21 @@ void Topology::_loadCached(void *tPtr,const Address &zta,SharedPtr<Peer> &peer)
|
||||||
id[0] = zta.toInt();
|
id[0] = zta.toInt();
|
||||||
id[1] = 0;
|
id[1] = 0;
|
||||||
std::vector<uint8_t> data(RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,id));
|
std::vector<uint8_t> data(RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,id));
|
||||||
if (!data.empty()) {
|
if (data.size() > 8) {
|
||||||
const uint8_t *d = data.data();
|
const uint8_t *d = data.data();
|
||||||
int dl = (int)data.size();
|
int dl = (int)data.size();
|
||||||
for (;;) {
|
|
||||||
|
const int64_t ts = (int64_t)Utils::loadBigEndian<uint64_t>(d);
|
||||||
Peer *const p = new Peer(RR);
|
Peer *const p = new Peer(RR);
|
||||||
int n = p->unmarshal(d,dl);
|
int n = p->unmarshal(d + 8,dl - 8);
|
||||||
if (n > 0) {
|
if (n < 0) {
|
||||||
// TODO: will eventually handle multiple peers
|
delete p;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((RR->node->now() - ts) < ZT_PEER_GLOBAL_TIMEOUT) {
|
||||||
|
// TODO: handle many peers, same address (?)
|
||||||
peer.set(p);
|
peer.set(p);
|
||||||
return;
|
return;
|
||||||
} else {
|
|
||||||
delete p;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch ( ... ) {
|
} catch ( ... ) {
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "Hashtable.hpp"
|
#include "Hashtable.hpp"
|
||||||
#include "SharedPtr.hpp"
|
#include "SharedPtr.hpp"
|
||||||
#include "ScopedPtr.hpp"
|
#include "ScopedPtr.hpp"
|
||||||
|
#include "H.hpp"
|
||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
|
@ -66,25 +67,41 @@ public:
|
||||||
ZT_ALWAYS_INLINE SharedPtr<Peer> peer(void *tPtr,const Address &zta,const bool loadFromCached = true)
|
ZT_ALWAYS_INLINE SharedPtr<Peer> peer(void *tPtr,const Address &zta,const bool loadFromCached = true)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
RWMutex::RLock _l(_peers_l);
|
RWMutex::RLock l(_peers_l);
|
||||||
const SharedPtr<Peer> *const ap = _peers.get(zta);
|
const SharedPtr<Peer> *const ap = _peers.get(zta);
|
||||||
if (ap)
|
if (ap)
|
||||||
return *ap;
|
return *ap;
|
||||||
}
|
}
|
||||||
|
{
|
||||||
SharedPtr<Peer> p;
|
SharedPtr<Peer> p;
|
||||||
if (loadFromCached) {
|
if (loadFromCached) {
|
||||||
_loadCached(tPtr,zta,p);
|
_loadCached(tPtr,zta,p);
|
||||||
if (p) {
|
if (p) {
|
||||||
RWMutex::Lock _l(_peers_l);
|
RWMutex::Lock l(_peers_l);
|
||||||
SharedPtr<Peer> &hp = _peers[zta];
|
SharedPtr<Peer> &hp = _peers[zta];
|
||||||
if (!hp)
|
if (hp)
|
||||||
|
return hp;
|
||||||
hp = p;
|
hp = p;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a peer by its 384-bit identity public key hash
|
||||||
|
*
|
||||||
|
* @param hash Identity hash
|
||||||
|
* @return Peer or NULL if no peer is currently in memory for this hash (cache is not checked in this case)
|
||||||
|
*/
|
||||||
|
ZT_ALWAYS_INLINE SharedPtr<Peer> peerByHash(const H<384> &hash)
|
||||||
|
{
|
||||||
|
RWMutex::RLock _l(_peers_l);
|
||||||
|
const SharedPtr<Peer> *const ap = _peersByIdentityHash.get(hash);
|
||||||
|
if (ap)
|
||||||
|
return *ap;
|
||||||
|
return SharedPtr<Peer>();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a peer by its incoming short probe packet payload
|
* Get a peer by its incoming short probe packet payload
|
||||||
|
@ -111,30 +128,22 @@ public:
|
||||||
ZT_ALWAYS_INLINE SharedPtr<Path> path(const int64_t l,const InetAddress &r)
|
ZT_ALWAYS_INLINE SharedPtr<Path> path(const int64_t l,const InetAddress &r)
|
||||||
{
|
{
|
||||||
const uint64_t k = _pathHash(l,r);
|
const uint64_t k = _pathHash(l,r);
|
||||||
|
{
|
||||||
_paths_l.rlock();
|
RWMutex::RLock lck(_paths_l);
|
||||||
SharedPtr<Path> p(_paths[k]);
|
SharedPtr<Path> *const p = _paths.get(k);
|
||||||
_paths_l.runlock();
|
|
||||||
if (p)
|
if (p)
|
||||||
return p;
|
return *p;
|
||||||
|
}
|
||||||
_paths_l.lock();
|
{
|
||||||
|
SharedPtr<Path> p(new Path(l,r));
|
||||||
|
RWMutex::Lock lck(_paths_l);
|
||||||
SharedPtr<Path> &p2 = _paths[k];
|
SharedPtr<Path> &p2 = _paths[k];
|
||||||
if (p2) {
|
if (p2)
|
||||||
p = p2;
|
return p2;
|
||||||
} else {
|
|
||||||
try {
|
|
||||||
p.set(new Path(l,r));
|
|
||||||
} catch ( ... ) {
|
|
||||||
_paths_l.unlock();
|
|
||||||
return SharedPtr<Path>();
|
|
||||||
}
|
|
||||||
p2 = p;
|
p2 = p;
|
||||||
}
|
|
||||||
_paths_l.unlock();
|
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Current best root server
|
* @return Current best root server
|
||||||
|
@ -173,10 +182,9 @@ public:
|
||||||
Hashtable< Address,SharedPtr<Peer> >::Iterator i(const_cast<Topology *>(this)->_peers);
|
Hashtable< Address,SharedPtr<Peer> >::Iterator i(const_cast<Topology *>(this)->_peers);
|
||||||
Address *a = nullptr;
|
Address *a = nullptr;
|
||||||
SharedPtr<Peer> *p = nullptr;
|
SharedPtr<Peer> *p = nullptr;
|
||||||
while (i.next(a,p)) {
|
while (i.next(a,p))
|
||||||
f(*((const SharedPtr<Peer> *)p));
|
f(*((const SharedPtr<Peer> *)p));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply a function or function object to all peers
|
* Apply a function or function object to all peers
|
||||||
|
@ -202,9 +210,8 @@ public:
|
||||||
Hashtable< Address,SharedPtr<Peer> >::Iterator i(const_cast<Topology *>(this)->_peers);
|
Hashtable< Address,SharedPtr<Peer> >::Iterator i(const_cast<Topology *>(this)->_peers);
|
||||||
Address *a = nullptr;
|
Address *a = nullptr;
|
||||||
SharedPtr<Peer> *p = nullptr;
|
SharedPtr<Peer> *p = nullptr;
|
||||||
while (i.next(a,p)) {
|
while (i.next(a,p))
|
||||||
f(*((const SharedPtr<Peer> *)p),std::binary_search(rootPeerPtrs.begin(),rootPeerPtrs.end(),(uintptr_t)p->ptr()));
|
f(*((const SharedPtr<Peer> *)p),std::binary_search(rootPeerPtrs.begin(),rootPeerPtrs.end(),(uintptr_t)p->ptr()));
|
||||||
}
|
|
||||||
} catch ( ... ) {} // should not throw
|
} catch ( ... ) {} // should not throw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -221,10 +228,9 @@ public:
|
||||||
Hashtable< uint64_t,SharedPtr<Path> >::Iterator i(const_cast<Topology *>(this)->_paths);
|
Hashtable< uint64_t,SharedPtr<Path> >::Iterator i(const_cast<Topology *>(this)->_paths);
|
||||||
uint64_t *k = nullptr;
|
uint64_t *k = nullptr;
|
||||||
SharedPtr<Path> *p = nullptr;
|
SharedPtr<Path> *p = nullptr;
|
||||||
while (i.next(k,p)) {
|
while (i.next(k,p))
|
||||||
f(*((const SharedPtr<Path> *)p));
|
f(*((const SharedPtr<Path> *)p));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param allPeers vector to fill with all current peers
|
* @param allPeers vector to fill with all current peers
|
||||||
|
@ -359,6 +365,7 @@ private:
|
||||||
|
|
||||||
Hashtable< Address,SharedPtr<Peer> > _peers;
|
Hashtable< Address,SharedPtr<Peer> > _peers;
|
||||||
Hashtable< uint64_t,SharedPtr<Peer> > _peersByIncomingProbe;
|
Hashtable< uint64_t,SharedPtr<Peer> > _peersByIncomingProbe;
|
||||||
|
Hashtable< H<384>,SharedPtr<Peer> > _peersByIdentityHash;
|
||||||
Hashtable< uint64_t,SharedPtr<Path> > _paths;
|
Hashtable< uint64_t,SharedPtr<Path> > _paths;
|
||||||
std::set< Identity > _roots; // locked by _peers_l
|
std::set< Identity > _roots; // locked by _peers_l
|
||||||
std::vector< SharedPtr<Peer> > _rootPeers; // locked by _peers_l
|
std::vector< SharedPtr<Peer> > _rootPeers; // locked by _peers_l
|
||||||
|
|
|
@ -118,15 +118,15 @@ void Trace::_tryingNewPath(
|
||||||
ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL1_TRYING_NEW_PATH);
|
ev.evType = ZT_CONST_TO_BE_UINT16(ZT_TRACE_VL1_TRYING_NEW_PATH);
|
||||||
ev.codeLocation = Utils::hton(codeLocation);
|
ev.codeLocation = Utils::hton(codeLocation);
|
||||||
ev.address = Utils::hton(trying.address().toInt());
|
ev.address = Utils::hton(trying.address().toInt());
|
||||||
memcpy(ev.identityHash,trying.hash(),48);
|
memcpy(ev.identityHash,trying.hash().data(),48);
|
||||||
physicalAddress.forTrace(ev.physicalAddress);
|
physicalAddress.forTrace(ev.physicalAddress);
|
||||||
triggerAddress.forTrace(ev.triggerAddress);
|
triggerAddress.forTrace(ev.triggerAddress);
|
||||||
ev.triggeringPacketId = triggeringPacketId;
|
ev.triggeringPacketId = triggeringPacketId;
|
||||||
ev.triggeringPacketVerb = triggeringPacketVerb;
|
ev.triggeringPacketVerb = triggeringPacketVerb;
|
||||||
ev.triggeredByAddress = Utils::hton(triggeredByAddress);
|
ev.triggeredByAddress = Utils::hton(triggeredByAddress);
|
||||||
if (triggeredByIdentityHash)
|
if (triggeredByIdentityHash)
|
||||||
memcpy(ev.triggeredByIdentityHash,triggeredByIdentityHash,48);
|
memcpy(ev.triggeredByIdentityHash,triggeredByIdentityHash,ZT_IDENTITY_HASH_SIZE);
|
||||||
else memset(ev.triggeredByIdentityHash,0,48);
|
else memset(ev.triggeredByIdentityHash,0,ZT_IDENTITY_HASH_SIZE);
|
||||||
ev.reason = (uint8_t)reason;
|
ev.reason = (uint8_t)reason;
|
||||||
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
|
RR->node->postEvent(tPtr,ZT_EVENT_TRACE,&ev);
|
||||||
}
|
}
|
||||||
|
@ -145,7 +145,7 @@ void Trace::_learnedNewPath(
|
||||||
ev.codeLocation = Utils::hton(codeLocation);
|
ev.codeLocation = Utils::hton(codeLocation);
|
||||||
ev.packetId = packetId; // packet IDs are kept in big-endian
|
ev.packetId = packetId; // packet IDs are kept in big-endian
|
||||||
ev.address = Utils::hton(peerIdentity.address().toInt());
|
ev.address = Utils::hton(peerIdentity.address().toInt());
|
||||||
memcpy(ev.identityHash,peerIdentity.hash(),48);
|
memcpy(ev.identityHash,peerIdentity.hash().data(),ZT_IDENTITY_HASH_SIZE);
|
||||||
physicalAddress.forTrace(ev.physicalAddress);
|
physicalAddress.forTrace(ev.physicalAddress);
|
||||||
replaced.forTrace(ev.replaced);
|
replaced.forTrace(ev.replaced);
|
||||||
|
|
||||||
|
@ -171,10 +171,10 @@ void Trace::_incomingPacketDropped(
|
||||||
ev.networkId = Utils::hton(networkId);
|
ev.networkId = Utils::hton(networkId);
|
||||||
if (peerIdentity) {
|
if (peerIdentity) {
|
||||||
ev.address = Utils::hton(peerIdentity.address().toInt());
|
ev.address = Utils::hton(peerIdentity.address().toInt());
|
||||||
memcpy(ev.identityHash,peerIdentity.hash(),48);
|
memcpy(ev.identityHash,peerIdentity.hash().data(),ZT_IDENTITY_HASH_SIZE);
|
||||||
} else {
|
} else {
|
||||||
ev.address = 0;
|
ev.address = 0;
|
||||||
memset(ev.identityHash,0,48);
|
memset(ev.identityHash,0,ZT_IDENTITY_HASH_SIZE);
|
||||||
}
|
}
|
||||||
physicalAddress.forTrace(ev.physicalAddress);
|
physicalAddress.forTrace(ev.physicalAddress);
|
||||||
ev.hops = hops;
|
ev.hops = hops;
|
||||||
|
|
104
node/VL1.cpp
104
node/VL1.cpp
|
@ -68,7 +68,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
||||||
// but we might as well avoid it. When the peer receives NOP on a path that hasn't been handshaked yet
|
// but we might as well avoid it. When the peer receives NOP on a path that hasn't been handshaked yet
|
||||||
// it will send its own HELLO to which we will respond with a fully encrypted OK(HELLO).
|
// it will send its own HELLO to which we will respond with a fully encrypted OK(HELLO).
|
||||||
if (len == ZT_PROTO_PROBE_LENGTH) {
|
if (len == ZT_PROTO_PROBE_LENGTH) {
|
||||||
const SharedPtr<Peer> peer(RR->topology->peerByProbe(Utils::loadAsIsEndian<uint64_t>(data->b)));
|
const SharedPtr<Peer> peer(RR->topology->peerByProbe(data->lI64(0)));
|
||||||
if ((peer)&&(peer->rateGateInboundProbe(now))) {
|
if ((peer)&&(peer->rateGateInboundProbe(now))) {
|
||||||
peer->sendNOP(tPtr,path->localSocket(),path->address(),now);
|
peer->sendNOP(tPtr,path->localSocket(),path->address(),now);
|
||||||
path->sent(now);
|
path->sent(now);
|
||||||
|
@ -90,7 +90,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
||||||
// Destination address of packet (filled below)
|
// Destination address of packet (filled below)
|
||||||
Address destination;
|
Address destination;
|
||||||
|
|
||||||
if (data->b[ZT_PROTO_PACKET_FRAGMENT_INDICATOR_INDEX] == ZT_PROTO_PACKET_FRAGMENT_INDICATOR) {
|
if (data->lI8(ZT_PROTO_PACKET_FRAGMENT_INDICATOR_INDEX) == ZT_PROTO_PACKET_FRAGMENT_INDICATOR) {
|
||||||
// Fragment -----------------------------------------------------------------------------------------------------
|
// Fragment -----------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
const Protocol::FragmentHeader &fragmentHeader = data->as<Protocol::FragmentHeader>();
|
const Protocol::FragmentHeader &fragmentHeader = data->as<Protocol::FragmentHeader>();
|
||||||
|
@ -234,7 +234,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
||||||
|
|
||||||
// Verify packet MAC.
|
// Verify packet MAC.
|
||||||
uint64_t mac[2];
|
uint64_t mac[2];
|
||||||
poly1305(mac,pkt.b->b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,macKey);
|
poly1305(mac,pkt.b->unsafeData + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,macKey);
|
||||||
if (ph->mac != mac[0]) {
|
if (ph->mac != mac[0]) {
|
||||||
RR->t->incomingPacketDropped(tPtr,0xcc89c812,ph->packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
RR->t->incomingPacketDropped(tPtr,0xcc89c812,ph->packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
||||||
return;
|
return;
|
||||||
|
@ -268,7 +268,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
||||||
for(i=0;i<prevOverflow;++i) {
|
for(i=0;i<prevOverflow;++i) {
|
||||||
if (s->s >= s->e)
|
if (s->s >= s->e)
|
||||||
goto next_slice;
|
goto next_slice;
|
||||||
ps->b->b[ps->e++] = s->b->b[s->s++]; // move from head of current to end of previous
|
ps->b->unsafeData[ps->e++] = s->b->unsafeData[s->s++]; // move from head of current to end of previous
|
||||||
}
|
}
|
||||||
next_slice: ps = s++;
|
next_slice: ps = s++;
|
||||||
}
|
}
|
||||||
|
@ -277,18 +277,18 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
||||||
// Simultaneously decrypt and assemble packet into a contiguous buffer.
|
// Simultaneously decrypt and assemble packet into a contiguous buffer.
|
||||||
// Since we moved data around above all slices will have sizes that are
|
// Since we moved data around above all slices will have sizes that are
|
||||||
// multiples of 64.
|
// multiples of 64.
|
||||||
memcpy(pkt.b->b,ph,sizeof(Protocol::Header));
|
memcpy(pkt.b->unsafeData,ph,sizeof(Protocol::Header));
|
||||||
pkt.e = sizeof(Protocol::Header);
|
pkt.e = sizeof(Protocol::Header);
|
||||||
for(FCV<Buf::Slice,ZT_MAX_PACKET_FRAGMENTS>::iterator s(pktv.begin());s!=pktv.end();++s) {
|
for(FCV<Buf::Slice,ZT_MAX_PACKET_FRAGMENTS>::iterator s(pktv.begin());s!=pktv.end();++s) {
|
||||||
const unsigned int sliceSize = s->e - s->s;
|
const unsigned int sliceSize = s->e - s->s;
|
||||||
s20.crypt12(s->b->b + s->s,pkt.b->b + pkt.e,sliceSize);
|
s20.crypt12(s->b->unsafeData + s->s,pkt.b->unsafeData + pkt.e,sliceSize);
|
||||||
pkt.e += sliceSize;
|
pkt.e += sliceSize;
|
||||||
}
|
}
|
||||||
ph = &(pkt.b->as<Protocol::Header>());
|
ph = &(pkt.b->as<Protocol::Header>());
|
||||||
|
|
||||||
// Verify packet MAC.
|
// Verify packet MAC.
|
||||||
uint64_t mac[2];
|
uint64_t mac[2];
|
||||||
poly1305(mac,pkt.b->b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,macKey);
|
poly1305(mac,pkt.b->unsafeData + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,macKey);
|
||||||
if (ph->mac != mac[0]) {
|
if (ph->mac != mac[0]) {
|
||||||
RR->t->incomingPacketDropped(tPtr,0xbc881231,ph->packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
RR->t->incomingPacketDropped(tPtr,0xbc881231,ph->packetId,0,peer->identity(),path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
||||||
return;
|
return;
|
||||||
|
@ -353,8 +353,8 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
||||||
|
|
||||||
SharedPtr<Buf> nb(new Buf());
|
SharedPtr<Buf> nb(new Buf());
|
||||||
const int uncompressedLen = LZ4_decompress_safe(
|
const int uncompressedLen = LZ4_decompress_safe(
|
||||||
reinterpret_cast<const char *>(pkt.b->b + ZT_PROTO_PACKET_PAYLOAD_START),
|
reinterpret_cast<const char *>(pkt.b->unsafeData + ZT_PROTO_PACKET_PAYLOAD_START),
|
||||||
reinterpret_cast<char *>(nb->b),
|
reinterpret_cast<char *>(nb->unsafeData),
|
||||||
(int)(packetSize - ZT_PROTO_PACKET_PAYLOAD_START),
|
(int)(packetSize - ZT_PROTO_PACKET_PAYLOAD_START),
|
||||||
ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START);
|
ZT_BUF_MEM_SIZE - ZT_PROTO_PACKET_PAYLOAD_START);
|
||||||
|
|
||||||
|
@ -402,7 +402,7 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
||||||
case Protocol::VERB_MULTICAST: ok = RR->vl2->_MULTICAST(tPtr,path,peer,*pkt.b,(int)packetSize); break;
|
case Protocol::VERB_MULTICAST: ok = RR->vl2->_MULTICAST(tPtr,path,peer,*pkt.b,(int)packetSize); break;
|
||||||
case Protocol::VERB_ENCAP: ok = _ENCAP(tPtr,path,peer,*pkt.b,(int)packetSize); break;
|
case Protocol::VERB_ENCAP: ok = _ENCAP(tPtr,path,peer,*pkt.b,(int)packetSize); break;
|
||||||
default:
|
default:
|
||||||
RR->t->incomingPacketDropped(tPtr,0xdeadeff0,ph->packetId,0,identityFromPeerPtr(peer),path->address(),hops,verb,ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB);
|
RR->t->incomingPacketDropped(tPtr,0xeeeeeff0,ph->packetId,0,identityFromPeerPtr(peer),path->address(),hops,verb,ZT_TRACE_PACKET_DROP_REASON_UNRECOGNIZED_VERB);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ok)
|
if (ok)
|
||||||
|
@ -414,10 +414,10 @@ void VL1::onRemotePacket(void *const tPtr,const int64_t localSocket,const InetAd
|
||||||
|
|
||||||
void VL1::_relay(void *tPtr,const SharedPtr<Path> &path,const Address &destination,SharedPtr<Buf> &data,unsigned int len)
|
void VL1::_relay(void *tPtr,const SharedPtr<Path> &path,const Address &destination,SharedPtr<Buf> &data,unsigned int len)
|
||||||
{
|
{
|
||||||
const uint8_t newHopCount = (data->b[ZT_PROTO_PACKET_FLAGS_INDEX] & 7U) + 1;
|
const uint8_t newHopCount = (data->lI8(ZT_PROTO_PACKET_FLAGS_INDEX) & 7U) + 1;
|
||||||
if (newHopCount >= ZT_RELAY_MAX_HOPS)
|
if (newHopCount >= ZT_RELAY_MAX_HOPS)
|
||||||
return;
|
return;
|
||||||
data->b[ZT_PROTO_PACKET_FLAGS_INDEX] = (data->b[ZT_PROTO_PACKET_FLAGS_INDEX] & 0xf8U) | newHopCount;
|
data->sI8(ZT_PROTO_PACKET_FLAGS_INDEX,(data->lI8(ZT_PROTO_PACKET_FLAGS_INDEX) & 0xf8U) | newHopCount);
|
||||||
|
|
||||||
const SharedPtr<Peer> toPeer(RR->topology->peer(tPtr,destination,false));
|
const SharedPtr<Peer> toPeer(RR->topology->peer(tPtr,destination,false));
|
||||||
if (!toPeer)
|
if (!toPeer)
|
||||||
|
@ -427,7 +427,7 @@ void VL1::_relay(void *tPtr,const SharedPtr<Path> &path,const Address &destinati
|
||||||
if (!toPath)
|
if (!toPath)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
toPath->send(RR,tPtr,data->b,len,now);
|
toPath->send(RR,tPtr,data->unsafeData,len,now);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VL1::_sendPendingWhois(void *const tPtr,const int64_t now)
|
void VL1::_sendPendingWhois(void *const tPtr,const int64_t now)
|
||||||
|
@ -467,15 +467,15 @@ void VL1::_sendPendingWhois(void *const tPtr,const int64_t now)
|
||||||
|
|
||||||
int outl = sizeof(Protocol::Header);
|
int outl = sizeof(Protocol::Header);
|
||||||
while ((a != toSend.end())&&(outl < ZT_PROTO_MAX_PACKET_LENGTH)) {
|
while ((a != toSend.end())&&(outl < ZT_PROTO_MAX_PACKET_LENGTH)) {
|
||||||
a->copyTo(outp.b + outl);
|
a->copyTo(outp.unsafeData + outl);
|
||||||
++a;
|
++a;
|
||||||
outl += ZT_ADDRESS_LENGTH;
|
outl += ZT_ADDRESS_LENGTH;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outl > sizeof(Protocol::Header)) {
|
if (outl > sizeof(Protocol::Header)) {
|
||||||
Protocol::armor(outp,outl,root->key(),peer->cipher());
|
Protocol::armor(outp,outl,root->key(),root->cipher());
|
||||||
RR->expect->sending(ph.packetId,now);
|
RR->expect->sending(ph.packetId,now);
|
||||||
rootPath->send(RR,tPtr,outp.b,outl,now);
|
rootPath->send(RR,tPtr,outp.unsafeData,outl,now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -525,7 +525,7 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Bu
|
||||||
Protocol::salsa2012DeriveKey(peer->key(),perPacketKey,pkt,packetSize);
|
Protocol::salsa2012DeriveKey(peer->key(),perPacketKey,pkt,packetSize);
|
||||||
Salsa20(perPacketKey,&p.h.packetId).crypt12(Utils::ZERO256,macKey,ZT_POLY1305_KEY_LEN);
|
Salsa20(perPacketKey,&p.h.packetId).crypt12(Utils::ZERO256,macKey,ZT_POLY1305_KEY_LEN);
|
||||||
uint64_t mac[2];
|
uint64_t mac[2];
|
||||||
poly1305(mac,pkt.b + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,macKey);
|
poly1305(mac,pkt.unsafeData + ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,packetSize - ZT_PROTO_PACKET_ENCRYPTED_SECTION_START,macKey);
|
||||||
if (p.h.mac != mac[0]) {
|
if (p.h.mac != mac[0]) {
|
||||||
RR->t->incomingPacketDropped(tPtr,0x11bfff81,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
RR->t->incomingPacketDropped(tPtr,0x11bfff81,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
||||||
return false;
|
return false;
|
||||||
|
@ -542,8 +542,8 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Bu
|
||||||
}
|
}
|
||||||
packetSize -= ZT_HMACSHA384_LEN;
|
packetSize -= ZT_HMACSHA384_LEN;
|
||||||
KBKDFHMACSHA384(key,ZT_PROTO_KDF_KEY_LABEL_HELLO_HMAC,0,0,hmacKey); // iter == 0 for HELLO, 1 for OK(HELLO)
|
KBKDFHMACSHA384(key,ZT_PROTO_KDF_KEY_LABEL_HELLO_HMAC,0,0,hmacKey); // iter == 0 for HELLO, 1 for OK(HELLO)
|
||||||
HMACSHA384(hmacKey,pkt.b,packetSize,hmac);
|
HMACSHA384(hmacKey,pkt.unsafeData,packetSize,hmac);
|
||||||
if (!Utils::secureEq(pkt.b + packetSize,hmac,ZT_HMACSHA384_LEN)) {
|
if (!Utils::secureEq(pkt.unsafeData + packetSize,hmac,ZT_HMACSHA384_LEN)) {
|
||||||
RR->t->incomingPacketDropped(tPtr,0x1000662a,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
RR->t->incomingPacketDropped(tPtr,0x1000662a,p.h.packetId,0,id,path->address(),hops,Protocol::VERB_NOP,ZT_TRACE_PACKET_DROP_REASON_MAC_FAILED);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -568,10 +568,10 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Bu
|
||||||
// can't even get ephemeral public keys without first knowing the long term secret key,
|
// can't even get ephemeral public keys without first knowing the long term secret key,
|
||||||
// adding a little defense in depth.
|
// adding a little defense in depth.
|
||||||
uint8_t iv[8];
|
uint8_t iv[8];
|
||||||
for (int i = 0; i < 8; ++i) iv[i] = pkt.b[i];
|
for (int i = 0; i < 8; ++i) iv[i] = pkt.unsafeData[i];
|
||||||
iv[7] &= 0xf8U; // this exists for pure legacy reasons, meh...
|
iv[7] &= 0xf8U; // this exists for pure legacy reasons, meh...
|
||||||
Salsa20 s20(key,iv);
|
Salsa20 s20(key,iv);
|
||||||
s20.crypt12(pkt.b + ptr,pkt.b + ptr,packetSize - ptr);
|
s20.crypt12(pkt.unsafeData + ptr,pkt.unsafeData + ptr,packetSize - ptr);
|
||||||
|
|
||||||
ptr += pkt.rI16(ptr); // skip length field which currently is always zero in v2.0+
|
ptr += pkt.rI16(ptr); // skip length field which currently is always zero in v2.0+
|
||||||
|
|
||||||
|
@ -654,23 +654,23 @@ bool VL1::_HELLO(void *tPtr,const SharedPtr<Path> &path,SharedPtr<Peer> &peer,Bu
|
||||||
int outl = sizeof(Protocol::OK::HELLO);
|
int outl = sizeof(Protocol::OK::HELLO);
|
||||||
outp.wO(outl,path->address());
|
outp.wO(outl,path->address());
|
||||||
|
|
||||||
outp.wI(outl,(uint16_t)0); // legacy field, always 0
|
outp.wI16(outl,0); // legacy field, always 0
|
||||||
|
|
||||||
if (p.versionProtocol >= 11) {
|
if (p.versionProtocol >= 11) {
|
||||||
outp.wI(outl,(uint16_t)myNodeMetaDataBin.size());
|
outp.wI16(outl,(uint16_t)myNodeMetaDataBin.size());
|
||||||
outp.wB(outl,myNodeMetaDataBin.data(),(unsigned int)myNodeMetaDataBin.size());
|
outp.wB(outl,myNodeMetaDataBin.data(),(unsigned int)myNodeMetaDataBin.size());
|
||||||
outp.wI(outl,(uint16_t)0); // length of additional fields, currently 0
|
outp.wI16(outl,0); // length of additional fields, currently 0
|
||||||
|
|
||||||
if ((outl + ZT_HMACSHA384_LEN) > ZT_PROTO_MAX_PACKET_LENGTH) // sanity check, shouldn't be possible
|
if ((outl + ZT_HMACSHA384_LEN) > ZT_PROTO_MAX_PACKET_LENGTH) // sanity check, shouldn't be possible
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
KBKDFHMACSHA384(key,ZT_PROTO_KDF_KEY_LABEL_HELLO_HMAC,0,1,hmacKey); // iter == 1 for OK
|
KBKDFHMACSHA384(key,ZT_PROTO_KDF_KEY_LABEL_HELLO_HMAC,0,1,hmacKey); // iter == 1 for OK
|
||||||
HMACSHA384(hmacKey,outp.b + sizeof(ok.h),outl - sizeof(ok.h),outp.b + outl);
|
HMACSHA384(hmacKey,outp.unsafeData + sizeof(ok.h),outl - sizeof(ok.h),outp.unsafeData + outl);
|
||||||
outl += ZT_HMACSHA384_LEN;
|
outl += ZT_HMACSHA384_LEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
Protocol::armor(outp,outl,peer->key(),peer->cipher());
|
Protocol::armor(outp,outl,peer->key(),peer->cipher());
|
||||||
path->send(RR,tPtr,outp.b,outl,now);
|
path->send(RR,tPtr,outp.unsafeData,outl,now);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -781,7 +781,7 @@ bool VL1::_WHOIS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &p
|
||||||
|
|
||||||
int outl = sizeof(Protocol::OK::WHOIS);
|
int outl = sizeof(Protocol::OK::WHOIS);
|
||||||
while ( ((ptr + ZT_ADDRESS_LENGTH) <= packetSize) && ((outl + ZT_IDENTITY_MARSHAL_SIZE_MAX + ZT_LOCATOR_MARSHAL_SIZE_MAX) < ZT_PROTO_MAX_PACKET_LENGTH) ) {
|
while ( ((ptr + ZT_ADDRESS_LENGTH) <= packetSize) && ((outl + ZT_IDENTITY_MARSHAL_SIZE_MAX + ZT_LOCATOR_MARSHAL_SIZE_MAX) < ZT_PROTO_MAX_PACKET_LENGTH) ) {
|
||||||
const SharedPtr<Peer> &wp(RR->topology->peer(tPtr,Address(pkt.b + ptr)));
|
const SharedPtr<Peer> &wp(RR->topology->peer(tPtr,Address(pkt.unsafeData + ptr)));
|
||||||
if (wp) {
|
if (wp) {
|
||||||
outp.wO(outl,wp->identity());
|
outp.wO(outl,wp->identity());
|
||||||
if (peer->remoteVersionProtocol() >= 11) { // older versions don't know what a locator is
|
if (peer->remoteVersionProtocol() >= 11) { // older versions don't know what a locator is
|
||||||
|
@ -798,7 +798,7 @@ bool VL1::_WHOIS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &p
|
||||||
|
|
||||||
if (outl > sizeof(Protocol::OK::WHOIS)) {
|
if (outl > sizeof(Protocol::OK::WHOIS)) {
|
||||||
Protocol::armor(outp,outl,peer->key(),peer->cipher());
|
Protocol::armor(outp,outl,peer->key(),peer->cipher());
|
||||||
path->send(RR,tPtr,outp.b,outl,RR->node->now());
|
path->send(RR,tPtr,outp.unsafeData,outl,RR->node->now());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -823,28 +823,27 @@ bool VL1::_RENDEZVOUS(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Pee
|
||||||
case 4:
|
case 4:
|
||||||
case 16:
|
case 16:
|
||||||
if ((sizeof(Protocol::RENDEZVOUS) + rdv.addressLength) <= packetSize) {
|
if ((sizeof(Protocol::RENDEZVOUS) + rdv.addressLength) <= packetSize) {
|
||||||
const InetAddress atAddr(pkt.b + sizeof(Protocol::RENDEZVOUS),rdv.addressLength,port);
|
const InetAddress atAddr(pkt.unsafeData + sizeof(Protocol::RENDEZVOUS),rdv.addressLength,port);
|
||||||
peer->contact(tPtr,Endpoint(atAddr),now,false,false);
|
peer->contact(tPtr,Endpoint(atAddr),now,false);
|
||||||
RR->t->tryingNewPath(tPtr,0x55a19aaa,with->identity(),atAddr,path->address(),Protocol::packetId(pkt,packetSize),Protocol::VERB_RENDEZVOUS,peer->address(),peer->identity().hash(),ZT_TRACE_TRYING_NEW_PATH_REASON_RENDEZVOUS);
|
RR->t->tryingNewPath(tPtr,0x55a19aaa,with->identity(),atAddr,path->address(),Protocol::packetId(pkt,packetSize),Protocol::VERB_RENDEZVOUS,peer->address(),peer->identity().hash().data(),ZT_TRACE_TRYING_NEW_PATH_REASON_RENDEZVOUS);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 255:
|
case 255: {
|
||||||
if ((sizeof(Protocol::RENDEZVOUS) + 1) <= packetSize) {
|
|
||||||
Endpoint ep;
|
Endpoint ep;
|
||||||
int epl = ep.unmarshal(pkt.b + sizeof(Protocol::RENDEZVOUS),packetSize - (int)sizeof(Protocol::RENDEZVOUS));
|
int p = sizeof(Protocol::RENDEZVOUS);
|
||||||
if ((epl > 0) && (ep)) {
|
int epl = pkt.rO(p,ep);
|
||||||
|
if ((epl > 0) && (ep) && (!Buf::readOverflow(p,packetSize))) {
|
||||||
switch (ep.type()) {
|
switch (ep.type()) {
|
||||||
case Endpoint::INETADDR_V4:
|
case Endpoint::TYPE_INETADDR_V4:
|
||||||
case Endpoint::INETADDR_V6:
|
case Endpoint::TYPE_INETADDR_V6:
|
||||||
peer->contact(tPtr,ep,now,false,false);
|
peer->contact(tPtr,ep,now,false);
|
||||||
RR->t->tryingNewPath(tPtr,0x55a19aab,with->identity(),ep.inetAddr(),path->address(),Protocol::packetId(pkt,packetSize),Protocol::VERB_RENDEZVOUS,peer->address(),peer->identity().hash(),ZT_TRACE_TRYING_NEW_PATH_REASON_RENDEZVOUS);
|
RR->t->tryingNewPath(tPtr,0x55a19aab,with->identity(),ep.inetAddr(),path->address(),Protocol::packetId(pkt,packetSize),Protocol::VERB_RENDEZVOUS,peer->address(),peer->identity().hash().data(),ZT_TRACE_TRYING_NEW_PATH_REASON_RENDEZVOUS);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} break;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -872,7 +871,7 @@ bool VL1::_ECHO(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &pe
|
||||||
outh.h.inReVerb = Protocol::VERB_ECHO;
|
outh.h.inReVerb = Protocol::VERB_ECHO;
|
||||||
outh.h.inRePacketId = packetId;
|
outh.h.inRePacketId = packetId;
|
||||||
int outl = sizeof(Protocol::OK::ECHO);
|
int outl = sizeof(Protocol::OK::ECHO);
|
||||||
outp.wB(outl,pkt.b + sizeof(Protocol::Header),packetSize - sizeof(Protocol::Header));
|
outp.wB(outl,pkt.unsafeData + sizeof(Protocol::Header),packetSize - sizeof(Protocol::Header));
|
||||||
|
|
||||||
if (Buf::writeOverflow(outl)) {
|
if (Buf::writeOverflow(outl)) {
|
||||||
RR->t->incomingPacketDropped(tPtr,0x14d70bb0,packetId,0,peer->identity(),path->address(),Protocol::packetHops(pkt,packetSize),Protocol::VERB_ECHO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
RR->t->incomingPacketDropped(tPtr,0x14d70bb0,packetId,0,peer->identity(),path->address(),Protocol::packetHops(pkt,packetSize),Protocol::VERB_ECHO,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||||
|
@ -880,7 +879,7 @@ bool VL1::_ECHO(void *tPtr,const SharedPtr<Path> &path,const SharedPtr<Peer> &pe
|
||||||
}
|
}
|
||||||
|
|
||||||
Protocol::armor(outp,outl,peer->key(),peer->cipher());
|
Protocol::armor(outp,outl,peer->key(),peer->cipher());
|
||||||
path->send(RR,tPtr,outp.b,outl,now);
|
path->send(RR,tPtr,outp.unsafeData,outl,now);
|
||||||
} else {
|
} else {
|
||||||
RR->t->incomingPacketDropped(tPtr,0x27878bc1,packetId,0,peer->identity(),path->address(),Protocol::packetHops(pkt,packetSize),Protocol::VERB_ECHO,ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED);
|
RR->t->incomingPacketDropped(tPtr,0x27878bc1,packetId,0,peer->identity(),path->address(),Protocol::packetHops(pkt,packetSize),Protocol::VERB_ECHO,ZT_TRACE_PACKET_DROP_REASON_RATE_LIMIT_EXCEEDED);
|
||||||
}
|
}
|
||||||
|
@ -908,13 +907,21 @@ bool VL1::_PUSH_DIRECT_PATHS(void *tPtr,const SharedPtr<Path> &path,const Shared
|
||||||
Endpoint ep;
|
Endpoint ep;
|
||||||
for(unsigned int pi=0;pi<numPaths;++pi) {
|
for(unsigned int pi=0;pi<numPaths;++pi) {
|
||||||
/*const uint8_t flags = pkt.rI8(ptr);*/ ++ptr; // flags are not presently used
|
/*const uint8_t flags = pkt.rI8(ptr);*/ ++ptr; // flags are not presently used
|
||||||
ptr += pkt.rI16(ptr); // extended attributes size, currently always 0
|
|
||||||
|
const int xas = (int)pkt.rI16(ptr);
|
||||||
|
//const uint8_t *const extendedAttrs = pkt.rBnc(ptr,xas);
|
||||||
|
ptr += xas;
|
||||||
|
|
||||||
const unsigned int addrType = pkt.rI8(ptr);
|
const unsigned int addrType = pkt.rI8(ptr);
|
||||||
const unsigned int addrRecordLen = pkt.rI8(ptr);
|
const unsigned int addrRecordLen = pkt.rI8(ptr);
|
||||||
if (addrRecordLen == 0) {
|
if (addrRecordLen == 0) {
|
||||||
RR->t->incomingPacketDropped(tPtr,0xaed00118,pdp.h.packetId,0,peer->identity(),path->address(),Protocol::packetHops(pdp.h),Protocol::VERB_PUSH_DIRECT_PATHS,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
RR->t->incomingPacketDropped(tPtr,0xaed00118,pdp.h.packetId,0,peer->identity(),path->address(),Protocol::packetHops(pdp.h),Protocol::VERB_PUSH_DIRECT_PATHS,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (Buf::readOverflow(ptr,packetSize)) {
|
||||||
|
RR->t->incomingPacketDropped(tPtr,0xb450e10f,pdp.h.packetId,0,peer->identity(),path->address(),Protocol::packetHops(pdp.h),Protocol::VERB_PUSH_DIRECT_PATHS,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
const void *addrBytes = nullptr;
|
const void *addrBytes = nullptr;
|
||||||
unsigned int addrLen = 0;
|
unsigned int addrLen = 0;
|
||||||
|
@ -934,11 +941,14 @@ bool VL1::_PUSH_DIRECT_PATHS(void *tPtr,const SharedPtr<Path> &path,const Shared
|
||||||
addrLen = 16;
|
addrLen = 16;
|
||||||
addrPort = pkt.rI16(ptr);
|
addrPort = pkt.rI16(ptr);
|
||||||
break;
|
break;
|
||||||
|
//case 200:
|
||||||
|
// TODO: this would be a WebRTC SDP offer contained in the extended attrs field
|
||||||
|
//break;
|
||||||
default: break;
|
default: break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Buf::readOverflow(ptr,packetSize)) {
|
if (Buf::readOverflow(ptr,packetSize)) {
|
||||||
RR->t->incomingPacketDropped(tPtr,0xbad0f10f,pdp.h.packetId,0,peer->identity(),path->address(),Protocol::packetHops(pdp.h),Protocol::VERB_PUSH_DIRECT_PATHS,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
RR->t->incomingPacketDropped(tPtr,0xb4d0f10f,pdp.h.packetId,0,peer->identity(),path->address(),Protocol::packetHops(pdp.h),Protocol::VERB_PUSH_DIRECT_PATHS,ZT_TRACE_PACKET_DROP_REASON_MALFORMED_PACKET);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -951,8 +961,8 @@ bool VL1::_PUSH_DIRECT_PATHS(void *tPtr,const SharedPtr<Path> &path,const Shared
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(ep.type()) {
|
switch(ep.type()) {
|
||||||
case Endpoint::INETADDR_V4:
|
case Endpoint::TYPE_INETADDR_V4:
|
||||||
case Endpoint::INETADDR_V6:
|
case Endpoint::TYPE_INETADDR_V6:
|
||||||
a = ep.inetAddr();
|
a = ep.inetAddr();
|
||||||
break;
|
break;
|
||||||
default: // other types are not supported yet
|
default: // other types are not supported yet
|
||||||
|
|
Loading…
Add table
Reference in a new issue