summaryrefslogtreecommitdiff
path: root/node
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2013-10-07 16:13:52 -0400
committerAdam Ierymenko <adam.ierymenko@gmail.com>2013-10-07 16:13:52 -0400
commit4d594b24bc992962c125b3c0ff18ad4d670090c3 (patch)
tree2bb43d592adf725efa8441e70088b34e2190b65f /node
parentb4ae1adfbffecc090357b4e9e5c04ec3b2d3280d (diff)
downloadinfinitytier-4d594b24bc992962c125b3c0ff18ad4d670090c3.tar.gz
infinitytier-4d594b24bc992962c125b3c0ff18ad4d670090c3.zip
Automagically push netconf certs -- Network support.
Diffstat (limited to 'node')
-rw-r--r--node/CertificateOfMembership.cpp9
-rw-r--r--node/CertificateOfMembership.hpp67
-rw-r--r--node/Network.cpp24
-rw-r--r--node/Network.hpp50
-rw-r--r--node/Packet.hpp5
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.