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

This commit is contained in:
Adam Ierymenko 2016-07-28 10:58:10 -07:00
parent 1e6e112806
commit 22e44c762b
7 changed files with 92 additions and 92 deletions

View File

@ -66,8 +66,8 @@
// Stored in database as schemaVersion key in Config. // Stored in database as schemaVersion key in Config.
// If not present, database is assumed to be empty and at the current schema version // If not present, database is assumed to be empty and at the current schema version
// and this key/value is added automatically. // and this key/value is added automatically.
#define ZT_NETCONF_SQLITE_SCHEMA_VERSION 4 #define ZT_NETCONF_SQLITE_SCHEMA_VERSION 5
#define ZT_NETCONF_SQLITE_SCHEMA_VERSION_STR "4" #define ZT_NETCONF_SQLITE_SCHEMA_VERSION_STR "5"
// API version reported via JSON control plane // API version reported via JSON control plane
#define ZT_NETCONF_CONTROLLER_API_VERSION 2 #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) { if (schemaVersion != ZT_NETCONF_SQLITE_SCHEMA_VERSION) {
sqlite3_close(_db); sqlite3_close(_db);
throw std::runtime_error("SqliteNetworkController database schema version mismatch"); 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) ||(sqlite3_prepare_v2(_db,"INSERT OR REPLACE INTO Node (id,identity) VALUES (?,?)",-1,&_sCreateOrReplaceNode,(const char **)0) != SQLITE_OK)
/* Rule */ /* 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,ztSource,ztDest,vlanId,vlanPcp,vlanDei,) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",-1,&_sCreateRule,(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,"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,"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) ||(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(_sCreateMember);
sqlite3_finalize(_sGetNodeIdentity); sqlite3_finalize(_sGetNodeIdentity);
sqlite3_finalize(_sCreateOrReplaceNode); sqlite3_finalize(_sCreateOrReplaceNode);
sqlite3_finalize(_sGetEtherTypesFromRuleTable);
sqlite3_finalize(_sGetActiveBridges); sqlite3_finalize(_sGetActiveBridges);
sqlite3_finalize(_sGetIpAssignmentsForNode); sqlite3_finalize(_sGetIpAssignmentsForNode);
sqlite3_finalize(_sGetIpAssignmentPools); sqlite3_finalize(_sGetIpAssignmentPools);

View File

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

View File

@ -96,24 +96,15 @@ CREATE UNIQUE INDEX Relay_networkId_address ON Relay (networkId,address);
CREATE TABLE Rule ( CREATE TABLE Rule (
networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE, networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
policyId varchar(32),
ruleNo integer NOT NULL, ruleNo integer NOT NULL,
nodeId char(10) REFERENCES Node(id), ruleType integer NOT NULL DEFAULT(0),
sourcePort char(10), "addr" blob(16),
destPort char(10), "int1" integer,
vlanId integer, "int2" integer,
vlanPcp integer, "int3" integer,
etherType integer, "int4" 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')
); );
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);

View File

@ -97,25 +97,16 @@
"\n"\ "\n"\
"CREATE TABLE Rule (\n"\ "CREATE TABLE Rule (\n"\
" networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"\ " networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"\
" policyId varchar(32),\n"\
" ruleNo integer NOT NULL,\n"\ " ruleNo integer NOT NULL,\n"\
" nodeId char(10) REFERENCES Node(id),\n"\ " ruleType integer NOT NULL DEFAULT(0),\n"\
" sourcePort char(10),\n"\ " \"addr\" blob(16),\n"\
" destPort char(10),\n"\ " \"int1\" integer,\n"\
" vlanId integer,\n"\ " \"int2\" integer,\n"\
" vlanPcp integer,\n"\ " \"int3\" integer,\n"\
" etherType integer,\n"\ " \"int4\" 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"\
");\n"\ ");\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"\
"" ""

View File

@ -391,12 +391,15 @@ enum ZT_VirtualNetworkType
/** /**
* The type of a virtual network rules table entry * 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. * Each rule is composed of one or more MATCHes followed by an ACTION.
*/ */
enum ZT_VirtualNetworkRuleType enum ZT_VirtualNetworkRuleType
{ {
// 0 to 31 reserved for actions
/** /**
* Drop frame * Drop frame
*/ */
@ -408,16 +411,16 @@ enum ZT_VirtualNetworkRuleType
ZT_NETWORK_RULE_ACTION_ACCEPT = 1, 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, 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, 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 * Source ZeroTier address -- analogous to an Ethernet port ID on a switch

View File

@ -44,9 +44,9 @@
#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)
/** /**
* 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 { namespace ZeroTier {
@ -87,14 +87,15 @@ public:
*/ */
enum Type 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 * Reserved qualifier IDs
* *
* IDs below 65536 should be considered reserved for future global * IDs below 1024 are reserved for use as standard IDs. Others are available
* assignment here. * for user-defined use.
* *
* Addition of new required fields requires that code in hasRequiredFields * Addition of new required fields requires that code in hasRequiredFields
* be updated as well. * be updated as well.
@ -126,12 +127,11 @@ public:
}; };
/** /**
* Create an empty certificate * Create an empty certificate of membership
*/ */
CertificateOfMembership() : CertificateOfMembership()
_qualifierCount(0)
{ {
memset(_signature.data,0,_signature.size()); memset(this,0,sizeof(CertificateOfMembership));
} }
CertificateOfMembership(const CertificateOfMembership &c) CertificateOfMembership(const CertificateOfMembership &c)
@ -168,22 +168,6 @@ public:
return *this; 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 * Create from binary-serialized COM in buffer
* *
@ -201,24 +185,6 @@ public:
*/ */
inline operator bool() const throw() { return (_qualifierCount != 0); } 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 * @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); 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); } 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 #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
/** /**
* @return String-serialized representation of this certificate * @return String-serialized representation of this certificate

View File

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