diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp index 650517446..810178970 100644 --- a/controller/SqliteNetworkController.cpp +++ b/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); diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp index 145788c7d..b917f6fbf 100644 --- a/controller/SqliteNetworkController.hpp +++ b/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; diff --git a/controller/schema.sql b/controller/schema.sql index 105db924d..479daa68e 100644 --- a/controller/schema.sql +++ b/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); diff --git a/controller/schema.sql.c b/controller/schema.sql.c index dab34138b..e84ee7661 100644 --- a/controller/schema.sql.c +++ b/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"\ "" diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 0d1ddd4b6..6abc04f20 100644 --- a/include/ZeroTierOne.h +++ b/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 diff --git a/node/CertificateOfMembership.hpp b/node/CertificateOfMembership.hpp index 0342bc334..9f251f6b9 100644 --- a/node/CertificateOfMembership.hpp +++ b/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 diff --git a/osdep/Thread.hpp b/osdep/Thread.hpp index 4f90dc0bf..9f6fb5a86 100644 --- a/osdep/Thread.hpp +++ b/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() {