Pārlūkot izejas kodu

Compute credential TTL et al.

Adam Ierymenko 9 gadi atpakaļ
vecāks
revīzija
32fa061700

+ 40 - 4
controller/EmbeddedNetworkController.cpp

@@ -413,7 +413,7 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest(
 		lrt = now;
 	}
 
-	json network(_readJson(_networkJP(nwid,false)));
+	const json network(_readJson(_networkJP(nwid,false)));
 	if (!network.size())
 		return NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND;
 
@@ -458,7 +458,11 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest(
 		// If member already has an authorized field, leave it alone. That way its state is
 		// preserved if the user toggles the network back to private. Otherwise set it to
 		// true by default for new members of public nets.
-		if (!member.count("authorized")) member["authorized"] = true;
+		if (!member.count("authorized")) {
+			member["authorized"] = true;
+			member["lastAuthorizedTime"] = now;
+			member["lastAuthorizedBy"] = authorizedBy;
+		}
 	} else if (_jB(member["authorized"],false)) {
 		authorizedBy = "memberIsAuthorized";
 	} else {
@@ -476,6 +480,8 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest(
 							if ( ((expires == 0ULL)||(expires > now)) && (tok.length() > 0) && (tok == atok) ) {
 								authorizedBy = "token";
 								member["authorized"] = true; // tokens actually change member authorization state
+								member["lastAuthorizedTime"] = now;
+								member["lastAuthorizedBy"] = authorizedBy;
 								break;
 							}
 						}
@@ -517,14 +523,28 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest(
 		return NetworkController::NETCONF_QUERY_ACCESS_DENIED;
 	}
 
+	// -------------------------------------------------------------------------
 	// If we made it this far, they are authorized.
+	// -------------------------------------------------------------------------
 
 	_NetworkMemberInfo nmi;
 	_getNetworkMemberInfo(now,nwid,nmi);
 
+	// Compute credential TTL. This is the "moving window" for COM agreement and
+	// the global TTL for Capability and Tag objects. (The same value is used
+	// for both.) This is computed by reference to the last time we deauthorized
+	// a member, since within the time period since this event any temporal
+	// differences are not particularly relevant.
+	uint64_t credentialTtl = ZT_NETWORKCONFIG_DEFAULT_MIN_CREDENTIAL_TTL;
+	if (now > nmi.mostRecentDeauthTime)
+		credentialTtl += (now - nmi.mostRecentDeauthTime);
+	if (credentialTtl > ZT_NETWORKCONFIG_DEFAULT_MAX_CREDENTIAL_TTL)
+		credentialTtl = ZT_NETWORKCONFIG_DEFAULT_MAX_CREDENTIAL_TTL;
+
 	nc.networkId = nwid;
 	nc.type = _jB(network["private"],true) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC;
 	nc.timestamp = now;
+	nc.credentialTimeToLive = credentialTtl;
 	nc.revision = _jI(network["revision"],0ULL);
 	nc.issuedTo = identity.address();
 	if (_jB(network["enableBroadcast"],true)) nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST;
@@ -777,7 +797,7 @@ NetworkController::ResultCode EmbeddedNetworkController::doNetworkConfigRequest(
 	}
 
 	if (_jB(network["private"],true)) {
-		CertificateOfMembership com(now,ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA,nwid,identity.address());
+		CertificateOfMembership com(now,credentialTtl,nwid,identity.address());
 		if (com.sign(signingId)) {
 			nc.com = com;
 		} else {
@@ -976,10 +996,24 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
 					_initMember(member);
 
 					try {
-						if (b.count("authorized")) member["authorized"] = _jB(b["authorized"],false);
 						if (b.count("activeBridge")) member["activeBridge"] = _jB(b["activeBridge"],false);
 						if ((b.count("identity"))&&(!member.count("identity"))) member["identity"] = _jS(b["identity"],""); // allow identity to be populated only if not already known
 
+						if (b.count("authorized")) {
+							const bool newAuth = _jB(b["authorized"],false);
+							const bool oldAuth = _jB(member["authorized"],false);
+							if (newAuth != oldAuth) {
+								if (newAuth) {
+									member["authorized"] = true;
+									member["lastAuthorizedTime"] = now;
+									member["lastAuthorizedBy"] = "user";
+								} else {
+									member["authorized"] = false;
+									member["lastDeauthorizedTime"] = now;
+								}
+							}
+						}
+
 						if (b.count("ipAssignments")) {
 							auto ipa = b["ipAssignments"];
 							if (ipa.is_array()) {
@@ -1476,6 +1510,8 @@ void EmbeddedNetworkController::_getNetworkMemberInfo(uint64_t now,uint64_t nwid
 						nmi.allocatedIps.insert(mip);
 				}
 			}
+		} else {
+			nmi.mostRecentDeauthTime = std::max(nmi.mostRecentDeauthTime,_jI(nm->second["lastDeauthorizedTime"],0ULL));
 		}
 	}
 }

+ 6 - 2
controller/EmbeddedNetworkController.hpp

@@ -141,12 +141,13 @@ private:
 	// This does lock _networkMemberCache_m
 	struct _NetworkMemberInfo
 	{
-		_NetworkMemberInfo() : authorizedMemberCount(0),activeMemberCount(0),totalMemberCount(0) {}
+		_NetworkMemberInfo() : authorizedMemberCount(0),activeMemberCount(0),totalMemberCount(0),mostRecentDeauthTime(0) {}
 		std::set<Address> activeBridges;
 		std::set<InetAddress> allocatedIps;
 		unsigned long authorizedMemberCount;
 		unsigned long activeMemberCount;
 		unsigned long totalMemberCount;
+		uint64_t mostRecentDeauthTime;
 	};
 	void _getNetworkMemberInfo(uint64_t now,uint64_t nwid,_NetworkMemberInfo &nmi);
 
@@ -154,7 +155,10 @@ private:
 	inline void _initMember(nlohmann::json &member)
 	{
 		if (!member.count("authorized")) member["authorized"] = false;
-		if (!member.count("ipAssignments")) member["ipAssignments"] = nlohmann::json::array();
+		if (!member.count("lastAuthorizedTime")) member["lastAuthorizedTime"] = 0ULL;
+		if (!member.count("lastAuthorizedBy")) member["lastAuthorizedBy"] = "";
+		if (!member.count("lastDeauthorizedTime")) member["lastDeauthorizedTime"] = 0ULL;
+ 		if (!member.count("ipAssignments")) member["ipAssignments"] = nlohmann::json::array();
 		if (!member.count("recentLog")) member["recentLog"] = nlohmann::json::array();
 		if (!member.count("activeBridge")) member["activeBridge"] = false;
 		if (!member.count("tags")) member["tags"] = nlohmann::json::array();

+ 3 - 0
controller/README.md

@@ -208,6 +208,9 @@ This returns an object containing all currently online members and the most rece
 | nwid                  | string        | 16-digit network ID                               | no       |
 | clock                 | integer       | Current clock, ms since epoch                     | no       |
 | authorized            | boolean       | Is member authorized? (for private networks)      | YES      |
+| lastAuthorizedTime    | integer       | Time 'authorized' was last set to 'true'          | no       |
+| lastAuthorizedBy      | string        | What last set 'authorized' to 'true'?             | no       |
+| lastDeauthorizedTime  | integer       | Time 'authorized' was last set to 'false'         | no       |
 | activeBridge          | boolean       | Member is able to bridge to other Ethernet nets   | YES      |
 | identity              | string        | Member's public ZeroTier identity (if known)      | no       |
 | ipAssignments         | array[string] | Managed IP address assignments                    | YES      |

+ 0 - 5
node/CertificateOfMembership.hpp

@@ -33,11 +33,6 @@
 #include "Identity.hpp"
 #include "Utils.hpp"
 
-/**
- * Default window of time for certificate agreement
- */
-#define ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA (ZT_NETWORK_AUTOCONF_DELAY * 5)
-
 /**
  * Maximum number of qualifiers allowed in a COM (absolute max: 65535)
  */

+ 2 - 2
node/Membership.hpp

@@ -32,10 +32,10 @@
 #include "NetworkConfig.hpp"
 
 // Expiration time for capability and tag cache
-#define ZT_MEMBERSHIP_STATE_EXPIRATION_TIME (ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA * 4)
+#define ZT_MEMBERSHIP_STATE_EXPIRATION_TIME 600000
 
 // Expiration time for Memberships (used in Peer::clean())
-#define ZT_MEMBERSHIP_EXPIRATION_TIME (ZT_MEMBERSHIP_STATE_EXPIRATION_TIME * 4)
+#define ZT_MEMBERSHIP_EXPIRATION_TIME (ZT_MEMBERSHIP_STATE_EXPIRATION_TIME * 2)
 
 namespace ZeroTier {
 

+ 16 - 0
node/NetworkConfig.hpp

@@ -40,6 +40,22 @@
 #include "Dictionary.hpp"
 #include "Identity.hpp"
 
+/**
+ * Default maximum credential TTL and maxDelta for COM timestamps
+ *
+ * The current value is two hours, providing ample time for a controller to
+ * experience fail-over, etc.
+ */
+#define ZT_NETWORKCONFIG_DEFAULT_MAX_CREDENTIAL_TTL 7200000ULL
+
+/**
+ * Default minimum credential TTL and maxDelta for COM timestamps
+ *
+ * This is just slightly over three minutes and provides three retries for
+ * all currently online members to refresh.
+ */
+#define ZT_NETWORKCONFIG_DEFAULT_MIN_CREDENTIAL_TTL 185000ULL
+
 /**
  * Flag: allow passive bridging (experimental)
  */