More porting to new Buf system.

This commit is contained in:
Adam Ierymenko 2020-01-24 23:36:08 -08:00
parent 91ce4c4ea6
commit 59da359b06
No known key found for this signature in database
GPG key ID: C8877CF2D7A5D7F3
22 changed files with 607 additions and 747 deletions

View file

@ -51,7 +51,10 @@ set(core_src
Buf.cpp
C25519.cpp
Capability.cpp
CertificateOfMembership.cpp
CertificateOfOwnership.cpp
Credential.cpp
Dictionary.cpp
ECC384.cpp
Endpoint.cpp
Identity.cpp

View file

@ -0,0 +1,139 @@
/*
* 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.
*/
/****/
#include "CertificateOfMembership.hpp"
namespace ZeroTier {
CertificateOfMembership::CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Address &issuedTo)
{
_qualifiers[0].id = COM_RESERVED_ID_TIMESTAMP;
_qualifiers[0].value = timestamp;
_qualifiers[0].maxDelta = timestampMaxDelta;
_qualifiers[1].id = COM_RESERVED_ID_NETWORK_ID;
_qualifiers[1].value = nwid;
_qualifiers[1].maxDelta = 0;
_qualifiers[2].id = COM_RESERVED_ID_ISSUED_TO;
_qualifiers[2].value = issuedTo.toInt();
_qualifiers[2].maxDelta = 0xffffffffffffffffULL;
_qualifierCount = 3;
_signatureLength = 0;
}
void CertificateOfMembership::setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta)
{
_signedBy.zero();
for(unsigned int i=0;i<_qualifierCount;++i) {
if (_qualifiers[i].id == id) {
_qualifiers[i].value = value;
_qualifiers[i].maxDelta = maxDelta;
return;
}
}
if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) {
_qualifiers[_qualifierCount].id = id;
_qualifiers[_qualifierCount].value = value;
_qualifiers[_qualifierCount].maxDelta = maxDelta;
++_qualifierCount;
std::sort(&(_qualifiers[0]),&(_qualifiers[_qualifierCount]));
}
}
bool CertificateOfMembership::sign(const Identity &with)
{
uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
unsigned int ptr = 0;
for(unsigned int i=0;i<_qualifierCount;++i) {
buf[ptr++] = Utils::hton(_qualifiers[i].id);
buf[ptr++] = Utils::hton(_qualifiers[i].value);
buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
}
try {
_signatureLength = with.sign(buf,ptr * sizeof(uint64_t),_signature,sizeof(_signature));
_signedBy = with.address();
return true;
} catch ( ... ) {
_signedBy.zero();
return false;
}
}
int CertificateOfMembership::marshal(uint8_t data[ZT_CERTIFICATEOFMEMBERSHIP_MARSHAL_SIZE_MAX]) const
{
data[0] = 1;
Utils::storeBigEndian<uint16_t>(data + 1,(uint16_t)_qualifierCount);
int p = 3;
for(unsigned int i=0;i<_qualifierCount;++i) {
Utils::storeBigEndian<uint64_t>(data + p,_qualifiers[i].id); p += 8;
Utils::storeBigEndian<uint64_t>(data + p,_qualifiers[i].value); p += 8;
Utils::storeBigEndian<uint64_t>(data + p,_qualifiers[i].maxDelta); p += 8;
}
_signedBy.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
if ((_signedBy)&&(_signatureLength == 96)) {
// UGLY: Ed25519 signatures in ZT are 96 bytes (64 + 32 bytes of hash).
// P-384 signatures are also 96 bytes, praise the horned one. That means
// we don't need to include a length. If we ever do we will need a new
// serialized object version, but only for those with length != 96.
memcpy(data + p,_signature,96); p += 96;
}
return p;
}
int CertificateOfMembership::unmarshal(const uint8_t *data,int len)
{
if ((len < 3)||(data[0] != 1))
return -1;
unsigned int numq = Utils::loadBigEndian<uint16_t>(data + 1);
if (numq > ZT_NETWORK_COM_MAX_QUALIFIERS)
return -1;
_qualifierCount = numq;
int p = 3;
for(unsigned int i=0;i<numq;++i) {
if ((p + 24) > len)
return -1;
_qualifiers[i].id = Utils::loadBigEndian<uint64_t>(data + p); p += 8;
_qualifiers[i].value = Utils::loadBigEndian<uint64_t>(data + p); p += 8;
_qualifiers[i].maxDelta = Utils::loadBigEndian<uint64_t>(data + p); p += 8;
}
if ((p + ZT_ADDRESS_LENGTH) > len)
return -1;
_signedBy.setTo(data + p); p += ZT_ADDRESS_LENGTH;
if (_signedBy) {
if ((p + 96) > len)
return -1;
_signatureLength = 96;
memcpy(_signature,data + p,96);
p += 96;
}
return p;
}
bool CertificateOfMembership::operator==(const CertificateOfMembership &c) const
{
if (_signedBy != c._signedBy)
return false;
if (_qualifierCount != c._qualifierCount)
return false;
if (_signatureLength != c._signatureLength)
return false;
for(unsigned int i=0;i<_qualifierCount;++i) {
const _Qualifier &a = _qualifiers[i];
const _Qualifier &b = c._qualifiers[i];
if ((a.id != b.id)||(a.value != b.value)||(a.maxDelta != b.maxDelta))
return false;
}
return (memcmp(_signature,c._signature,_signatureLength) == 0);
}
} // namespace ZeroTier

View file

