Browse Source

Get rid of expiration in Capability and Tag and move this to NetworkConfig so it can be set network-wide and reset if needed. Also add NetworkConfig field for this and centralize checking of credential time validity.

Adam Ierymenko 9 years ago
parent
commit
9a3c652a51

+ 2 - 2
controller/EmbeddedNetworkController.cpp

@@ -576,7 +576,7 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest(
 							++caprc;
 							++caprc;
 					}
 					}
 				}
 				}
-				nc.capabilities[nc.capabilityCount] = Capability((uint32_t)capId,nwid,now,now + ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA,1,capr,caprc);
+				nc.capabilities[nc.capabilityCount] = Capability((uint32_t)capId,nwid,now,1,capr,caprc);
 				if (nc.capabilities[nc.capabilityCount].sign(signingId,identity.address()))
 				if (nc.capabilities[nc.capabilityCount].sign(signingId,identity.address()))
 					++nc.capabilityCount;
 					++nc.capabilityCount;
 				if (nc.capabilityCount >= ZT_MAX_NETWORK_CAPABILITIES)
 				if (nc.capabilityCount >= ZT_MAX_NETWORK_CAPABILITIES)
@@ -595,7 +595,7 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest(
 		for(std::map< uint32_t,uint32_t >::const_iterator t(tagsById.begin());t!=tagsById.end();++t) {
 		for(std::map< uint32_t,uint32_t >::const_iterator t(tagsById.begin());t!=tagsById.end();++t) {
 			if (nc.tagCount >= ZT_MAX_NETWORK_TAGS)
 			if (nc.tagCount >= ZT_MAX_NETWORK_TAGS)
 				break;
 				break;
-			nc.tags[nc.tagCount] = Tag(nwid,now,now + ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA,identity.address(),t->first,t->second);
+			nc.tags[nc.tagCount] = Tag(nwid,now,identity.address(),t->first,t->second);
 			if (nc.tags[nc.tagCount].sign(signingId))
 			if (nc.tags[nc.tagCount].sign(signingId))
 				++nc.tagCount;
 				++nc.tagCount;
 		}
 		}

+ 1 - 11
node/Capability.hpp

@@ -72,17 +72,15 @@ public:
 	 * @param id Capability ID
 	 * @param id Capability ID
 	 * @param nwid Network ID
 	 * @param nwid Network ID
 	 * @param ts Timestamp (at controller)
 	 * @param ts Timestamp (at controller)
-	 * @param expiration Expiration relative to network config timestamp
 	 * @param mccl Maximum custody chain length (1 to create non-transferrable capability)
 	 * @param mccl Maximum custody chain length (1 to create non-transferrable capability)
 	 * @param rules Network flow rules for this capability
 	 * @param rules Network flow rules for this capability
 	 * @param ruleCount Number of flow rules
 	 * @param ruleCount Number of flow rules
 	 */
 	 */
-	Capability(uint32_t id,uint64_t nwid,uint64_t ts,uint64_t expiration,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount)
+	Capability(uint32_t id,uint64_t nwid,uint64_t ts,unsigned int mccl,const ZT_VirtualNetworkRule *rules,unsigned int ruleCount)
 	{
 	{
 		memset(this,0,sizeof(Capability));
 		memset(this,0,sizeof(Capability));
 		_nwid = nwid;
 		_nwid = nwid;
 		_ts = ts;
 		_ts = ts;
-		_expiration = expiration;
 		_id = id;
 		_id = id;
 		_maxCustodyChainLength = (mccl > 0) ? ((mccl < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) ? mccl : (unsigned int)ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) : 1;
 		_maxCustodyChainLength = (mccl > 0) ? ((mccl < ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) ? mccl : (unsigned int)ZT_MAX_CAPABILITY_CUSTODY_CHAIN_LENGTH) : 1;
 		_ruleCount = (ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES;
 		_ruleCount = (ruleCount < ZT_MAX_CAPABILITY_RULES) ? ruleCount : ZT_MAX_CAPABILITY_RULES;
@@ -110,11 +108,6 @@ public:
 	 */
 	 */
 	inline uint64_t networkId() const { return _nwid; }
 	inline uint64_t networkId() const { return _nwid; }
 
 
-	/**
-	 * @return Expiration time relative to network config timestamp
-	 */
-	inline uint64_t expiration() const { return _expiration; }
-
 	/**
 	/**
 	 * @return Timestamp
 	 * @return Timestamp
 	 */
 	 */
@@ -343,7 +336,6 @@ public:
 		// These are the same between Tag and Capability
 		// These are the same between Tag and Capability
 		b.append(_nwid);
 		b.append(_nwid);
 		b.append(_ts);
 		b.append(_ts);
-		b.append(_expiration);
 		b.append(_id);
 		b.append(_id);
 
 
 		b.append((uint16_t)_ruleCount);
 		b.append((uint16_t)_ruleCount);
@@ -381,7 +373,6 @@ public:
 		// These are the same between Tag and Capability
 		// These are the same between Tag and Capability
 		_nwid = b.template at<uint64_t>(p); p += 8;
 		_nwid = b.template at<uint64_t>(p); p += 8;
 		_ts = b.template at<uint64_t>(p); p += 8;
 		_ts = b.template at<uint64_t>(p); p += 8;
-		_expiration = b.template at<uint64_t>(p); p += 8;
 		_id = b.template at<uint32_t>(p); p += 4;
 		_id = b.template at<uint32_t>(p); p += 4;
 
 
 		const unsigned int rc = b.template at<uint16_t>(p); p += 2;
 		const unsigned int rc = b.template at<uint16_t>(p); p += 2;
@@ -420,7 +411,6 @@ public:
 private:
 private:
 	uint64_t _nwid;
 	uint64_t _nwid;
 	uint64_t _ts;
 	uint64_t _ts;
-	uint64_t _expiration;
 	uint32_t _id;
 	uint32_t _id;
 
 
 	unsigned int _maxCustodyChainLength;
 	unsigned int _maxCustodyChainLength;

+ 12 - 37
node/CertificateOfMembership.hpp

@@ -35,11 +35,6 @@
 
 
 /**
 /**
  * Default window of time for certificate agreement
  * Default window of time for certificate agreement
- *
- * Right now we use time for 'revision' so this is the maximum time divergence
- * between two certs for them to agree. It comes out to five minutes, which
- * gives a lot of margin for error if the controller hiccups or its clock
- * drifts but causes de-authorized peers to fall off fast enough.
  */
  */
 #define ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA (ZT_NETWORK_AUTOCONF_DELAY * 5)
 #define ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA (ZT_NETWORK_AUTOCONF_DELAY * 5)
 
 
@@ -93,25 +88,17 @@ public:
 	enum ReservedId
 	enum ReservedId
 	{
 	{
 		/**
 		/**
-		 * Revision number of certificate
-		 *
-		 * Certificates may differ in revision number by a designated max
-		 * delta. Differences wider than this cause certificates not to agree.
+		 * Timestamp of certificate
 		 */
 		 */
-		COM_RESERVED_ID_REVISION = 0,
+		COM_RESERVED_ID_TIMESTAMP = 0,
 
 
 		/**
 		/**
 		 * Network ID for which certificate was issued
 		 * Network ID for which certificate was issued
-		 *
-		 * maxDelta here is zero, since this must match.
 		 */
 		 */
 		COM_RESERVED_ID_NETWORK_ID = 1,
 		COM_RESERVED_ID_NETWORK_ID = 1,
 
 
 		/**
 		/**
 		 * ZeroTier address to whom certificate was issued
 		 * ZeroTier address to whom certificate was issued
-		 *
-		 * maxDelta will be 0xffffffffffffffff here since it's permitted to differ
-		 * from peers obviously.
 		 */
 		 */
 		COM_RESERVED_ID_ISSUED_TO = 2
 		COM_RESERVED_ID_ISSUED_TO = 2
 	};
 	};
@@ -132,16 +119,16 @@ public:
 	/**
 	/**
 	 * Create from required fields common to all networks
 	 * Create from required fields common to all networks
 	 *
 	 *
-	 * @param revision Revision number of certificate
+	 * @param timestamp Timestamp of certificate
 	 * @param timestampMaxDelta Maximum variation between timestamps on this net
 	 * @param timestampMaxDelta Maximum variation between timestamps on this net
 	 * @param nwid Network ID
 	 * @param nwid Network ID
 	 * @param issuedTo Certificate recipient
 	 * @param issuedTo Certificate recipient
 	 */
 	 */
-	CertificateOfMembership(uint64_t revision,uint64_t revisionMaxDelta,uint64_t nwid,const Address &issuedTo)
+	CertificateOfMembership(uint64_t timestamp,uint64_t timestampMaxDelta,uint64_t nwid,const Address &issuedTo)
 	{
 	{
-		_qualifiers[0].id = COM_RESERVED_ID_REVISION;
-		_qualifiers[0].value = revision;
-		_qualifiers[0].maxDelta = revisionMaxDelta;
+		_qualifiers[0].id = COM_RESERVED_ID_TIMESTAMP;
+		_qualifiers[0].value = timestamp;
+		_qualifiers[0].maxDelta = timestampMaxDelta;
 		_qualifiers[1].id = COM_RESERVED_ID_NETWORK_ID;
 		_qualifiers[1].id = COM_RESERVED_ID_NETWORK_ID;
 		_qualifiers[1].value = nwid;
 		_qualifiers[1].value = nwid;
 		_qualifiers[1].maxDelta = 0;
 		_qualifiers[1].maxDelta = 0;
@@ -176,27 +163,15 @@ public:
 	inline operator bool() const throw() { return (_qualifierCount != 0); }
 	inline operator bool() const throw() { return (_qualifierCount != 0); }
 
 
 	/**
 	/**
-	 * @return Maximum delta for mandatory revision field or 0 if field missing
+	 * @return Timestamp for this cert and maximum delta for timestamp
 	 */
 	 */
-	inline uint64_t revisionMaxDelta() const
+	inline std::pair<uint64_t,uint64_t> timestamp() const
 	{
 	{
 		for(unsigned int i=0;i<_qualifierCount;++i) {
 		for(unsigned int i=0;i<_qualifierCount;++i) {
-			if (_qualifiers[i].id == COM_RESERVED_ID_REVISION)
-				return _qualifiers[i].maxDelta;
+			if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP)
+				return std::pair<uint64_t,uint64_t>(_qualifiers[i].value,_qualifiers[i].maxDelta);
 		}
 		}
-		return 0ULL;
-	}
-
-	/**
-	 * @return Revision number for this cert
-	 */
-	inline uint64_t revision() const
-	{
-		for(unsigned int i=0;i<_qualifierCount;++i) {
-			if (_qualifiers[i].id == COM_RESERVED_ID_REVISION)
-				return _qualifiers[i].value;
-		}
-		return 0ULL;
+		return std::pair<uint64_t,uint64_t>(0ULL,0ULL);
 	}
 	}
 
 
 	/**
 	/**

+ 1 - 1
node/Membership.cpp

@@ -86,7 +86,7 @@ int Membership::addCredential(const RuntimeEnvironment *RR,const CertificateOfMe
 	if (_com == com)
 	if (_com == com)
 		return 0;
 		return 0;
 	const int vr = com.verify(RR);
 	const int vr = com.verify(RR);
-	if ((vr == 0)&&(com.revision() > _com.revision()))
+	if ((vr == 0)&&(com.timestamp().first > _com.timestamp().first))
 		_com = com;
 		_com = com;
 	return vr;
 	return vr;
 }
 }

+ 5 - 5
node/Membership.hpp

@@ -84,10 +84,10 @@ public:
 		{
 		{
 		}
 		}
 
 
-		inline const Capability *next()
+		inline const Capability *next(const NetworkConfig &nconf)
 		{
 		{
 			while (_i != _e) {
 			while (_i != _e) {
-				if (_i->second.lastReceived)
+				if ((_i->second.lastReceived)&&(nconf.isCredentialTimestampValid(_i->second.cap)))
 					return &((_i++)->second.cap);
 					return &((_i++)->second.cap);
 				else ++_i;
 				else ++_i;
 			}
 			}
@@ -137,7 +137,7 @@ public:
 	inline const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const
 	inline const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const
 	{
 	{
 		const TState *t = _tags.get(id);
 		const TState *t = _tags.get(id);
-		return ((t) ? (((t->lastReceived != 0)&&(t->tag.expiration() < nconf.timestamp)) ? &(t->tag) : (const Tag *)0) : (const Tag *)0);
+		return ((t) ? (((t->lastReceived != 0)&&(nconf.isCredentialTimestampValid(t->tag))) ? &(t->tag) : (const Tag *)0) : (const Tag *)0);
 	}
 	}
 
 
 	/**
 	/**
@@ -154,7 +154,7 @@ public:
 		TState *ts = (TState *)0;
 		TState *ts = (TState *)0;
 		Hashtable<uint32_t,TState>::Iterator i(const_cast<Membership *>(this)->_tags);
 		Hashtable<uint32_t,TState>::Iterator i(const_cast<Membership *>(this)->_tags);
 		while (i.next(id,ts)) {
 		while (i.next(id,ts)) {
-			if ((ts->lastReceived)&&(ts->tag.expiration() < nconf.timestamp)) {
+			if ((ts->lastReceived)&&(nconf.isCredentialTimestampValid(ts->tag))) {
 				if (n >= maxTags)
 				if (n >= maxTags)
 					return n;
 					return n;
 				ids[n] = *id;
 				ids[n] = *id;
@@ -172,7 +172,7 @@ public:
 	inline const Capability *getCapability(const NetworkConfig &nconf,const uint32_t id) const
 	inline const Capability *getCapability(const NetworkConfig &nconf,const uint32_t id) const
 	{
 	{
 		std::map<uint32_t,CState>::const_iterator c(_caps.find(id));
 		std::map<uint32_t,CState>::const_iterator c(_caps.find(id));
-		return ((c != _caps.end()) ? (((c->second.lastReceived != 0)&&(c->second.cap.expiration() < nconf.timestamp)) ? &(c->second.cap) : (const Capability *)0) : (const Capability *)0);
+		return ((c != _caps.end()) ? (((c->second.lastReceived != 0)&&(nconf.isCredentialTimestampValid(c->second.cap))) ? &(c->second.cap) : (const Capability *)0) : (const Capability *)0);
 	}
 	}
 
 
 	/**
 	/**

+ 7 - 7
node/Network.cpp

@@ -102,7 +102,7 @@ static bool _ipv6GetPayload(const uint8_t *frameData,unsigned int frameLen,unsig
 // 0 == no match, -1 == match/drop, 1 == match/accept
 // 0 == no match, -1 == match/drop, 1 == match/accept
 static int _doZtFilter(
 static int _doZtFilter(
 	const RuntimeEnvironment *RR,
 	const RuntimeEnvironment *RR,
-	const uint64_t nwid,
+	const NetworkConfig &nconf,
 	const bool inbound,
 	const bool inbound,
 	const Address &ztSource,
 	const Address &ztSource,
 	const Address &ztDest,
 	const Address &ztDest,
@@ -155,7 +155,7 @@ static int _doZtFilter(
 			case ZT_NETWORK_RULE_ACTION_TEE:
 			case ZT_NETWORK_RULE_ACTION_TEE:
 			case ZT_NETWORK_RULE_ACTION_REDIRECT: {
 			case ZT_NETWORK_RULE_ACTION_REDIRECT: {
 				Packet outp(Address(rules[rn].v.zt),RR->identity.address(),Packet::VERB_EXT_FRAME);
 				Packet outp(Address(rules[rn].v.zt),RR->identity.address(),Packet::VERB_EXT_FRAME);
-				outp.append(nwid);
+				outp.append(nconf.networkId);
 				outp.append((uint8_t)((rt == ZT_NETWORK_RULE_ACTION_REDIRECT) ? 0x04 : 0x02));
 				outp.append((uint8_t)((rt == ZT_NETWORK_RULE_ACTION_REDIRECT) ? 0x04 : 0x02));
 				macDest.appendTo(outp);
 				macDest.appendTo(outp);
 				macSource.appendTo(outp);
 				macSource.appendTo(outp);
@@ -481,7 +481,7 @@ bool Network::filterOutgoingPacket(
 	Membership &m = _memberships[ztDest];
 	Membership &m = _memberships[ztDest];
 	const unsigned int remoteTagCount = m.getAllTags(_config,remoteTagIds,remoteTagValues,ZT_MAX_NETWORK_TAGS);
 	const unsigned int remoteTagCount = m.getAllTags(_config,remoteTagIds,remoteTagValues,ZT_MAX_NETWORK_TAGS);
 
 
-	switch(_doZtFilter(RR,_id,false,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,relevantLocalTags,relevantLocalTagCount)) {
+	switch(_doZtFilter(RR,_config,false,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,relevantLocalTags,relevantLocalTagCount)) {
 		case -1:
 		case -1:
 			return false;
 			return false;
 		case 1:
 		case 1:
@@ -491,7 +491,7 @@ bool Network::filterOutgoingPacket(
 
 
 	for(unsigned int c=0;c<_config.capabilityCount;++c) {
 	for(unsigned int c=0;c<_config.capabilityCount;++c) {
 		relevantLocalTagCount = 0;
 		relevantLocalTagCount = 0;
-		switch (_doZtFilter(RR,_id,false,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,relevantLocalTags,relevantLocalTagCount)) {
+		switch (_doZtFilter(RR,_config,false,ztSource,ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.capabilities[c].rules(),_config.capabilities[c].ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,relevantLocalTags,relevantLocalTagCount)) {
 			case -1:
 			case -1:
 				return false;
 				return false;
 			case 1:
 			case 1:
@@ -523,7 +523,7 @@ bool Network::filterIncomingPacket(
 	Membership &m = _memberships[ztDest];
 	Membership &m = _memberships[ztDest];
 	const unsigned int remoteTagCount = m.getAllTags(_config,remoteTagIds,remoteTagValues,ZT_MAX_NETWORK_TAGS);
 	const unsigned int remoteTagCount = m.getAllTags(_config,remoteTagIds,remoteTagValues,ZT_MAX_NETWORK_TAGS);
 
 
-	switch (_doZtFilter(RR,_id,true,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,relevantLocalTags,relevantLocalTagCount)) {
+	switch (_doZtFilter(RR,_config,true,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,_config.rules,_config.ruleCount,_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,relevantLocalTags,relevantLocalTagCount)) {
 		case -1:
 		case -1:
 			return false;
 			return false;
 		case 1:
 		case 1:
@@ -532,9 +532,9 @@ bool Network::filterIncomingPacket(
 
 
 	Membership::CapabilityIterator mci(m);
 	Membership::CapabilityIterator mci(m);
 	const Capability *c;
 	const Capability *c;
-	while ((c = mci.next())) {
+	while ((c = mci.next(_config))) {
 		relevantLocalTagCount = 0;
 		relevantLocalTagCount = 0;
-		switch(_doZtFilter(RR,_id,false,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,relevantLocalTags,relevantLocalTagCount)) {
+		switch(_doZtFilter(RR,_config,false,sourcePeer->address(),ztDest,macSource,macDest,frameData,frameLen,etherType,vlanId,c->rules(),c->ruleCount(),_config.tags,_config.tagCount,remoteTagIds,remoteTagValues,remoteTagCount,relevantLocalTags,relevantLocalTagCount)) {
 			case -1:
 			case -1:
 				return false;
 				return false;
 			case 1:
 			case 1:

+ 2 - 0
node/NetworkConfig.cpp

@@ -37,6 +37,7 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
 		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION)) return false;
 		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_VERSION,(uint64_t)ZT_NETWORKCONFIG_VERSION)) return false;
 		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,this->networkId)) return false;
 		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID,this->networkId)) return false;
 		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,this->timestamp)) return false;
 		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,this->timestamp)) return false;
+		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TTL,this->credentialTimeToLive)) return false;
 		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision)) return false;
 		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision)) return false;
 		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo)) return false;
 		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo)) return false;
 		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags)) return false;
 		if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags)) return false;
@@ -202,6 +203,7 @@ bool NetworkConfig::fromDictionary(const Identity &controllerId,Dictionary<ZT_NE
 			return false;
 			return false;
 		}
 		}
 		this->timestamp = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,0);
 		this->timestamp = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,0);
+		this->credentialTimeToLive = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TTL,0);
 		this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION,0);
 		this->revision = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_REVISION,0);
 		this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,0);
 		this->issuedTo = d.getUI(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,0);
 		if (!this->issuedTo) {
 		if (!this->issuedTo) {

+ 20 - 0
node/NetworkConfig.hpp

@@ -125,6 +125,8 @@ namespace ZeroTier {
 #define ZT_NETWORKCONFIG_DICT_KEY_TYPE "t"
 #define ZT_NETWORKCONFIG_DICT_KEY_TYPE "t"
 // text
 // text
 #define ZT_NETWORKCONFIG_DICT_KEY_NAME "n"
 #define ZT_NETWORKCONFIG_DICT_KEY_NAME "n"
+// credential time to live in ms
+#define ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TTL "cttl"
 // binary serialized certificate of membership
 // binary serialized certificate of membership
 #define ZT_NETWORKCONFIG_DICT_KEY_COM "C"
 #define ZT_NETWORKCONFIG_DICT_KEY_COM "C"
 // specialists (binary array of uint64_t)
 // specialists (binary array of uint64_t)
@@ -367,11 +369,24 @@ public:
 		return (Tag *)0;
 		return (Tag *)0;
 	}
 	}
 
 
+	/**
+	 * Check whether a capability or tag is expired
+	 *
+	 * @param cred Credential to check -- must have timestamp() accessor method
+	 * @return True if credential is NOT expired
+	 */
+	template<typename C>
+	inline bool isCredentialTimestampValid(const C &cred) const
+	{
+		return ( (cred.timestamp() >= timestamp) || ((timestamp - cred.timestamp()) <= credentialTimeToLive) );
+	}
+
 	/*
 	/*
 	inline void dump() const
 	inline void dump() const
 	{
 	{
 		printf("networkId==%.16llx\n",networkId);
 		printf("networkId==%.16llx\n",networkId);
 		printf("timestamp==%llu\n",timestamp);
 		printf("timestamp==%llu\n",timestamp);
+		printf("credentialTimeToLive==%llu\n",credentialTimeToLive);
 		printf("revision==%llu\n",revision);
 		printf("revision==%llu\n",revision);
 		printf("issuedTo==%.10llx\n",issuedTo.toInt());
 		printf("issuedTo==%.10llx\n",issuedTo.toInt());
 		printf("multicastLimit==%u\n",multicastLimit);
 		printf("multicastLimit==%u\n",multicastLimit);
@@ -405,6 +420,11 @@ public:
 	 */
 	 */
 	uint64_t timestamp;
 	uint64_t timestamp;
 
 
+	/**
+	 * TTL for capabilities and tags
+	 */
+	uint64_t credentialTimeToLive;
+
 	/**
 	/**
 	 * Controller-side revision counter for this configuration
 	 * Controller-side revision counter for this configuration
 	 */
 	 */

+ 1 - 7
node/Tag.hpp

@@ -62,15 +62,13 @@ public:
 	/**
 	/**
 	 * @param nwid Network ID
 	 * @param nwid Network ID
 	 * @param ts Timestamp
 	 * @param ts Timestamp
-	 * @param expiration Tag expiration relative to network config timestamp
 	 * @param issuedTo Address to which this tag was issued
 	 * @param issuedTo Address to which this tag was issued
 	 * @param id Tag ID
 	 * @param id Tag ID
 	 * @param value Tag value
 	 * @param value Tag value
 	 */
 	 */
-	Tag(const uint64_t nwid,const uint64_t ts,const uint64_t expiration,const Address &issuedTo,const uint32_t id,const uint32_t value) :
+	Tag(const uint64_t nwid,const uint64_t ts,const Address &issuedTo,const uint32_t id,const uint32_t value) :
 		_nwid(nwid),
 		_nwid(nwid),
 		_ts(ts),
 		_ts(ts),
-		_expiration(expiration),
 		_id(id),
 		_id(id),
 		_value(value),
 		_value(value),
 		_issuedTo(issuedTo),
 		_issuedTo(issuedTo),
@@ -79,7 +77,6 @@ public:
 	}
 	}
 
 
 	inline uint64_t networkId() const { return _nwid; }
 	inline uint64_t networkId() const { return _nwid; }
-	inline uint64_t expiration() const { return _expiration; }
 	inline uint64_t timestamp() const { return _ts; }
 	inline uint64_t timestamp() const { return _ts; }
 	inline uint32_t id() const { return _id; }
 	inline uint32_t id() const { return _id; }
 	inline const uint32_t &value() const { return _value; }
 	inline const uint32_t &value() const { return _value; }
@@ -120,7 +117,6 @@ public:
 		// These are the same between Tag and Capability
 		// These are the same between Tag and Capability
 		b.append(_nwid);
 		b.append(_nwid);
 		b.append(_ts);
 		b.append(_ts);
-		b.append(_expiration);
 		b.append(_id);
 		b.append(_id);
 
 
 		b.append(_value);
 		b.append(_value);
@@ -146,7 +142,6 @@ public:
 		// These are the same between Tag and Capability
 		// These are the same between Tag and Capability
 		_nwid = b.template at<uint64_t>(p); p += 8;
 		_nwid = b.template at<uint64_t>(p); p += 8;
 		_ts = b.template at<uint64_t>(p); p += 8;
 		_ts = b.template at<uint64_t>(p); p += 8;
-		_expiration = b.template at<uint64_t>(p); p += 8;
 		_id = b.template at<uint32_t>(p); p += 4;
 		_id = b.template at<uint32_t>(p); p += 4;
 
 
 		_value = b.template at<uint32_t>(p); p += 4;
 		_value = b.template at<uint32_t>(p); p += 4;
@@ -176,7 +171,6 @@ public:
 private:
 private:
 	uint64_t _nwid;
 	uint64_t _nwid;
 	uint64_t _ts;
 	uint64_t _ts;
-	uint64_t _expiration;
 	uint32_t _id;
 	uint32_t _id;
 	uint32_t _value;
 	uint32_t _value;
 	Address _issuedTo;
 	Address _issuedTo;