Browse Source

Automagically push netconf certs -- Network support.

Adam Ierymenko 12 years ago
parent
commit
4d594b24bc
5 changed files with 125 additions and 30 deletions
  1. 9 0
      node/CertificateOfMembership.cpp
  2. 66 1
      node/CertificateOfMembership.hpp
  3. 24 0
      node/Network.cpp
  4. 25 25
      node/Network.hpp
  5. 1 4
      node/Packet.hpp

+ 9 - 0
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];

+ 66 - 1
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
@@ -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
 	{

+ 24 - 0
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.

+ 25 - 25
node/Network.hpp

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

+ 1 - 4
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.