@ -23,7 +23,6 @@
#include "Constants.hpp"
#include "Credential.hpp"
#include "Buffer.hpp"
#include "Address.hpp"
#include "C25519.hpp"
#include "Identity.hpp"
@ -34,6 +33,8 @@
*/
#define ZT_NETWORK_COM_MAX_QUALIFIERS 8
#define ZT_CERTIFICATEOFMEMBERSHIP_MARSHAL_SIZE_MAX (1 + 2 + (24 * ZT_NETWORK_COM_MAX_QUALIFIERS) + 5 + ZT_SIGNATURE_BUFFER_SIZE)
namespace ZeroTier {
class RuntimeEnvironment;
@ -113,29 +114,7 @@ public:
* @param nwid Network ID
* @param issuedTo Certificate recipient
*/
ZT_ALWAYS_INLINE CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Address &issuedTo)
{
_qualifiers[0].id = COM_RESERVED_ID_TIMESTAMP;
_qualifiers[0].value = timestamp;
_qualifiers[0].maxDelta = timestampMaxDelta;
_qualifiers[1].id = COM_RESERVED_ID_NETWORK_ID;
_qualifiers[1].value = nwid;
_qualifiers[1].maxDelta = 0;
_qualifiers[2].id = COM_RESERVED_ID_ISSUED_TO;
_qualifiers[2].value = issuedTo.toInt();
_qualifiers[2].maxDelta = 0xffffffffffffffffULL;
_qualifierCount = 3;
_signatureLength = 0;
}
/**
* Create from binary-serialized COM in buffer
*
* @param b Buffer to deserialize from
* @param startAt Position to start in buffer
*/
template<unsigned int C>
ZT_ALWAYS_INLINE CertificateOfMembership(const Buffer<C> &b,unsigned int startAt = 0) { deserialize(b,startAt); }
CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Address &issuedTo);
/**
* @return True if there's something here
@ -192,24 +171,7 @@ public:
* @param value Qualifier value
* @param maxDelta Qualifier maximum allowed difference (absolute value of difference)
*/
ZT_ALWAYS_INLINE void setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta)
{
_signedBy.zero();
for(unsigned int i=0;i<_qualifierCount;++i) {
if (_qualifiers[i].id == id) {
_qualifiers[i].value = value;
_qualifiers[i].maxDelta = maxDelta;
return;
}
}
if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) {
_qualifiers[_qualifierCount].id = id;
_qualifiers[_qualifierCount].value = value;
_qualifiers[_qualifierCount].maxDelta = maxDelta;
++_qualifierCount;
std::sort(&(_qualifiers[0]),&(_qualifiers[_qualifierCount]));
}
}
void setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta);
ZT_ALWAYS_INLINE void setQualifier(ReservedId id,uint64_t value,uint64_t maxDelta) { setQualifier((uint64_t)id,value,maxDelta); }
@ -268,25 +230,7 @@ public:
* @param with Identity to sign with, must include private key
* @return True if signature was successful
*/
ZT_ALWAYS_INLINE bool sign(const Identity &with)
{
uint64_t buf[ZT_NETWORK_COM_MAX_QUALIFIERS * 3];
unsigned int ptr = 0;
for(unsigned int i=0;i<_qualifierCount;++i) {
buf[ptr++] = Utils::hton(_qualifiers[i].id);
buf[ptr++] = Utils::hton(_qualifiers[i].value);
buf[ptr++] = Utils::hton(_qualifiers[i].maxDelta);
}
try {
_signatureLength = with.sign(buf,ptr * sizeof(uint64_t),_signature,sizeof(_signature));
_signedBy = with.address();
return true;
} catch ( ... ) {
_signedBy.zero();
return false;
}
}
bool sign(const Identity &with);
/**
* Verify this COM and its signature
@ -301,95 +245,21 @@ public:
*/
ZT_ALWAYS_INLINE const Address &signedBy() const { return _signedBy; }
template<unsigned int C>
inline void serialize(Buffer<C> &b) const
{
b.append((uint8_t)1);
b.append((uint16_t)_qualifierCount);
for(unsigned int i=0;i<_qualifierCount;++i) {
b.append(_qualifiers[i].id);
b.append(_qualifiers[i].value);
b.append(_qualifiers[i].maxDelta);
}
_signedBy.appendTo(b);
if ((_signedBy)&&(_signatureLength == 96)) {
// UGLY: Ed25519 signatures in ZT are 96 bytes (64 + 32 bytes of hash).
// P-384 signatures are also 96 bytes, praise the horned one. That means
// we don't need to include a length. If we ever do we will need a new
// serialized object version, but only for those with length != 96.
b.append(_signature,96);
}
}
static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_CERTIFICATEOFMEMBERSHIP_MARSHAL_SIZE_MAX; }
int marshal(uint8_t data[ZT_CERTIFICATEOFMEMBERSHIP_MARSHAL_SIZE_MAX]) const;
int unmarshal(const uint8_t *data,int len);
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{
unsigned int p = startAt;
_signedBy.zero();
_qualifierCount = 0;
_signatureLength = 0;
if (b[p++] != 1)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
unsigned int numq = b.template at<uint16_t>(p); p += sizeof(uint16_t);
uint64_t lastId = 0;
for(unsigned int i=0;i<numq;++i) {
const uint64_t qid = b.template at<uint64_t>(p);
if (qid < lastId)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING;
else lastId = qid;
if (_qualifierCount < ZT_NETWORK_COM_MAX_QUALIFIERS) {
_qualifiers[_qualifierCount].id = qid;
_qualifiers[_qualifierCount].value = b.template at<uint64_t>(p + 8);
_qualifiers[_qualifierCount].maxDelta = b.template at<uint64_t>(p + 16);
p += 24;
++_qualifierCount;
} else {
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
}
}
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
if (_signedBy) {
// See "UGLY" comment in serialize()...
_signatureLength = 96;
memcpy(_signature,b.field(p,96),96);
p += 96;
}
return (p - startAt);
}
ZT_ALWAYS_INLINE bool operator==(const CertificateOfMembership &c) const
{
if (_signedBy != c._signedBy)
return false;
if (_qualifierCount != c._qualifierCount)
return false;
if (_signatureLength != c._signatureLength)
return false;
for(unsigned int i=0;i<_qualifierCount;++i) {
const _Qualifier &a = _qualifiers[i];
const _Qualifier &b = c._qualifiers[i];
if ((a.id != b.id)||(a.value != b.value)||(a.maxDelta != b.maxDelta))
return false;
}
return (memcmp(_signature,c._signature,_signatureLength) == 0);
}
bool operator==(const CertificateOfMembership &c) const;
ZT_ALWAYS_INLINE bool operator!=(const CertificateOfMembership &c) const { return (!(*this == c)); }
private:
struct _Qualifier
{
_Qualifier() : id(0),value(0),maxDelta(0) {}
ZT_ALWAYS_INLINE _Qualifier() : id(0),value(0),maxDelta(0) {}
uint64_t id;
uint64_t value;
uint64_t maxDelta;
inline bool operator<(const _Qualifier &q) const { return (id < q.id); } // sort order
ZT_ALWAYS_INLINE bool operator<(const _Qualifier &q) const { return (id < q.id); } // sort order
};
Address _signedBy;

View file

