Преглед изворни кода

More rules engine work: key/value pair matching for microsegmentation.

Adam Ierymenko пре 9 година
родитељ
комит
22e44c762b

+ 35 - 5
controller/SqliteNetworkController.cpp

@@ -66,8 +66,8 @@
 // Stored in database as schemaVersion key in Config.
 // If not present, database is assumed to be empty and at the current schema version
 // and this key/value is added automatically.
-#define ZT_NETCONF_SQLITE_SCHEMA_VERSION 4
-#define ZT_NETCONF_SQLITE_SCHEMA_VERSION_STR "4"
+#define ZT_NETCONF_SQLITE_SCHEMA_VERSION 5
+#define ZT_NETCONF_SQLITE_SCHEMA_VERSION_STR "5"
 
 // API version reported via JSON control plane
 #define ZT_NETCONF_CONTROLLER_API_VERSION 2
@@ -334,6 +334,38 @@ SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,c
 			}
 		}
 
+		if (schemaVersion < 5) {
+			// Upgrade old rough draft Rule table to new release format
+			if (sqlite3_exec(_db,
+					"DROP INDEX Rule_networkId_ruleNo;\n"
+					"ALTER TABLE \"Rule\" RENAME TO RuleOld;\n"
+					"CREATE TABLE Rule (\n"
+					"  networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"
+					"  policyId varchar(32),\n"
+					"  ruleNo integer NOT NULL,\n"
+					"  ruleType integer NOT NULL DEFAULT(0),\n"
+					"  \"addr\" blob(16),\n"
+					"  \"int1\" integer,\n"
+					"  \"int2\" integer,\n"
+					"  \"int3\" integer,\n"
+					"  \"int4\" integer\n"
+					");\n"
+					"INSERT INTO \"Rule\" SELECT networkId,(ruleNo*2) AS ruleNo,37 AS \"ruleType\",etherType AS \"int1\" FROM RuleOld WHERE RuleOld.etherType IS NOT NULL AND RuleOld.etherType > 0;\n"
+					"INSERT INTO \"Rule\" SELECT networkId,((ruleNo*2)+1) AS ruleNo,1 AS \"ruleType\" FROM RuleOld;\n"
+					"DROP TABLE RuleOld;\n"
+					"CREATE INDEX Rule_networkId_ruleNo ON Rule (networkId, ruleNo);\n"
+					"CREATE INDEX Rule_networkId_policyId ON Rule (networkId, policyId);\n"
+					"UPDATE \"Config\" SET \"v\" = 5 WHERE \"k\" = 'schemaVersion';\n"
+				,0,0,0) != SQLITE_OK) {
+				char err[1024];
+				Utils::snprintf(err,sizeof(err),"SqliteNetworkController cannot upgrade the database to version 3: %s",sqlite3_errmsg(_db));
+				sqlite3_close(_db);
+				throw std::runtime_error(err);
+			} else {
+				schemaVersion = 5;
+			}
+		}
+
 		if (schemaVersion != ZT_NETCONF_SQLITE_SCHEMA_VERSION) {
 			sqlite3_close(_db);
 			throw std::runtime_error("SqliteNetworkController database schema version mismatch");
@@ -365,8 +397,7 @@ SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,c
 			||(sqlite3_prepare_v2(_db,"INSERT OR REPLACE INTO Node (id,identity) VALUES (?,?)",-1,&_sCreateOrReplaceNode,(const char **)0) != SQLITE_OK)
 
 			/* Rule */
-			||(sqlite3_prepare_v2(_db,"SELECT etherType FROM Rule WHERE networkId = ? AND \"action\" = 'accept'",-1,&_sGetEtherTypesFromRuleTable,(const char **)0) != SQLITE_OK)
-			||(sqlite3_prepare_v2(_db,"INSERT INTO Rule (networkId,ruleNo,nodeId,sourcePort,destPort,vlanId,vlanPcP,etherType,macSource,macDest,ipSource,ipDest,ipTos,ipProtocol,ipSourcePort,ipDestPort,flags,invFlags,\"action\") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",-1,&_sCreateRule,(const char **)0) != SQLITE_OK)
+			||(sqlite3_prepare_v2(_db,"INSERT INTO Rule (networkId,ruleNo,nodeId,ztSource,ztDest,vlanId,vlanPcp,vlanDei,) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",-1,&_sCreateRule,(const char **)0) != SQLITE_OK)
 			||(sqlite3_prepare_v2(_db,"SELECT ruleNo,nodeId,sourcePort,destPort,vlanId,vlanPcp,etherType,macSource,macDest,ipSource,ipDest,ipTos,ipProtocol,ipSourcePort,ipDestPort,\"flags\",invFlags,\"action\" FROM Rule WHERE networkId = ? ORDER BY ruleNo ASC",-1,&_sListRules,(const char **)0) != SQLITE_OK)
 			||(sqlite3_prepare_v2(_db,"DELETE FROM Rule WHERE networkId = ?",-1,&_sDeleteRulesForNetwork,(const char **)0) != SQLITE_OK)
 
@@ -457,7 +488,6 @@ SqliteNetworkController::~SqliteNetworkController()
 		sqlite3_finalize(_sCreateMember);
 		sqlite3_finalize(_sGetNodeIdentity);
 		sqlite3_finalize(_sCreateOrReplaceNode);
-		sqlite3_finalize(_sGetEtherTypesFromRuleTable);
 		sqlite3_finalize(_sGetActiveBridges);
 		sqlite3_finalize(_sGetIpAssignmentsForNode);
 		sqlite3_finalize(_sGetIpAssignmentPools);

+ 0 - 1
controller/SqliteNetworkController.hpp

@@ -137,7 +137,6 @@ private:
 	sqlite3_stmt *_sCreateMember;
 	sqlite3_stmt *_sGetNodeIdentity;
 	sqlite3_stmt *_sCreateOrReplaceNode;
-	sqlite3_stmt *_sGetEtherTypesFromRuleTable;
 	sqlite3_stmt *_sGetActiveBridges;
 	sqlite3_stmt *_sGetIpAssignmentsForNode;
 	sqlite3_stmt *_sGetIpAssignmentPools;

+ 9 - 18
controller/schema.sql

@@ -96,24 +96,15 @@ CREATE UNIQUE INDEX Relay_networkId_address ON Relay (networkId,address);
 
 CREATE TABLE Rule (
   networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
+  policyId varchar(32),
   ruleNo integer NOT NULL,
-  nodeId char(10) REFERENCES Node(id),
-  sourcePort char(10),
-  destPort char(10),
-  vlanId integer,
-  vlanPcp integer,
-  etherType integer,
-  macSource char(12),
-  macDest char(12),
-  ipSource varchar(64),
-  ipDest varchar(64),
-  ipTos integer,
-  ipProtocol integer,
-  ipSourcePort integer,
-  ipDestPort integer,
-  flags integer,
-  invFlags integer,
-  "action" varchar(4096) NOT NULL DEFAULT('accept')
+  ruleType integer NOT NULL DEFAULT(0),
+  "addr" blob(16),
+  "int1" integer,
+  "int2" integer,
+  "int3" integer,
+  "int4" integer
 );
 
-CREATE UNIQUE INDEX Rule_networkId_ruleNo ON Rule (networkId, ruleNo);
+CREATE INDEX Rule_networkId_ruleNo ON Rule (networkId, ruleNo);
+CREATE INDEX Rule_networkId_policyId ON Rule (networkId, policyId);

+ 9 - 18
controller/schema.sql.c

@@ -97,25 +97,16 @@
 "\n"\
 "CREATE TABLE Rule (\n"\
 "  networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"\
+"  policyId varchar(32),\n"\
 "  ruleNo integer NOT NULL,\n"\
-"  nodeId char(10) REFERENCES Node(id),\n"\
-"  sourcePort char(10),\n"\
-"  destPort char(10),\n"\
-"  vlanId integer,\n"\
-"  vlanPcp integer,\n"\
-"  etherType integer,\n"\
-"  macSource char(12),\n"\
-"  macDest char(12),\n"\
-"  ipSource varchar(64),\n"\
-"  ipDest varchar(64),\n"\
-"  ipTos integer,\n"\
-"  ipProtocol integer,\n"\
-"  ipSourcePort integer,\n"\
-"  ipDestPort integer,\n"\
-"  flags integer,\n"\
-"  invFlags integer,\n"\
-"  \"action\" varchar(4096) NOT NULL DEFAULT('accept')\n"\
+"  ruleType integer NOT NULL DEFAULT(0),\n"\
+"  \"addr\" blob(16),\n"\
+"  \"int1\" integer,\n"\
+"  \"int2\" integer,\n"\
+"  \"int3\" integer,\n"\
+"  \"int4\" integer\n"\
 ");\n"\
 "\n"\
-"CREATE UNIQUE INDEX Rule_networkId_ruleNo ON Rule (networkId, ruleNo);\n"\
+"CREATE INDEX Rule_networkId_ruleNo ON Rule (networkId, ruleNo);\n"\
+"CREATE INDEX Rule_networkId_policyId ON Rule (networkId, policyId);\n"\
 ""

+ 7 - 4
include/ZeroTierOne.h

@@ -391,12 +391,15 @@ enum ZT_VirtualNetworkType
 /**
  * The type of a virtual network rules table entry
  *
- * These must range from 0 to 127 (0x7f).
+ * These must range from 0 to 127 (0x7f) because the most significant bit
+ * is reserved as a NOT flag.
  *
  * Each rule is composed of one or more MATCHes followed by an ACTION.
  */
 enum ZT_VirtualNetworkRuleType
 {
+	// 0 to 31 reserved for actions
+
 	/**
 	 * Drop frame
 	 */
@@ -408,16 +411,16 @@ enum ZT_VirtualNetworkRuleType
 	ZT_NETWORK_RULE_ACTION_ACCEPT = 1,
 
 	/**
-	 * Forward a copy of this frame to an observer
+	 * Forward a copy of this frame to an observer (by ZT address)
 	 */
 	ZT_NETWORK_RULE_ACTION_TEE = 2,
 
 	/**
-	 * Explicitly redirect this frame to another device (ignored if this is the target device)
+	 * Drop and redirect this frame to another node (by ZT address)
 	 */
 	ZT_NETWORK_RULE_ACTION_REDIRECT = 3,
 
-	// <32 == actions
+	// 32 to 127 reserved for match criteria
 
 	/**
 	 * Source ZeroTier address -- analogous to an Ethernet port ID on a switch

+ 24 - 43
node/CertificateOfMembership.hpp

@@ -44,9 +44,9 @@
 #define ZT_NETWORK_COM_DEFAULT_REVISION_MAX_DELTA (ZT_NETWORK_AUTOCONF_DELAY * 5)
 
 /**
- * Maximum number of qualifiers in a COM
+ * Maximum number of qualifiers allowed in a COM (absolute max: 65535)
  */
-#define ZT_NETWORK_COM_MAX_QUALIFIERS 16
+#define ZT_NETWORK_COM_MAX_QUALIFIERS 256
 
 namespace ZeroTier {
 
@@ -87,14 +87,15 @@ public:
 	 */
 	enum Type
 	{
-		COM_UINT64_ED25519 = 1 // tuples of unsigned 64's signed with Ed25519
+		// tuples of unsigned 64's signed with Ed25519
+		COM_UINT64_ED25519 = 1
 	};
 
 	/**
 	 * Reserved qualifier IDs
 	 *
-	 * IDs below 65536 should be considered reserved for future global
-	 * assignment here.
+	 * IDs below 1024 are reserved for use as standard IDs. Others are available
+	 * for user-defined use.
 	 *
 	 * Addition of new required fields requires that code in hasRequiredFields
 	 * be updated as well.
@@ -126,12 +127,11 @@ public:
 	};
 
 	/**
-	 * Create an empty certificate
+	 * Create an empty certificate of membership
 	 */
-	CertificateOfMembership() :
-		_qualifierCount(0)
+	CertificateOfMembership()
 	{
-		memset(_signature.data,0,_signature.size());
+		memset(this,0,sizeof(CertificateOfMembership));
 	}
 
 	CertificateOfMembership(const CertificateOfMembership &c)
@@ -168,22 +168,6 @@ public:
 		return *this;
 	}
 
-#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
-	/**
-	 * Create from string-serialized data
-	 *
-	 * @param s String-serialized COM
-	 */
-	CertificateOfMembership(const char *s) { fromString(s); }
-
-	/**
-	 * Create from string-serialized data
-	 *
-	 * @param s String-serialized COM
-	 */
-	CertificateOfMembership(const std::string &s) { fromString(s.c_str()); }
-#endif // ZT_SUPPORT_OLD_STYLE_NETCONF
-
 	/**
 	 * Create from binary-serialized COM in buffer
 	 *
@@ -201,24 +185,6 @@ public:
 	 */
 	inline operator bool() const throw() { return (_qualifierCount != 0); }
 
-	/**
-	 * Check for presence of all required fields common to all networks
-	 *
-	 * @return True if all required fields are present
-	 */
-	inline bool hasRequiredFields() const
-	{
-		if (_qualifierCount < 3)
-			return false;
-		if (_qualifiers[0].id != COM_RESERVED_ID_REVISION)
-			return false;
-		if (_qualifiers[1].id != COM_RESERVED_ID_NETWORK_ID)
-			return false;
-		if (_qualifiers[2].id != COM_RESERVED_ID_ISSUED_TO)
-			return false;
-		return true;
-	}
-
 	/**
 	 * @return Maximum delta for mandatory revision field or 0 if field missing
 	 */
@@ -279,6 +245,21 @@ public:
 	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); }
 
+	/**
+	 * Get the value of a qualifier field
+	 *
+	 * @param id Qualifier ID
+	 * @return Value or 0 if not found
+	 */
+	inline uint64_t getQualifierValue(uint64_t id)
+	{
+		for(unsigned int i=0;i<_qualifierCount;++i) {
+			if (_qualifiers[i].id == id)
+				return _qualifiers[i].value;
+		}
+		return 0;
+	}
+
 #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
 	/**
 	 * @return String-serialized representation of this certificate

+ 8 - 3
osdep/Thread.hpp

@@ -126,12 +126,17 @@ public:
 	{
 		memset(&_tid,0,sizeof(_tid));
 		pthread_attr_init(&_tattr);
-#ifdef __LINUX__
-		pthread_attr_setstacksize(&_tattr,8388608); // for MUSL libc and others, has no effect in normal glibc environments
-#endif
+		// This corrects for systems with abnormally small defaults (musl) and also
+		// shrinks the stack on systems with large defaults to save a bit of memory.
+		pthread_attr_setstacksize(&_tattr,524288);
 		_started = false;
 	}
 
+	~Thread()
+	{
+		pthread_attr_destroy(&_tattr);
+	}
+
 	Thread(const Thread &t)
 		throw()
 	{