Automagically push netconf certs -- Network support.

This commit is contained in:
Adam Ierymenko 2013-10-07 16:13:52 -04:00
parent b4ae1adfbf
commit 4d594b24bc
5 changed files with 125 additions and 30 deletions

View File

@ -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];

View File

@ -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
{

View File

@ -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.

View File

@ -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;

View File

@ -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.