@ -0,0 +1,118 @@
/*
* 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.
*/
/****/
#include "CertificateOfOwnership.hpp"
namespace ZeroTier {
void CertificateOfOwnership::addThing(const InetAddress &ip)
{
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
if (ip.ss_family == AF_INET) {
_thingTypes[_thingCount] = THING_IPV4_ADDRESS;
memcpy(_thingValues[_thingCount],&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
++_thingCount;
} else if (ip.ss_family == AF_INET6) {
_thingTypes[_thingCount] = THING_IPV6_ADDRESS;
memcpy(_thingValues[_thingCount],reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr,16);
++_thingCount;
}
}
void CertificateOfOwnership::addThing(const MAC &mac)
{
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
_thingTypes[_thingCount] = THING_MAC_ADDRESS;
mac.copyTo(_thingValues[_thingCount],6);
++_thingCount;
}
bool CertificateOfOwnership::sign(const Identity &signer)
{
uint8_t buf[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX + 16];
if (signer.hasPrivate()) {
_signedBy = signer.address();
_signatureLength = signer.sign(buf,(unsigned int)marshal(buf,true),_signature,sizeof(_signature));
return true;
}
return false;
}
int CertificateOfOwnership::marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX],bool forSign) const
{
int p = 0;
if (forSign) {
for(int k=0;k<16;++k)
data[p++] = 0x7f;
}
Utils::storeBigEndian<uint64_t>(data + p,_networkId);
Utils::storeBigEndian<uint64_t>(data + p + 8,(uint64_t)_ts);
Utils::storeBigEndian<uint64_t>(data + p + 16,_flags);
Utils::storeBigEndian<uint32_t>(data + p + 24,_id);
Utils::storeBigEndian<uint16_t>(data + p + 28,(uint16_t)_thingCount);
p += 30;
for(unsigned int i=0,j=_thingCount;i<j;++i) {
data[p++] = _thingTypes[i];
memcpy(data + p,_thingValues[i],ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE;
}
_issuedTo.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
_signedBy.copyTo(data + p); p += ZT_ADDRESS_LENGTH;
if (!forSign) {
data[p++] = 1;
Utils::storeBigEndian<uint16_t>(data + p,(uint16_t)_signatureLength); p += 2;
memcpy(data + p,_signature,_signatureLength); p += (int)_signatureLength;
}
data[p++] = 0;
data[p++] = 0;
if (forSign) {
for(int k=0;k<16;++k)
data[p++] = 0x7f;
}
return p;
}
int CertificateOfOwnership::unmarshal(const uint8_t *data,int len)
{
if (len < 30)
return -1;
_networkId = Utils::loadBigEndian<uint64_t>(data);
_ts = (int64_t)Utils::loadBigEndian<uint64_t>(data + 8);
_flags = Utils::loadBigEndian<uint64_t>(data + 16);
_id = Utils::loadBigEndian<uint32_t>(data + 24);
_thingCount = Utils::loadBigEndian<uint16_t>(data + 28);
if (_thingCount > ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS)
return -1;
int p = 30;
for(unsigned int i=0,j=_thingCount;i<j;++i) {
if ((p + 1 + ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE) > len)
return -1;
_thingTypes[i] = data[p++];
memcpy(_thingValues[i],data + p,ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE;
}
if ((p + ZT_ADDRESS_LENGTH + ZT_ADDRESS_LENGTH + 1 + 2) > len)
return -1;
_issuedTo.setTo(data + p); p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(data + p); p += ZT_ADDRESS_LENGTH + 1;
p += 2 + Utils::loadBigEndian<uint16_t>(data + p);
if (p > len)
return -1;
return p;
}
} // namespace ZeroTier

View file

@ -24,7 +24,6 @@
#include "C25519.hpp"
#include "Address.hpp"
#include "Identity.hpp"
#include "Buffer.hpp"
#include "InetAddress.hpp"
#include "MAC.hpp"
@ -34,6 +33,8 @@
// Maximum size of a thing's value field in bytes
#define ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE 16
#define ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX (8 + 8 + 8 + 4 + 2 + ((1 + ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE) * ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) + 5 + 5 + 1 + 2 + ZT_SIGNATURE_BUFFER_SIZE + 2)
namespace ZeroTier {
class RuntimeEnvironment;
@ -98,112 +99,20 @@ public:
return this->_owns(THING_MAC_ADDRESS,tmp,6);
}
ZT_ALWAYS_INLINE void addThing(const InetAddress &ip)
{
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
if (ip.ss_family == AF_INET) {
_thingTypes[_thingCount] = THING_IPV4_ADDRESS;
memcpy(_thingValues[_thingCount],&(reinterpret_cast<const struct sockaddr_in *>(&ip)->sin_addr.s_addr),4);
++_thingCount;
} else if (ip.ss_family == AF_INET6) {
_thingTypes[_thingCount] = THING_IPV6_ADDRESS;
memcpy(_thingValues[_thingCount],reinterpret_cast<const struct sockaddr_in6 *>(&ip)->sin6_addr.s6_addr,16);
++_thingCount;
}
}
ZT_ALWAYS_INLINE void addThing(const MAC &mac)
{
if (_thingCount >= ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) return;
_thingTypes[_thingCount] = THING_MAC_ADDRESS;
mac.copyTo(_thingValues[_thingCount],6);
++_thingCount;
}
void addThing(const InetAddress &ip);
void addThing(const MAC &mac);
/**
* @param signer Signing identity, must have private key
* @return True if signature was successful
*/
ZT_ALWAYS_INLINE bool sign(const Identity &signer)
{
if (signer.hasPrivate()) {
Buffer<sizeof(CertificateOfOwnership) + 64> tmp;
_signedBy = signer.address();
this->serialize(tmp,true);
_signatureLength = signer.sign(tmp.data(),tmp.size(),_signature,sizeof(_signature));
return true;
}
return false;
}
bool sign(const Identity &signer);
ZT_ALWAYS_INLINE Credential::VerifyResult verify(const RuntimeEnvironment *RR,void *tPtr) const { return _verify(RR,tPtr,*this); }
template<unsigned int C>
inline void serialize(Buffer<C> &b,const bool forSign = false) const
{
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
b.append(_networkId);
b.append(_ts);
b.append(_flags);
b.append(_id);
b.append((uint16_t)_thingCount);
for(unsigned int i=0,j=_thingCount;i<j;++i) {
b.append((uint8_t)_thingTypes[i]);
b.append(_thingValues[i],ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
}
_issuedTo.appendTo(b);
_signedBy.appendTo(b);
if (!forSign) {
b.append((uint8_t)1);
b.append((uint16_t)_signatureLength); // length of signature
b.append(_signature,_signatureLength);
}
b.append((uint16_t)0); // length of additional fields, currently 0
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{
unsigned int p = startAt;
*this = CertificateOfOwnership();
_networkId = b.template at<uint64_t>(p); p += 8;
_ts = b.template at<uint64_t>(p); p += 8;
_flags = b.template at<uint64_t>(p); p += 8;
_id = b.template at<uint32_t>(p); p += 4;
_thingCount = b.template at<uint16_t>(p); p += 2;
for(unsigned int i=0,j=_thingCount;i<j;++i) {
if (i < ZT_CERTIFICATEOFOWNERSHIP_MAX_THINGS) {
_thingTypes[i] = (uint8_t)b[p++];
memcpy(_thingValues[i],b.field(p,ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE),ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE);
p += ZT_CERTIFICATEOFOWNERSHIP_MAX_THING_VALUE_SIZE;
}
}
_issuedTo.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
if (b[p++] == 1) {
_signatureLength = b.template at<uint16_t>(p);
if (_signatureLength > sizeof(_signature))
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
p += 2;
memcpy(_signature,b.field(p,_signatureLength),_signatureLength); p += _signatureLength;
} else {
p += 2 + b.template at<uint16_t>(p);
}
p += 2 + b.template at<uint16_t>(p);
if (p > b.size())
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_OVERFLOW;
return (p - startAt);
}
static ZT_ALWAYS_INLINE int marshalSizeMax() { return ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX; }
int marshal(uint8_t data[ZT_CERTIFICATEOFOWNERSHIP_MARSHAL_SIZE_MAX],bool forSign = false) const;
int unmarshal(const uint8_t *data,int len);
// Provides natural sort order by ID
ZT_ALWAYS_INLINE bool operator<(const CertificateOfOwnership &coo) const { return (_id < coo._id); }

224
node/Dictionary.cpp Normal file
View file

@ -0,0 +1,224 @@
/*
* 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.
*/
/****/
#include "Dictionary.hpp"
namespace ZeroTier {
Dictionary::Dictionary(const char *s,unsigned int len)
{
for(unsigned int i=0;i<ZT_DICTIONARY_MAX_CAPACITY;++i) {
if ((s)&&(i < len)) {
if (!(_d[i] = *s))
s = (const char *)0;
else ++s;
} else _d[i] = (char)0;
}
_d[ZT_DICTIONARY_MAX_CAPACITY-1] = (char)0;
}
bool Dictionary::load(const char *s)
{
for(unsigned int i=0;i<ZT_DICTIONARY_MAX_CAPACITY;++i) {
if (s) {
if (!(_d[i] = *s))
s = (const char *)0;
else ++s;
} else _d[i] = (char)0;
}
_d[ZT_DICTIONARY_MAX_CAPACITY - 1] = (char)0;
return (!s);
}
int Dictionary::get(const char *key,char *dest,unsigned int destlen) const
{
const char *p = _d;
const char *const eof = p + ZT_DICTIONARY_MAX_CAPACITY;
const char *k;
bool esc;
int j;
if (!destlen) // sanity check
return -1;
while (*p) {
k = key;
while ((*k)&&(*p)) {
if (*p != *k)
break;
++k;
if (++p == eof) {
dest[0] = (char)0;
return -1;
}
}
if ((!*k)&&(*p == '=')) {
j = 0;
esc = false;
++p;
while ((*p != 0)&&(*p != 13)&&(*p != 10)) {
if (esc) {
esc = false;
switch(*p) {
case 'r': dest[j++] = 13; break;
case 'n': dest[j++] = 10; break;
case '0': dest[j++] = (char)0; break;
case 'e': dest[j++] = '='; break;
default: dest[j++] = *p; break;
}
if (j == (int)destlen) {
dest[j-1] = (char)0;
return j-1;
}
} else if (*p == '\\') {
esc = true;
} else {
dest[j++] = *p;
if (j == (int)destlen) {
dest[j-1] = (char)0;
return j-1;
}
}
if (++p == eof) {
dest[0] = (char)0;
return -1;
}
}
dest[j] = (char)0;
return j;
} else {
while ((*p)&&(*p != 13)&&(*p != 10)) {
if (++p == eof) {
dest[0] = (char)0;
return -1;
}
}
if (*p) {
if (++p == eof) {
dest[0] = (char)0;
return -1;
}
}
else break;
}
}
dest[0] = (char)0;
return -1;
}
bool Dictionary::add(const char *key,const char *value,int vlen)
{
for(unsigned int i=0;i<ZT_DICTIONARY_MAX_CAPACITY;++i) {
if (!_d[i]) {
unsigned int j = i;
if (j > 0) {
_d[j++] = (char)10;
if (j == ZT_DICTIONARY_MAX_CAPACITY) {
_d[i] = (char)0;
return false;
}
}
const char *p = key;
while (*p) {
_d[j++] = *(p++);
if (j == ZT_DICTIONARY_MAX_CAPACITY) {
_d[i] = (char)0;
return false;
}
}
_d[j++] = '=';
if (j == ZT_DICTIONARY_MAX_CAPACITY) {
_d[i] = (char)0;
return false;
}
p = value;
int k = 0;
while ( ((vlen < 0)&&(*p)) || (k < vlen) ) {
switch(*p) {
case 0:
case 13:
case 10:
case '\\':
case '=':
_d[j++] = '\\';
if (j == ZT_DICTIONARY_MAX_CAPACITY) {
_d[i] = (char)0;
return false;
}
switch(*p) {
case 0: _d[j++] = '0'; break;
case 13: _d[j++] = 'r'; break;
case 10: _d[j++] = 'n'; break;
case '\\': _d[j++] = '\\'; break;
case '=': _d[j++] = 'e'; break;
}
if (j == ZT_DICTIONARY_MAX_CAPACITY) {
_d[i] = (char)0;
return false;
}
break;
default:
_d[j++] = *p;
if (j == ZT_DICTIONARY_MAX_CAPACITY) {
_d[i] = (char)0;
return false;
}
break;
}
++p;
++k;
}
_d[j] = (char)0;
return true;
}
}
return false;
}
bool Dictionary::add(const char *key,bool value)
{
return this->add(key,(value) ? "1" : "0",1);
}
bool Dictionary::add(const char *key,uint64_t value)
{
char tmp[32];
return this->add(key,Utils::hex(value,tmp),-1);
}
bool Dictionary::add(const char *key,int64_t value)
{
char tmp[32];
if (value >= 0) {
return this->add(key,Utils::hex((uint64_t)value,tmp),-1);
} else {
tmp[0] = '-';
return this->add(key,Utils::hex((uint64_t)(value * -1),tmp+1),-1);
}
}
bool Dictionary::add(const char *key,const Address &a)
{
char tmp[32];
return this->add(key,Utils::hex(a.toInt(),tmp),-1);
}
} // namespace ZeroTier

View file

@ -16,11 +16,13 @@
#include "Constants.hpp"
#include "Utils.hpp"
#include "Buffer.hpp"
#include "Address.hpp"
#include "Buf.hpp"
#include <cstdint>
#define ZT_DICTIONARY_MAX_CAPACITY 65536
namespace ZeroTier {
/**
@ -45,32 +47,14 @@ namespace ZeroTier {
*
* @tparam C Dictionary max capacity in bytes
*/
template<unsigned int C>
class Dictionary
{
public:
inline Dictionary() { memset(_d,0,sizeof(_d)); }
inline Dictionary(const char *s) { this->load(s); }
inline Dictionary(const char *s,unsigned int len)
{
for(unsigned int i=0;i<C;++i) {
if ((s)&&(i < len)) {
if (!(_d[i] = *s))
s = (const char *)0;
else ++s;
} else _d[i] = (char)0;
}
_d[C - 1] = (char)0;
}
inline Dictionary(const Dictionary &d) { memcpy(_d,d._d,C); }
ZT_ALWAYS_INLINE Dictionary() { _d[0] = 0; }
explicit ZT_ALWAYS_INLINE Dictionary(const char *s) { this->load(s); }
Dictionary(const char *s,unsigned int len);
inline Dictionary &operator=(const Dictionary &d)
{
memcpy(_d,d._d,C);
return *this;
}
inline operator bool() const { return (_d[0] != 0); }
ZT_ALWAYS_INLINE operator bool() const { return (_d[0] != 0); }
/**
* Load a dictionary from a C-string
@ -78,35 +62,12 @@ public:
* @param s Dictionary in string form
* @return False if 's' was longer than our capacity
*/
inline bool load(const char *s)
{
for(unsigned int i=0;i<C;++i) {
if (s) {
if (!(_d[i] = *s))
s = (const char *)0;
else ++s;
} else _d[i] = (char)0;
}
_d[C - 1] = (char)0;
return (!s);
}
bool load(const char *s);
/**
* Delete all entries
*/
inline void clear() { memset(_d,0,sizeof(_d)); }
/**
* @return Size of dictionary in bytes not including terminating NULL
*/
inline unsigned int sizeBytes() const
{
for(unsigned int i=0;i<C;++i) {
if (!_d[i])
return i;
}
return C-1;
}
ZT_ALWAYS_INLINE void clear() { memset(_d,0,sizeof(_d)); }
/**
* Get an entry
@ -130,104 +91,7 @@ public:
* @param destlen Size of destination buffer
* @return -1 if not found, or actual number of bytes stored in dest[] minus trailing 0
*/
inline int get(const char *key,char *dest,unsigned int destlen) const
{
const char *p = _d;
const char *const eof = p + C;
const char *k;
bool esc;
int j;
if (!destlen) // sanity check
return -1;
while (*p) {
k = key;
while ((*k)&&(*p)) {
if (*p != *k)
break;
++k;
if (++p == eof) {
dest[0] = (char)0;
return -1;
}
}
if ((!*k)&&(*p == '=')) {
j = 0;
esc = false;
++p;
while ((*p != 0)&&(*p != 13)&&(*p != 10)) {
if (esc) {
esc = false;
switch(*p) {
case 'r': dest[j++] = 13; break;
case 'n': dest[j++] = 10; break;
case '0': dest[j++] = (char)0; break;
case 'e': dest[j++] = '='; break;
default: dest[j++] = *p; break;
}
if (j == (int)destlen) {
dest[j-1] = (char)0;
return j-1;
}
} else if (*p == '\\') {
esc = true;
} else {
dest[j++] = *p;
if (j == (int)destlen) {
dest[j-1] = (char)0;
return j-1;
}
}
if (++p == eof) {
dest[0] = (char)0;
return -1;
}
}
dest[j] = (char)0;
return j;
} else {
while ((*p)&&(*p != 13)&&(*p != 10)) {
if (++p == eof) {
dest[0] = (char)0;
return -1;
}
}
if (*p) {
if (++p == eof) {
dest[0] = (char)0;
return -1;
}
}
else break;
}
}
dest[0] = (char)0;
return -1;
}
/**
* Get the contents of a key into a buffer
*
* @param key Key to get
* @param dest Destination buffer
* @return True if key was found (if false, dest will be empty)
* @tparam BC Buffer capacity (usually inferred)
*/
template<unsigned int BC>
inline bool get(const char *key,Buffer<BC> &dest) const
{
const int r = this->get(key,const_cast<char *>(reinterpret_cast<const char *>(dest.data())),BC);
if (r >= 0) {
dest.setSize((unsigned int)r);
return true;
} else {
dest.clear();
return false;
}
}
int get(const char *key,char *dest,unsigned int destlen) const;
/**
* Get a boolean value
@ -236,7 +100,7 @@ public:
* @param dfl Default value if not found in dictionary
* @return Boolean value of key or 'dfl' if not found
*/
inline bool getB(const char *key,bool dfl = false) const
ZT_ALWAYS_INLINE bool getB(const char *key,bool dfl = false) const
{
char tmp[4];
if (this->get(key,tmp,sizeof(tmp)) >= 0)
@ -251,7 +115,7 @@ public:
* @param dfl Default value or 0 if unspecified
* @return Decoded hex UInt value or 'dfl' if not found
*/
inline uint64_t getUI(const char *key,uint64_t dfl = 0) const
ZT_ALWAYS_INLINE uint64_t getUI(const char *key,uint64_t dfl = 0) const
{
char tmp[128];
if (this->get(key,tmp,sizeof(tmp)) >= 1)
@ -266,7 +130,7 @@ public:
* @param dfl Default value or 0 if unspecified
* @return Decoded hex UInt value or 'dfl' if not found
*/
inline int64_t getI(const char *key,int64_t dfl = 0) const
ZT_ALWAYS_INLINE int64_t getI(const char *key,int64_t dfl = 0) const
{
char tmp[128];
if (this->get(key,tmp,sizeof(tmp)) >= 1)
@ -288,137 +152,33 @@ public:
* @param vlen Length of value in bytes or -1 to treat value[] as a C-string and look for terminating 0
* @return True if there was enough room to add this key=value pair
*/
inline bool add(const char *key,const char *value,int vlen = -1)
{
for(unsigned int i=0;i<C;++i) {
if (!_d[i]) {
unsigned int j = i;
if (j > 0) {
_d[j++] = (char)10;
if (j == C) {
_d[i] = (char)0;
return false;
}
}
const char *p = key;
while (*p) {
_d[j++] = *(p++);
if (j == C) {
_d[i] = (char)0;
return false;
}
}
_d[j++] = '=';
if (j == C) {
_d[i] = (char)0;
return false;
}
p = value;
int k = 0;
while ( ((vlen < 0)&&(*p)) || (k < vlen) ) {
switch(*p) {
case 0:
case 13:
case 10:
case '\\':
case '=':
_d[j++] = '\\';
if (j == C) {
_d[i] = (char)0;
return false;
}
switch(*p) {
case 0: _d[j++] = '0'; break;
case 13: _d[j++] = 'r'; break;
case 10: _d[j++] = 'n'; break;
case '\\': _d[j++] = '\\'; break;
case '=': _d[j++] = 'e'; break;
}
if (j == C) {
_d[i] = (char)0;
return false;
}
break;
default:
_d[j++] = *p;
if (j == C) {
_d[i] = (char)0;
return false;
}
break;
}
++p;
++k;
}
_d[j] = (char)0;
return true;
}
}
return false;
}
bool add(const char *key,const char *value,int vlen = -1);
/**
* Add a boolean as a '1' or a '0'
*/
inline bool add(const char *key,bool value)
{
return this->add(key,(value) ? "1" : "0",1);
}
bool add(const char *key,bool value);
/**
* Add a 64-bit integer (unsigned) as a hex value
*/
inline bool add(const char *key,uint64_t value)
{
char tmp[32];
return this->add(key,Utils::hex(value,tmp),-1);
}
bool add(const char *key,uint64_t value);
/**
* Add a 64-bit integer (unsigned) as a hex value
*/
inline bool add(const char *key,int64_t value)
{
char tmp[32];
if (value >= 0) {
return this->add(key,Utils::hex((uint64_t)value,tmp),-1);
} else {
tmp[0] = '-';
return this->add(key,Utils::hex((uint64_t)(value * -1),tmp+1),-1);
}
}
bool add(const char *key,int64_t value);
/**
* Add a 64-bit integer (unsigned) as a hex value
*/
inline bool add(const char *key,const Address &a)
{
char tmp[32];
return this->add(key,Utils::hex(a.toInt(),tmp),-1);
}
/**
* Add a binary buffer's contents as a value
*
* @tparam BC Buffer capacity (usually inferred)
*/
template<unsigned int BC>
inline bool add(const char *key,const Buffer<BC> &value)
{
return this->add(key,(const char *)value.data(),(int)value.size());
}
bool add(const char *key,const Address &a);
/**
* @param key Key to check
* @return True if key is present
*/
inline bool contains(const char *key) const
ZT_ALWAYS_INLINE bool contains(const char *key) const
{
char tmp[2];
return (this->get(key,tmp,2) >= 0);
@ -427,13 +187,12 @@ public:
/**
* @return Value of C template parameter
*/
inline unsigned int capacity() const { return C; }
ZT_ALWAYS_INLINE unsigned int capacity() const { return sizeof(_d); }
inline const char *data() const { return _d; }
inline char *unsafeData() { return _d; }
ZT_ALWAYS_INLINE const char *data() const { return _d; }
private:
char _d[C];
char _d[ZT_DICTIONARY_MAX_CAPACITY];
};
} // namespace ZeroTier

View file

@ -21,7 +21,6 @@
#include "Utils.hpp"
#include "Address.hpp"
#include "C25519.hpp"
#include "Buffer.hpp"
#include "SHA512.hpp"
#include "ECC384.hpp"
@ -158,108 +157,6 @@ public:
*/
ZT_ALWAYS_INLINE const Address &address() const { return _address; }
/**
* Serialize this identity (binary)
*
* @param b Destination buffer to append to
* @param includePrivate If true, include private key component (if present) (default: false)
*/
template<unsigned int C>
inline void serialize(Buffer<C> &b,bool includePrivate = false) const
{
_address.appendTo(b);
switch(_type) {
case C25519:
b.append((uint8_t)C25519);
b.append(_pub.c25519,ZT_C25519_PUBLIC_KEY_LEN);
if ((_hasPrivate)&&(includePrivate)) {
b.append((uint8_t)ZT_C25519_PRIVATE_KEY_LEN);
b.append(_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
} else {
b.append((uint8_t)0);
}
break;
case P384:
b.append((uint8_t)P384);
b.append(&_pub,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_C25519_SIGNATURE_LEN + ZT_ECC384_SIGNATURE_SIZE);
if ((_hasPrivate)&&(includePrivate)) {
b.append((uint8_t)(ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE));
b.append(_priv.c25519,ZT_C25519_PRIVATE_KEY_LEN);
b.append(_priv.p384,ZT_ECC384_PRIVATE_KEY_SIZE);
} else {
b.append((uint8_t)0);
}
b.append((uint8_t)0); // size of additional fields (should have included such a thing in v0!)
break;
}
}
/**
* Deserialize a binary serialized identity
*
* If an exception is thrown, the Identity object is left in an undefined
* state and should not be used.
*
* @param b Buffer containing serialized data
* @param startAt Index within buffer of serialized data (default: 0)
* @return Length of serialized data read from buffer
*/
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{
_hasPrivate = false;
unsigned int p = startAt;
unsigned int pkl;
_address.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
p += ZT_ADDRESS_LENGTH;
switch((_type = (Type)b[p++])) {
case C25519:
memcpy(_pub.c25519,b.field(p,ZT_C25519_PUBLIC_KEY_LEN),ZT_C25519_PUBLIC_KEY_LEN);
p += ZT_C25519_PUBLIC_KEY_LEN;
pkl = (unsigned int)b[p++];
if (pkl) {
if (pkl != ZT_C25519_PRIVATE_KEY_LEN)
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
_hasPrivate = true;
memcpy(_priv.c25519,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
p += ZT_C25519_PRIVATE_KEY_LEN;
} else {
_hasPrivate = false;
}
break;
case P384:
memcpy(&_pub,b.field(p,ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_C25519_SIGNATURE_LEN + ZT_ECC384_SIGNATURE_SIZE),ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_C25519_SIGNATURE_LEN + ZT_ECC384_SIGNATURE_SIZE);
p += ZT_C25519_PUBLIC_KEY_LEN + ZT_ECC384_PUBLIC_KEY_SIZE + ZT_C25519_SIGNATURE_LEN + ZT_ECC384_SIGNATURE_SIZE;
pkl = (unsigned int)b[p++];
if (pkl) {
if (pkl != (ZT_C25519_PRIVATE_KEY_LEN + ZT_ECC384_PRIVATE_KEY_SIZE))
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_CRYPTOGRAPHIC_TOKEN;
_hasPrivate = true;
memcpy(_priv.c25519,b.field(p,ZT_C25519_PRIVATE_KEY_LEN),ZT_C25519_PRIVATE_KEY_LEN);
p += ZT_C25519_PRIVATE_KEY_LEN;
memcpy(_priv.p384,b.field(p,ZT_ECC384_PRIVATE_KEY_SIZE),ZT_ECC384_PRIVATE_KEY_SIZE);
p += ZT_ECC384_PRIVATE_KEY_SIZE;
} else {
_hasPrivate = false;
}
p += b.template at<uint8_t>(p) + 2;
break;
default:
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_INVALID_TYPE;
}
return (p - startAt);
}
/**
* Serialize to a more human-friendly string
*

View file

@ -21,7 +21,6 @@
#include "Constants.hpp"
#include "Utils.hpp"
#include "MAC.hpp"
#include "Buffer.hpp"
namespace ZeroTier {
@ -498,62 +497,6 @@ public:
int marshal(uint8_t data[19]) const;
int unmarshal(const uint8_t *restrict data,const int len);
template<unsigned int C>
inline void serialize(Buffer<C> &b) const
{
// This is used in the protocol and must be the same as describe in places
// like VERB_HELLO in Packet.hpp.
switch(ss_family) {
case AF_INET:
b.append((uint8_t)0x04);
b.append(&(reinterpret_cast<const struct sockaddr_in *>(this)->sin_addr.s_addr),4);
b.append((uint16_t)port()); // just in case sin_port != uint16_t
return;
case AF_INET6:
b.append((uint8_t)0x06);
b.append(reinterpret_cast<const struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,16);
b.append((uint16_t)port()); // just in case sin_port != uint16_t
return;
default:
b.append((uint8_t)0);
return;
}
}
template<unsigned int C>
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
{
memset(this,0,sizeof(InetAddress));
unsigned int p = startAt;
switch(b[p++]) {
case 0:
return 1;
case 0x01:
// TODO: Ethernet address (but accept for forward compatibility)
return 7;
case 0x02:
// TODO: Bluetooth address (but accept for forward compatibility)
return 7;
case 0x03:
// TODO: Other address types (but accept for forward compatibility)
// These could be extended/optional things like AF_UNIX, LTE Direct, shared memory, etc.
return (unsigned int)(b.template at<uint16_t>(p) + 3); // other addresses begin with 16-bit non-inclusive length
case 0x04:
ss_family = AF_INET;
memcpy(&(reinterpret_cast<struct sockaddr_in *>(this)->sin_addr.s_addr),b.field(p,4),4); p += 4;
reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p)); p += 2;
break;
case 0x06:
ss_family = AF_INET6;
memcpy(reinterpret_cast<struct sockaddr_in6 *>(this)->sin6_addr.s6_addr,b.field(p,16),16); p += 16;
reinterpret_cast<struct sockaddr_in *>(this)->sin_port = Utils::hton(b.template at<uint16_t>(p)); p += 2;
break;
default:
throw ZT_EXCEPTION_INVALID_SERIALIZED_DATA_BAD_ENCODING;
}
return (p - startAt);
}
bool operator==(const InetAddress &a) const;
bool operator<(const InetAddress &a) const;
ZT_ALWAYS_INLINE bool operator!=(const InetAddress &a) const { return !(*this == a); }

View file

@ -21,7 +21,6 @@
#include "Constants.hpp"
#include "Utils.hpp"
#include "Address.hpp"
#include "Buffer.hpp"
namespace ZeroTier {
@ -39,9 +38,9 @@ public:
((((uint64_t)d) & 0xffULL) << 16U) |
((((uint64_t)e) & 0xffULL) << 8U) |
(((uint64_t)f) & 0xffULL) ) {}
ZT_ALWAYS_INLINE MAC(const uint8_t b[6]) { setTo(b); }
explicit ZT_ALWAYS_INLINE MAC(const uint8_t b[6]) { setTo(b); }
ZT_ALWAYS_INLINE MAC(const Address &ztaddr,uint64_t nwid) { fromAddress(ztaddr,nwid); }
ZT_ALWAYS_INLINE MAC(const uint64_t m) : _m(m & 0xffffffffffffULL) {}
explicit ZT_ALWAYS_INLINE MAC(const uint64_t m) : _m(m & 0xffffffffffffULL) {}
/**
* @return MAC in 64-bit integer

View file

@ -18,7 +18,6 @@
#include "Peer.hpp"
#include "Topology.hpp"
#include "Switch.hpp"
#include "Packet.hpp"
#include "Node.hpp"
namespace ZeroTier {

View file

@ -63,7 +63,7 @@ public:
// multicast address directly from the IP address, and it gives us
// 24 bits of uniqueness. Collisions aren't likely to be common enough
// to care about.
const unsigned char *a = (const unsigned char *)ip.rawIpData();
const uint8_t *a = (const uint8_t *)ip.rawIpData();
return MulticastGroup(MAC(0x33,0x33,0xff,a[13],a[14],a[15]),0);
}
return MulticastGroup();

View file

@ -20,7 +20,28 @@
namespace ZeroTier {
bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,bool includeLegacy) const
NetworkConfig::NetworkConfig() :
networkId(0),
timestamp(0),
credentialTimeMaxDelta(0),
revision(0),
issuedTo(),
flags(0),
mtu(0),
multicastLimit(0),
specialistCount(0),
routeCount(0),
staticIpCount(0),
ruleCount(0),
capabilityCount(0),
tagCount(0),
certificateOfOwnershipCount(0),
type(ZT_NETWORK_TYPE_PRIVATE)
{
name[0] = 0;
}
bool NetworkConfig::toDictionary(Dictionary &d,bool includeLegacy) const
{
ScopedPtr< Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> > tmp(new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>());
char tmp2[128];
@ -105,7 +126,7 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
return true;
}
bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d)
bool NetworkConfig::fromDictionary(const Dictionary &d)
{
static const NetworkConfig NIL_NC;
ScopedPtr< Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY> > tmp(new Buffer<ZT_NETWORKCONFIG_DICT_CAPACITY>());
@ -218,4 +239,20 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
}
}
bool NetworkConfig::addSpecialist(const Address &a,const uint64_t f)
{
const uint64_t aint = a.toInt();
for(unsigned int i=0;i<specialistCount;++i) {
if ((specialists[i] & 0xffffffffffULL) == aint) {
specialists[i] |= f;
return true;
}
}
if (specialistCount < ZT_MAX_NETWORK_SPECIALISTS) {
specialists[specialistCount++] = f | aint;
return true;
}
return false;
}
} // namespace ZeroTier

View file

@ -17,13 +17,11 @@
#include <cstdint>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include "Constants.hpp"
#include "Buffer.hpp"
#include "InetAddress.hpp"
#include "MulticastGroup.hpp"
#include "Address.hpp"
@ -168,26 +166,7 @@ namespace ZeroTier {
*/
struct NetworkConfig
{
inline NetworkConfig() :
networkId(0),
timestamp(0),
credentialTimeMaxDelta(0),
revision(0),
issuedTo(),
flags(0),
mtu(0),
multicastLimit(0),
specialistCount(0),
routeCount(0),
staticIpCount(0),
ruleCount(0),
capabilityCount(0),
tagCount(0),
certificateOfOwnershipCount(0),
type(ZT_NETWORK_TYPE_PRIVATE)
{
name[0] = 0;
}
NetworkConfig();
/**
* Write this network config to a dictionary for transport
@ -196,7 +175,7 @@ struct NetworkConfig
* @param includeLegacy If true, include legacy fields for old node versions
* @return True if dictionary was successfully created, false if e.g. overflow
*/
bool toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,bool includeLegacy) const;
bool toDictionary(Dictionary &d,bool includeLegacy) const;
/**
* Read this network config from a dictionary
@ -204,33 +183,33 @@ struct NetworkConfig
* @param d Dictionary (non-const since it might be modified during parse, should not be used after call)
* @return True if dictionary was valid and network config successfully initialized
*/
bool fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d);
bool fromDictionary(const Dictionary &d);
/**
* @return True if broadcast (ff:ff:ff:ff:ff:ff) address should work on this network
*/
inline bool enableBroadcast() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); }
ZT_ALWAYS_INLINE bool enableBroadcast() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST) != 0); }
/**
* @return True if IPv6 NDP emulation should be allowed for certain "magic" IPv6 address patterns
*/
inline bool ndpEmulation() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); }
ZT_ALWAYS_INLINE bool ndpEmulation() const { return ((this->flags & ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION) != 0); }
/**
* @return Network type is public (no access control)
*/
inline bool isPublic() const { return (this->type == ZT_NETWORK_TYPE_PUBLIC); }
ZT_ALWAYS_INLINE bool isPublic() const { return (this->type == ZT_NETWORK_TYPE_PUBLIC); }
/**
* @return Network type is private (certificate access control)
*/
inline bool isPrivate() const { return (this->type == ZT_NETWORK_TYPE_PRIVATE); }
ZT_ALWAYS_INLINE bool isPrivate() const { return (this->type == ZT_NETWORK_TYPE_PRIVATE); }
/**
* @param fromPeer Peer attempting to bridge other Ethernet peers onto network
* @return True if this network allows bridging
*/
inline bool permitsBridging(const Address &fromPeer) const
ZT_ALWAYS_INLINE bool permitsBridging(const Address &fromPeer) const
{
for(unsigned int i=0;i<specialistCount;++i) {
if ((fromPeer == specialists[i])&&((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE) != 0))
@ -239,9 +218,9 @@ struct NetworkConfig
return false;
}
inline operator bool() const { return (networkId != 0); }
inline bool operator==(const NetworkConfig &nc) const { return (memcmp(this,&nc,sizeof(NetworkConfig)) == 0); }
inline bool operator!=(const NetworkConfig &nc) const { return (!(*this == nc)); }
ZT_ALWAYS_INLINE operator bool() const { return (networkId != 0); }
ZT_ALWAYS_INLINE bool operator==(const NetworkConfig &nc) const { return (memcmp(this,&nc,sizeof(NetworkConfig)) == 0); }
ZT_ALWAYS_INLINE bool operator!=(const NetworkConfig &nc) const { return (!(*this == nc)); }
/**
* Add a specialist or mask flags if already present
@ -253,23 +232,9 @@ struct NetworkConfig
* @param f Flags (OR of specialist role/type flags)
* @return True if successfully masked or added
*/
inline bool addSpecialist(const Address &a,const uint64_t f)
{
const uint64_t aint = a.toInt();
for(unsigned int i=0;i<specialistCount;++i) {
if ((specialists[i] & 0xffffffffffULL) == aint) {
specialists[i] |= f;
return true;
}
}
if (specialistCount < ZT_MAX_NETWORK_SPECIALISTS) {
specialists[specialistCount++] = f | aint;
return true;
}
return false;
}
bool addSpecialist(const Address &a,const uint64_t f);
inline const Capability *capability(const uint32_t id) const
ZT_ALWAYS_INLINE const Capability *capability(const uint32_t id) const
{
for(unsigned int i=0;i<capabilityCount;++i) {
if (capabilities[i].id() == id)
@ -278,7 +243,7 @@ struct NetworkConfig
return (Capability *)0;
}
inline const Tag *tag(const uint32_t id) const
ZT_ALWAYS_INLINE const Tag *tag(const uint32_t id) const
{
for(unsigned int i=0;i<tagCount;++i) {
if (tags[i].id() == id)

View file

@ -21,8 +21,6 @@
#include "NetworkController.hpp"
#include "Switch.hpp"
#include "Topology.hpp"
#include "Buffer.hpp"
#include "Packet.hpp"
#include "Address.hpp"
#include "Identity.hpp"
#include "SelfAwareness.hpp"
@ -30,6 +28,7 @@
#include "Trace.hpp"
#include "ScopedPtr.hpp"
#include "Locator.hpp"
#include "Protocol.hpp"
namespace ZeroTier {

View file

@ -29,6 +29,7 @@
#include "Mutex.hpp"
#include "Endpoint.hpp"
#include "Locator.hpp"
#include "Protocol.hpp"
#include <vector>
@ -103,9 +104,9 @@ public:
unsigned int hops,
uint64_t packetId,
unsigned int payloadLength,
Packet::Verb verb,
Protocol::Verb verb,
uint64_t inRePacketId,
Packet::Verb inReVerb,
Protocol::Verb inReVerb,
uint64_t networkId);
/**

View file

@ -24,7 +24,6 @@
#include "Address.hpp"
#include "C25519.hpp"
#include "Utils.hpp"
#include "Buffer.hpp"
#include "Identity.hpp"
/**

View file

@ -22,7 +22,6 @@
#include "InetAddress.hpp"
#include "Peer.hpp"
#include "SelfAwareness.hpp"
#include "Packet.hpp"
#include "Trace.hpp"
namespace ZeroTier {

View file

@ -22,7 +22,6 @@
#include "Constants.hpp"
#include "Mutex.hpp"
#include "MAC.hpp"
#include "Packet.hpp"
#include "Utils.hpp"
#include "InetAddress.hpp"
#include "Topology.hpp"
@ -30,6 +29,7 @@
#include "SharedPtr.hpp"
#include "IncomingPacket.hpp"
#include "Hashtable.hpp"
#include "Protocol.hpp"
namespace ZeroTier {

View file

@ -24,7 +24,6 @@
#include "C25519.hpp"
#include "Address.hpp"
#include "Identity.hpp"
#include "Buffer.hpp"
namespace ZeroTier {

View file

@ -15,7 +15,10 @@
#include <cstdlib>
#include <ctime>
#include "Constants.hpp"
#include "Utils.hpp"
#include "Mutex.hpp"
#include "AES.hpp"
#include "SHA512.hpp"
#ifdef __UNIX_LIKE__
#include <unistd.h>
@ -27,11 +30,6 @@
#include <wincrypt.h>
#endif
#include "Utils.hpp"
#include "Mutex.hpp"
#include "AES.hpp"
#include "SHA512.hpp"
namespace ZeroTier {
namespace Utils {
@ -166,13 +164,13 @@ void getSecureRandom(void *buf,unsigned int bytes)
static Mutex globalLock;
static bool initialized = false;
static uint64_t randomState[8];
static uint8_t randomBuf[65536];
static unsigned long randomPtr = sizeof(randomBuf);
static uint64_t randomBuf[8192];
static unsigned int randomPtr = 65536;
Mutex::Lock gl(globalLock);
for(unsigned int i=0;i<bytes;++i) {
if (randomPtr >= sizeof(randomBuf)) {
if (randomPtr >= 65536) {
randomPtr = 0;
if (!initialized) {
@ -225,18 +223,22 @@ void getSecureRandom(void *buf,unsigned int bytes)
#endif
}
++randomState[0];
SHA512(randomState,randomState,sizeof(randomState));
AES aes(reinterpret_cast<const uint8_t *>(randomState));
uint64_t ctr[2];
uint64_t ctr[2],tmp[2];
ctr[0] = randomState[6];
ctr[1] = randomState[7];
for(unsigned long i=0;i<sizeof(randomBuf);i+=16) {
for(int k=0;k<8192;) {
++ctr[0];
aes.encrypt(reinterpret_cast<const uint8_t *>(ctr),randomBuf + i);
aes.encrypt(reinterpret_cast<const uint8_t *>(ctr),reinterpret_cast<uint8_t *>(tmp));
randomBuf[k] ^= tmp[0];
randomBuf[k+1] ^= tmp[1];
k += 2;
}
}
reinterpret_cast<uint8_t *>(buf)[i] = randomBuf[randomPtr++];
reinterpret_cast<uint8_t *>(buf)[i] = reinterpret_cast<uint8_t *>(randomBuf)[randomPtr++];
}
}

View file

@ -19,6 +19,11 @@
#include <cstdint>
#include <cstring>
#include <ctime>
#include <stdexcept>
#include <vector>
#include <map>
#include "Constants.hpp"
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
#include <emmintrin.h>
@ -26,12 +31,6 @@
#include <immintrin.h>
#endif
#include <stdexcept>
#include <vector>
#include <map>
#include "Constants.hpp"
namespace ZeroTier {
namespace Utils {
@ -87,7 +86,7 @@ char *decimal(unsigned long n,char s[24]);
* @return Pointer to s containing hex string with trailing zero byte
*/
template<typename I>
static inline char *hex(I x,char *s)
static ZT_ALWAYS_INLINE char *hex(I x,char *s)
{
char *const r = s;
for(unsigned int i=0,b=(sizeof(x)*8);i<sizeof(x);++i) {