NetworkConfig refactor part 1

This commit is contained in:
Adam Ierymenko 2016-04-12 12:11:34 -07:00
parent 9b8444fff1
commit 6f854c8391
8 changed files with 577 additions and 319 deletions

View file

@ -23,8 +23,8 @@
#include <string.h>
#include <string>
#include <vector>
#include <stdexcept>
#include <algorithm>
#include "Constants.hpp"
#include "Buffer.hpp"
@ -43,6 +43,11 @@
*/
#define ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA (ZT_NETWORK_AUTOCONF_DELAY * 5)
/**
* Maximum number of qualifiers in a COM
*/
#define ZT_NETWORK_COM_MAX_QUALIFIERS 32
namespace ZeroTier {
/**
@ -67,6 +72,9 @@ namespace ZeroTier {
* often enough to stay within the max delta for this qualifier. But other
* criteria could be added in the future for very special behaviors, things
* like latitude and longitude for instance.
*
* This is a memcpy()'able structure and is safe (in a crash sense) to modify
* without locks.
*/
class CertificateOfMembership
{
@ -120,7 +128,16 @@ public:
/**
* Create an empty certificate
*/
CertificateOfMembership() { memset(_signature.data,0,_signature.size()); }
CertificateOfMembership() :
_qualifierCount(0)
{
memset(_signature.data,0,_signature.size());
}
CertificateOfMembership(const CertificateOfMembership &c)
{
memcpy(this,&c,sizeof(CertificateOfMembership));
}
/**
* Create from required fields common to all networks
@ -132,12 +149,26 @@ public:
*/
CertificateOfMembership(uint64_t revision,uint64_t revisionMaxDelta,uint64_t nwid,const Address &issuedTo)
{
_qualifiers.push_back(_Qualifier(COM_RESERVED_ID_REVISION,revision,revisionMaxDelta));
_qualifiers.push_back(_Qualifier(COM_RESERVED_ID_NETWORK_ID,nwid,0));
_qualifiers.push_back(_Qualifier(COM_RESERVED_ID_ISSUED_TO,issuedTo.toInt(),0xffffffffffffffffULL));
_qualifiers[0].id = COM_RESERVED_ID_REVISION;
_qualifiers[0].value = revision;
_qualifiers[0].maxDelta = revisionMaxDelta;
_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;
memset(_signature.data,0,_signature.size());
}
inline CertificateOfMembership &operator=(const CertificateOfMembership &c)
{
memcpy(this,&c,sizeof(CertificateOfMembership));
return *this;
}
#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
/**
* Create from string-serialized data
*
@ -151,6 +182,7 @@ public:
* @param s String-serialized COM
*/
CertificateOfMembership(const std::string &s) { fromString(s.c_str()); }
#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
/**
* Create from binary-serialized COM in buffer
@ -160,7 +192,6 @@ public:
*/
template<unsigned int C>
CertificateOfMembership(const Buffer<C> &b,unsigned int startAt = 0)
throw(std::out_of_range,std::invalid_argument)
{
deserialize(b,startAt);
}
@ -168,11 +199,7 @@ public:
/**
* @return True if there's something here
*/
inline operator bool() const
throw()
{
return (_qualifiers.size() != 0);
}
inline operator bool() const throw() { return (_qualifierCount != 0); }
/**
* Check for presence of all required fields common to all networks
@ -180,9 +207,8 @@ public:
* @return True if all required fields are present
*/
inline bool hasRequiredFields() const
throw()
{
if (_qualifiers.size() < 3)
if (_qualifierCount < 3)
return false;
if (_qualifiers[0].id != COM_RESERVED_ID_REVISION)
return false;
@ -197,11 +223,10 @@ public:
* @return Maximum delta for mandatory revision field or 0 if field missing
*/
inline uint64_t revisionMaxDelta() const
throw()
{
for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) {
if (q->id == COM_RESERVED_ID_REVISION)
return q->maxDelta;
for(unsigned int i=0;i<_qualifierCount;++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_REVISION)
return _qualifiers[i].maxDelta;
}
return 0ULL;
}
@ -210,11 +235,10 @@ public:
* @return Revision number for this cert
*/
inline uint64_t revision() const
throw()
{
for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) {
if (q->id == COM_RESERVED_ID_REVISION)
return q->value;
for(unsigned int i=0;i<_qualifierCount;++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_REVISION)
return _qualifiers[i].value;
}
return 0ULL;
}
@ -223,11 +247,10 @@ public:
* @return Address to which this cert was issued
*/
inline Address issuedTo() const
throw()
{
for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) {
if (q->id == COM_RESERVED_ID_ISSUED_TO)
return Address(q->value);
for(unsigned int i=0;i<_qualifierCount;++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_ISSUED_TO)
return Address(_qualifiers[i].value);
}
return Address();
}
@ -236,11 +259,10 @@ public:
* @return Network ID for which this cert was issued
*/
inline uint64_t networkId() const
throw()
{
for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) {
if (q->id == COM_RESERVED_ID_NETWORK_ID)
return q->value;
for(unsigned int i=0;i<_qualifierCount;++i) {
if (_qualifiers[i].id == COM_RESERVED_ID_NETWORK_ID)
return _qualifiers[i].value;
}
return 0ULL;
}
@ -257,6 +279,7 @@ public:
void setQualifier(uint64_t id,uint64_t value,uint64_t maxDelta);
inline void setQualifier(ReservedId id,uint64_t value,uint64_t maxDelta) { setQualifier((uint64_t)id,value,maxDelta); }
#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
/**
* @return String-serialized representation of this certificate
*/
@ -273,6 +296,7 @@ public:
*/
void fromString(const char *s);
inline void fromString(const std::string &s) { fromString(s.c_str()); }
#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
/**
* Compare two certificates for parameter agreement
@ -287,8 +311,7 @@ public:
* @param other Cert to compare with
* @return True if certs agree and 'other' may be communicated with
*/
bool agreesWith(const CertificateOfMembership &other) const
throw();
bool agreesWith(const CertificateOfMembership &other) const;
/**
* Sign this certificate
@ -320,11 +343,11 @@ public:
inline void serialize(Buffer<C> &b) const
{
b.append((unsigned char)COM_UINT64_ED25519);
b.append((uint16_t)_qualifiers.size());
for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) {
b.append(q->id);
b.append(q->value);
b.append(q->maxDelta);
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)
@ -336,25 +359,28 @@ public:
{
unsigned int p = startAt;
_qualifiers.clear();
_qualifierCount = 0;
_signedBy.zero();
if (b[p++] != COM_UINT64_ED25519)
throw std::invalid_argument("unknown certificate of membership type");
throw std::invalid_argument("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) {
uint64_t tmp = b.template at<uint64_t>(p);
if (tmp < lastId)
throw std::invalid_argument("certificate qualifiers are not sorted");
else lastId = tmp;
_qualifiers.push_back(_Qualifier(
tmp,
b.template at<uint64_t>(p + 8),
b.template at<uint64_t>(p + 16)
));
p += 24;
const uint64_t qid = b.template at<uint64_t>(p);
if (qid < lastId)
throw std::invalid_argument("qualifiers not sorted");
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 std::invalid_argument("too many qualifiers");
}
}
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
@ -373,10 +399,9 @@ public:
{
if (_signedBy != c._signedBy)
return false;
// We have to compare in depth manually since == only compares id
if (_qualifiers.size() != c._qualifiers.size())
if (_qualifierCount != c._qualifierCount)
return false;
for(unsigned long i=0;i<_qualifiers.size();++i) {
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))
@ -389,22 +414,16 @@ public:
private:
struct _Qualifier
{
_Qualifier() throw() {}
_Qualifier(uint64_t i,uint64_t v,uint64_t m) throw() :
id(i),
value(v),
maxDelta(m) {}
_Qualifier() : id(0),value(0),maxDelta(0) {}
uint64_t id;
uint64_t value;
uint64_t maxDelta;
inline bool operator==(const _Qualifier &q) const throw() { return (id == q.id); } // for unique
inline bool operator<(const _Qualifier &q) const throw() { return (id < q.id); } // for sort
inline bool operator<(const _Qualifier &q) const throw() { return (id < q.id); } // sort order
};
Address _signedBy;
std::vector<_Qualifier> _qualifiers; // sorted by id and unique
_Qualifier _qualifiers[ZT_NETWORK_COM_MAX_QUALIFIERS];
unsigned int _qualifierCount;
C25519::Signature _signature;
};