diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-10-07 16:13:52 -0400 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2013-10-07 16:13:52 -0400 |
commit | 4d594b24bc992962c125b3c0ff18ad4d670090c3 (patch) | |
tree | 2bb43d592adf725efa8441e70088b34e2190b65f /node | |
parent | b4ae1adfbffecc090357b4e9e5c04ec3b2d3280d (diff) | |
download | infinitytier-4d594b24bc992962c125b3c0ff18ad4d670090c3.tar.gz infinitytier-4d594b24bc992962c125b3c0ff18ad4d670090c3.zip |
Automagically push netconf certs -- Network support.
Diffstat (limited to 'node')
-rw-r--r-- | node/CertificateOfMembership.cpp | 9 | ||||
-rw-r--r-- | node/CertificateOfMembership.hpp | 67 | ||||
-rw-r--r-- | node/Network.cpp | 24 | ||||
-rw-r--r-- | node/Network.hpp | 50 | ||||
-rw-r--r-- | node/Packet.hpp | 5 |
5 files changed, 125 insertions, 30 deletions
diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp index 0944851a..c0385fb7 100644 --- a/node/CertificateOfMembership.cpp +++ b/node/CertificateOfMembership.cpp @@ -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]; diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index 99d784b2..7ae60ba1 100644 --- a/node/CertificateOfMembership.hpp +++ b/node/CertificateOfMembership.hpp @@ -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 @@ -97,6 +99,19 @@ public: 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 * * Any signature is invalidated and signedBy is set to null. @@ -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 { diff --git a/node/Network.cpp b/node/Network.cpp index 911ae998..2d08a91f 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -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. diff --git a/node/Network.hpp b/node/Network.hpp index 9f43c957..64e01c57 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -470,6 +470,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; diff --git a/node/Packet.hpp b/node/Packet.hpp index 36858479..54117664 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -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. |