mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-20 21:43:08 +00:00
Automagically push netconf certs -- Network support.
This commit is contained in:
parent
b4ae1adfbf
commit
4d594b24bc
@ -51,6 +51,8 @@ std::string CertificateOfMembership::toString() const
|
||||
{
|
||||
std::string s;
|
||||
|
||||
s.append("1:"); // COM_UINT64_ED25519
|
||||
|
||||
uint64_t *buf = new uint64_t[_qualifiers.size() * 3];
|
||||
try {
|
||||
unsigned int ptr = 0;
|
||||
@ -87,6 +89,13 @@ void CertificateOfMembership::fromString(const char *s)
|
||||
unsigned int colonAt = 0;
|
||||
while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt;
|
||||
|
||||
if (!((colonAt == 1)&&(s[0] == '1'))) // COM_UINT64_ED25519?
|
||||
return;
|
||||
|
||||
s += colonAt + 1;
|
||||
colonAt = 0;
|
||||
while ((s[colonAt])&&(s[colonAt] != ':')) ++colonAt;
|
||||
|
||||
if (colonAt) {
|
||||
unsigned int buflen = colonAt / 2;
|
||||
char *buf = new char[buflen];
|
||||
|
@ -33,8 +33,10 @@
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Buffer.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "C25519.hpp"
|
||||
#include "Identity.hpp"
|
||||
@ -86,7 +88,7 @@ public:
|
||||
* IDs below 65536 should be considered reserved for future global
|
||||
* assignment here.
|
||||
*/
|
||||
enum ReservedIds
|
||||
enum ReservedId
|
||||
{
|
||||
COM_RESERVED_ID_TIMESTAMP = 0, // timestamp, max delta defines cert life
|
||||
COM_RESERVED_ID_NETWORK_ID = 1 // network ID, max delta always 0
|
||||
@ -96,6 +98,19 @@ public:
|
||||
CertificateOfMembership(const char *s) { fromString(s); }
|
||||
CertificateOfMembership(const std::string &s) { fromString(s.c_str()); }
|
||||
|
||||
/**
|
||||
* @return Maximum delta for mandatory timestamp field or 0 if field missing
|
||||
*/
|
||||
inline uint64_t timestampMaxDelta() const
|
||||
throw()
|
||||
{
|
||||
for(std::vector<_Qualifier>::const_iterator q(_qualifiers.begin());q!=_qualifiers.end();++q) {
|
||||
if (q->id == COM_RESERVED_ID_TIMESTAMP)
|
||||
return q->maxDelta;
|
||||
}
|
||||
return 0ULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add or update a qualifier in this certificate
|
||||
*
|
||||
@ -106,6 +121,7 @@ public:
|
||||
* @param maxDelta Qualifier maximum allowed difference (absolute value of difference)
|
||||
*/
|
||||
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); }
|
||||
|
||||
/**
|
||||
* @return String-serialized representation of this certificate
|
||||
@ -165,6 +181,55 @@ public:
|
||||
*/
|
||||
inline const Address &signedBy() const throw() { return _signedBy; }
|
||||
|
||||
template<unsigned int C>
|
||||
inline void serialize(Buffer<C> &b) const
|
||||
throw(std::out_of_range)
|
||||
{
|
||||
b.append((unsigned char)COM_UINT64_ED25519);
|
||||
b.append((uint32_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);
|
||||
}
|
||||
_signedBy.appendTo(b);
|
||||
if (_signedBy)
|
||||
b.append(_signature.data,_signature.size());
|
||||
}
|
||||
|
||||
template<unsigned int C>
|
||||
inline unsigned int deserialize(const Buffer<C> &b,unsigned int startAt = 0)
|
||||
throw(std::out_of_range,std::invalid_argument)
|
||||
{
|
||||
unsigned int p = startAt;
|
||||
|
||||
_qualifiers.clear();
|
||||
_signedBy.zero();
|
||||
|
||||
if (b[p++] != COM_UINT64_ED25519)
|
||||
throw std::invalid_argument("unknown certificate of membership type");
|
||||
|
||||
unsigned int numq = b.template at<uint32_t>(p); p += sizeof(uint32_t);
|
||||
for(unsigned int i=0;i<numq;++i) {
|
||||
_qualifiers.push_back(_Qualifier(
|
||||
b.template at<uint64_t>(p),
|
||||
b.template at<uint64_t>(p + 8),
|
||||
b.template at<uint64_t>(p + 16)
|
||||
));
|
||||
p += 24;
|
||||
}
|
||||
|
||||
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
|
||||
p += ZT_ADDRESS_LENGTH;
|
||||
|
||||
if (_signedBy) {
|
||||
memcpy(_signature.data,b.field(p,_signature.size()),_signature.size());
|
||||
p += _signature.size();
|
||||
}
|
||||
|
||||
return (p - startAt);
|
||||
}
|
||||
|
||||
private:
|
||||
struct _Qualifier
|
||||
{
|
||||
|
@ -169,6 +169,30 @@ void Network::addMembershipCertificate(const Address &peer,const CertificateOfMe
|
||||
_membershipCertificates[peer] = cert;
|
||||
}
|
||||
|
||||
void Network::pushMembershipCertificate(const Address &peer,bool force,uint64_t now)
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
|
||||
if (_isOpen)
|
||||
return;
|
||||
|
||||
uint64_t timestampMaxDelta = _myCertificate.timestampMaxDelta();
|
||||
if (!timestampMaxDelta) {
|
||||
LOG("unable to push my certificate to %s for network %.16llx: certificate invalid, missing required timestamp field",peer.toString().c_str(),_id);
|
||||
return; // required field missing!
|
||||
}
|
||||
|
||||
uint64_t &lastPushed = _lastPushedMembershipCertificate[peer];
|
||||
if ((force)||((now - lastPushed) > (timestampMaxDelta / 2))) {
|
||||
lastPushed = now;
|
||||
|
||||
Packet outp(peer,_r->identity.address(),Packet::VERB_NETWORK_MEMBERSHIP_CERTIFICATE);
|
||||
outp.append((uint64_t)_id);
|
||||
_myCertificate.serialize(outp);
|
||||
_r->sw->send(outp,true);
|
||||
}
|
||||
}
|
||||
|
||||
bool Network::isAllowed(const Address &peer) const
|
||||
{
|
||||
// Exceptions can occur if we do not yet have *our* configuration.
|
||||
|
@ -469,6 +469,15 @@ public:
|
||||
*/
|
||||
void addMembershipCertificate(const Address &peer,const CertificateOfMembership &cert);
|
||||
|
||||
/**
|
||||
* Push our membership certificate to a peer
|
||||
*
|
||||
* @param peer Destination peer address
|
||||
* @param force If true, push even if we've already done so within required time frame
|
||||
* @param now Current time
|
||||
*/
|
||||
void pushMembershipCertificate(const Address &peer,bool force,uint64_t now);
|
||||
|
||||
/**
|
||||
* @param peer Peer address to check
|
||||
* @return True if peer is allowed to communicate on this network
|
||||
@ -483,11 +492,7 @@ public:
|
||||
/**
|
||||
* @return Time of last updated configuration or 0 if none
|
||||
*/
|
||||
inline uint64_t lastConfigUpdate() const
|
||||
throw()
|
||||
{
|
||||
return _lastConfigUpdate;
|
||||
}
|
||||
inline uint64_t lastConfigUpdate() const throw() { return _lastConfigUpdate; }
|
||||
|
||||
/**
|
||||
* @return Status of this network
|
||||
@ -530,9 +535,6 @@ public:
|
||||
bal = _multicastRateAccounts.insert(std::pair< std::pair<Address,MulticastGroup>,BandwidthAccount >(k,BandwidthAccount(r.preload,r.maxBalance,r.accrual))).first;
|
||||
}
|
||||
return bal->second.deduct(bytes);
|
||||
//bool tmp = bal->second.deduct(bytes);
|
||||
//printf("%s: BAL: %u\n",mg.toString().c_str(),(unsigned int)bal->second.balance());
|
||||
//return tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -547,20 +549,12 @@ public:
|
||||
/**
|
||||
* @return Bits in multicast restriciton prefix
|
||||
*/
|
||||
inline unsigned int multicastPrefixBits() const
|
||||
throw()
|
||||
{
|
||||
return _multicastPrefixBits;
|
||||
}
|
||||
inline unsigned int multicastPrefixBits() const throw() { return _multicastPrefixBits; }
|
||||
|
||||
/**
|
||||
* @return Max depth (TTL) for a multicast frame
|
||||
*/
|
||||
inline unsigned int multicastDepth() const
|
||||
throw()
|
||||
{
|
||||
return _multicastDepth;
|
||||
}
|
||||
inline unsigned int multicastDepth() const throw() { return _multicastDepth; }
|
||||
|
||||
private:
|
||||
static void _CBhandleTapData(void *arg,const MAC &from,const MAC &to,unsigned int etherType,const Buffer<4096> &data);
|
||||
@ -578,19 +572,25 @@ private:
|
||||
// Membership certificates supplied by other peers on this network
|
||||
std::map<Address,CertificateOfMembership> _membershipCertificates;
|
||||
|
||||
// Configuration from network master node
|
||||
// The last time we sent a membership certificate to a given peer
|
||||
std::map<Address,uint64_t> _lastPushedMembershipCertificate;
|
||||
|
||||
// Configuration from network master node -- and some memoized fields from
|
||||
// the most recent _configuration we have.
|
||||
Config _configuration;
|
||||
CertificateOfMembership _myCertificate; // memoized from _configuration
|
||||
MulticastRates _mcRates; // memoized from _configuration
|
||||
std::set<InetAddress> _staticAddresses; // memoized from _configuration
|
||||
bool _isOpen; // memoized from _configuration
|
||||
unsigned int _multicastPrefixBits; // memoized from _configuration
|
||||
unsigned int _multicastDepth; // memoized from _configuration
|
||||
CertificateOfMembership _myCertificate;
|
||||
MulticastRates _mcRates;
|
||||
std::set<InetAddress> _staticAddresses;
|
||||
bool _isOpen;
|
||||
unsigned int _multicastPrefixBits;
|
||||
unsigned int _multicastDepth;
|
||||
|
||||
// Ethertype whitelist bit field, set from config, for really fast lookup
|
||||
unsigned char _etWhitelist[65536 / 8];
|
||||
|
||||
// Network ID -- master node is most significant 40 bits
|
||||
uint64_t _id;
|
||||
|
||||
volatile uint64_t _lastConfigUpdate;
|
||||
volatile bool _destroyOnDelete;
|
||||
volatile bool _ready;
|
||||
|
@ -553,10 +553,7 @@ public:
|
||||
|
||||
/* Network member certificate for sending peer:
|
||||
* <[8] 64-bit network ID>
|
||||
* <[2] 16-bit length of certificate>
|
||||
* <[2] 16-bit length of signature>
|
||||
* <[...] string-serialized certificate dictionary>
|
||||
* <[...] signature of certificate>
|
||||
* <[...] serialized certificate of membership>
|
||||
*
|
||||
* OK is generated on acceptance. ERROR is returned on failure. In both
|
||||
* cases the payload is the network ID.
|
||||
|
Loading…
Reference in New Issue
Block a user