mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-08 03:34:14 +00:00
Add a timestamp to netconf cache, fix some SQL queries in NC.
This commit is contained in:
parent
417f56de2f
commit
740121504f
@ -37,6 +37,9 @@
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "../include/ZeroTierOne.h"
|
||||
#include "../node/Constants.hpp"
|
||||
|
||||
#include "SqliteNetworkController.hpp"
|
||||
#include "../node/Utils.hpp"
|
||||
#include "../node/CertificateOfMembership.hpp"
|
||||
@ -52,6 +55,9 @@
|
||||
#define ZT_NETCONF_SQLITE_SCHEMA_VERSION 1
|
||||
#define ZT_NETCONF_SQLITE_SCHEMA_VERSION_STR "1"
|
||||
|
||||
// Maximum age in ms for a cached netconf before we regenerate anyway (one hour)
|
||||
#define ZT_CACHED_NETCONF_MAX_AGE (60 * 60 * 1000)
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
|
||||
@ -63,10 +69,11 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
|
||||
sqlite3_busy_timeout(_db,10000);
|
||||
|
||||
sqlite3_stmt *s = (sqlite3_stmt *)0;
|
||||
if ((sqlite3_prepare_v2(_db,"SELECT 'v' FROM Config WHERE 'k' = 'schemaVersion';",-1,&s,(const char **)0) == SQLITE_OK)&&(s)) {
|
||||
if ((sqlite3_prepare_v2(_db,"SELECT v FROM Config WHERE k = 'schemaVersion';",-1,&s,(const char **)0) == SQLITE_OK)&&(s)) {
|
||||
int schemaVersion = -1234;
|
||||
if (sqlite3_step(s) == SQLITE_ROW)
|
||||
if (sqlite3_step(s) == SQLITE_ROW) {
|
||||
schemaVersion = sqlite3_column_int(s,0);
|
||||
}
|
||||
|
||||
sqlite3_finalize(s);
|
||||
|
||||
@ -88,22 +95,22 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
|
||||
}
|
||||
|
||||
if (
|
||||
(sqlite3_prepare_v2(_db,"SELECT 'name','private','enableBroadcast','allowPassiveBridging','v4AssignMode','v6AssignMode','multicastLimit','revision' FROM Network WHERE 'id' = ?",-1,&_sGetNetworkById,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT rowid,'cachedNetconf','cachedNetconfRevision','clientReportedRevision','authorized','activeBridge' FROM Member WHERE 'networkId' = ? AND 'nodeId' = ?",-1,&_sGetMemberByNetworkAndNodeId,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"INSERT INTO Member ('networkId','nodeId','cachedNetconfRevision','clientReportedRevision','authorized','activeBridge') VALUES (?,?,0,0,?,0)",-1,&_sCreateMember,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT 'identity' FROM Node WHERE 'id' = ?",-1,&_sGetNodeIdentity,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"INSERT INTO Node ('id','identity','lastAt','lastSeen','firstSeen') VALUES (?,?,?,?,?)",-1,&_sCreateNode,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"UPDATE Node SET 'lastAt' = ?,'lastSeen' = ? WHERE 'id' = ?",-1,&_sUpdateNode,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"UPDATE Node SET 'lastSeen' = ? WHERE 'id' = ?",-1,&_sUpdateNode2,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"UPDATE Member SET 'clientReportedRevision' = ? WHERE rowid = ?",-1,&_sUpdateMemberClientReportedRevision,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT 'etherType' FROM Rule WHERE 'networkId' = ? AND 'action' = 'accept'",-1,&_sGetEtherTypesFromRuleTable,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT 'mgMac','mgAdi','preload','maxBalance','accrual' FROM MulticastRate WHERE 'networkId' = ?",-1,&_sGetMulticastRates,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT 'nodeId' FROM Member WHERE 'networkId' = ? AND 'authorized' > 0 AND 'activeBridge' > 0",-1,&_sGetActiveBridges,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT DISTINCT 'ip','ipNetmaskBits' FROM IpAssignment WHERE 'networkId' = ? AND 'nodeId' = ? AND 'ipVersion' = ?",-1,&_sGetIpAssignmentsForNode,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT DISTINCT 'ipNetwork','ipNetmaskBits' FROM IpAssignmentPool WHERE 'networkId' = ? AND 'ipVersion' = ? AND 'active' > 0",-1,&_sGetIpAssignmentPools,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT 1 FROM IpAssignment WHERE 'networkId' = ? AND 'ip' = ? AND 'ipVersion' = ?",-1,&_sCheckIfIpIsAllocated,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"INSERT INTO IpAssignment ('networkId','nodeId','ip','ipNetmaskBits','ipVersion') VALUES (?,?,?,?,?)",-1,&_sAllocateIp,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"UPDATE Member SET 'cachedNetconf' = ?,'cachedNetconfRevision' = ? WHERE rowid = ?",-1,&_sCacheNetconf,(const char **)0) != SQLITE_OK)
|
||||
(sqlite3_prepare_v2(_db,"SELECT name,private,enableBroadcast,allowPassiveBridging,v4AssignMode,v6AssignMode,multicastLimit,revision FROM Network WHERE id = ?",-1,&_sGetNetworkById,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT rowid,cachedNetconf,cachedNetconfRevision,cachedNetconfTimestamp,clientReportedRevision,authorized,activeBridge FROM Member WHERE networkId = ? AND nodeId = ?",-1,&_sGetMemberByNetworkAndNodeId,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"INSERT INTO Member (networkId,nodeId,cachedNetconfRevision,clientReportedRevision,authorized,activeBridge) VALUES (?,?,0,0,?,0)",-1,&_sCreateMember,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT identity FROM Node WHERE id = ?",-1,&_sGetNodeIdentity,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"INSERT INTO Node (id,identity,lastAt,lastSeen,firstSeen) VALUES (?,?,?,?,?)",-1,&_sCreateNode,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"UPDATE Node SET lastAt = ?,lastSeen = ? WHERE id = ?",-1,&_sUpdateNode,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"UPDATE Node SET lastSeen = ? WHERE id = ?",-1,&_sUpdateNode2,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"UPDATE Member SET clientReportedRevision = ? WHERE rowid = ?",-1,&_sUpdateMemberClientReportedRevision,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT etherType FROM Rule WHERE networkId = ? AND \"action\" = 'accept'",-1,&_sGetEtherTypesFromRuleTable,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT mgMac,mgAdi,preload,maxBalance,accrual FROM MulticastRate WHERE networkId = ?",-1,&_sGetMulticastRates,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT nodeId FROM Member WHERE networkId = ? AND authorized > 0 AND activeBridge > 0",-1,&_sGetActiveBridges,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT DISTINCT ip,ipNetmaskBits FROM IpAssignment WHERE networkId = ? AND nodeId = ? AND ipVersion = ?",-1,&_sGetIpAssignmentsForNode,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT DISTINCT ipNetwork,ipNetmaskBits FROM IpAssignmentPool WHERE networkId = ? AND ipVersion = ? AND active > 0",-1,&_sGetIpAssignmentPools,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT 1 FROM IpAssignment WHERE networkId = ? AND ip = ? AND ipVersion = ?",-1,&_sCheckIfIpIsAllocated,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"INSERT INTO IpAssignment (networkId,nodeId,ip,ipNetmaskBits,ipVersion) VALUES (?,?,?,?,?)",-1,&_sAllocateIp,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"UPDATE Member SET cachedNetconf = ?,cachedNetconfRevision = ? WHERE rowid = ?",-1,&_sCacheNetconf,(const char **)0) != SQLITE_OK)
|
||||
) {
|
||||
sqlite3_close(_db);
|
||||
throw std::runtime_error("SqliteNetworkController unable to initialize one or more prepared statements");
|
||||
@ -166,6 +173,7 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
|
||||
int cachedNetconfBytes;
|
||||
const void *cachedNetconf;
|
||||
uint64_t cachedNetconfRevision;
|
||||
uint64_t cachedNetconfTimestamp;
|
||||
uint64_t clientReportedRevision;
|
||||
bool authorized;
|
||||
bool activeBridge;
|
||||
@ -252,9 +260,10 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
|
||||
member.cachedNetconfBytes = sqlite3_column_bytes(_sGetMemberByNetworkAndNodeId,1);
|
||||
member.cachedNetconf = sqlite3_column_blob(_sGetMemberByNetworkAndNodeId,1);
|
||||
member.cachedNetconfRevision = (uint64_t)sqlite3_column_int64(_sGetMemberByNetworkAndNodeId,2);
|
||||
member.clientReportedRevision = (uint64_t)sqlite3_column_int64(_sGetMemberByNetworkAndNodeId,3);
|
||||
member.authorized = (sqlite3_column_int(_sGetMemberByNetworkAndNodeId,4) > 0);
|
||||
member.activeBridge = (sqlite3_column_int(_sGetMemberByNetworkAndNodeId,5) > 0);
|
||||
member.cachedNetconfTimestamp = (uint64_t)sqlite3_column_int64(_sGetMemberByNetworkAndNodeId,3);
|
||||
member.clientReportedRevision = (uint64_t)sqlite3_column_int64(_sGetMemberByNetworkAndNodeId,4);
|
||||
member.authorized = (sqlite3_column_int(_sGetMemberByNetworkAndNodeId,5) > 0);
|
||||
member.activeBridge = (sqlite3_column_int(_sGetMemberByNetworkAndNodeId,6) > 0);
|
||||
}
|
||||
|
||||
// Create Member record for unknown nodes, auto-authorizing if network is public
|
||||
@ -297,7 +306,9 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
|
||||
// Generate or retrieve cached netconf
|
||||
|
||||
netconf.clear();
|
||||
if ((member.cachedNetconfRevision == network.revision)&&(member.cachedNetconfBytes > 0)) {
|
||||
if ( (member.cachedNetconfBytes > 0)&&
|
||||
(member.cachedNetconfRevision == network.revision)&&
|
||||
((OSUtils::now() - member.cachedNetconfTimestamp) < ZT_CACHED_NETCONF_MAX_AGE) ) {
|
||||
// Use cached copy
|
||||
std::string tmp((const char *)member.cachedNetconf,member.cachedNetconfBytes);
|
||||
netconf.fromString(tmp);
|
||||
@ -450,7 +461,7 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
|
||||
// TODO: IPv6 auto-assign once it's supported in UI
|
||||
|
||||
if (network.isPrivate) {
|
||||
CertificateOfMembership com(network.revision,16,nwid,identity.address());
|
||||
CertificateOfMembership com(network.revision,ZT1_CERTIFICATE_OF_MEMBERSHIP_REVISION_MAX_DELTA,nwid,identity.address());
|
||||
if (com.sign(signingId)) // basically can't fail unless our identity is invalid
|
||||
netconf[ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP] = com.toString();
|
||||
else {
|
||||
|
@ -32,6 +32,7 @@ CREATE TABLE Member (
|
||||
nodeId char(10) NOT NULL,
|
||||
cachedNetconf blob(4096),
|
||||
cachedNetconfRevision integer NOT NULL DEFAULT(0),
|
||||
cachedNetconfTimestamp integer NOT NULL DEFAULT(0),
|
||||
clientReportedRevision integer NOT NULL DEFAULT(0),
|
||||
authorized integer NOT NULL DEFAULT(0),
|
||||
activeBridge integer NOT NULL DEFAULT(0)
|
||||
|
@ -33,6 +33,7 @@
|
||||
" nodeId char(10) NOT NULL,\n"\
|
||||
" cachedNetconf blob(4096),\n"\
|
||||
" cachedNetconfRevision integer NOT NULL DEFAULT(0),\n"\
|
||||
" cachedNetconfTimestamp integer NOT NULL DEFAULT(0),\n"\
|
||||
" clientReportedRevision integer NOT NULL DEFAULT(0),\n"\
|
||||
" authorized integer NOT NULL DEFAULT(0),\n"\
|
||||
" activeBridge integer NOT NULL DEFAULT(0)\n"\
|
||||
|
@ -103,6 +103,17 @@ extern "C" {
|
||||
*/
|
||||
#define ZT1_MAX_PEER_NETWORK_PATHS 4
|
||||
|
||||
/**
|
||||
* Maximum number of revisions over which a network COM can differ and still be in-horizon (agree)
|
||||
*
|
||||
* This is the default max delta for the revision field in COMs issued
|
||||
* by network controllers, and is defined here for documentation purposes.
|
||||
* When a network is changed so as to de-authorize a member, its revision
|
||||
* should be incremented by this number. Otherwise all other changes that
|
||||
* materially affect the network should result in increment by one.
|
||||
*/
|
||||
#define ZT1_CERTIFICATE_OF_MEMBERSHIP_REVISION_MAX_DELTA 16
|
||||
|
||||
/**
|
||||
* Feature flag: ZeroTier One was built to be thread-safe -- concurrent processXXX() calls are okay
|
||||
*/
|
||||
|
23
selftest.cpp
23
selftest.cpp
@ -720,13 +720,25 @@ static int testPhy()
|
||||
static int testSqliteNetworkController()
|
||||
{
|
||||
#ifdef ZT_ENABLE_NETWORK_CONTROLLER
|
||||
|
||||
OSUtils::rm("./selftest_network_controller.db");
|
||||
|
||||
try {
|
||||
std::cout << "[network-controller] Generating signing identity..." << std::endl;
|
||||
Identity signingId;
|
||||
signingId.generate();
|
||||
|
||||
std::cout << "[network-controller] Creating database..." << std::endl;
|
||||
SqliteNetworkController controller(signingId,"network-controller-test.db");
|
||||
{
|
||||
std::cout << "[network-controller] Creating database..." << std::endl;
|
||||
SqliteNetworkController controller("./selftest_network_controller.db");
|
||||
std::cout << "[network-controller] Closing database..." << std::endl;
|
||||
}
|
||||
|
||||
{
|
||||
std::cout << "[network-controller] Re-opening database..." << std::endl;
|
||||
SqliteNetworkController controller("./selftest_network_controller.db");
|
||||
std::cout << "[network-controller] Closing database..." << std::endl;
|
||||
}
|
||||
} catch (std::runtime_error &exc) {
|
||||
std::cout << "FAIL! (unexpected exception: " << exc.what() << ")" << std::endl;
|
||||
return -1;
|
||||
@ -734,6 +746,9 @@ static int testSqliteNetworkController()
|
||||
std::cout << "FAIL! (unexpected exception: ...)" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
OSUtils::rm("./selftest_network_controller.db");
|
||||
|
||||
#endif // ZT_ENABLE_NETWORK_CONTROLLER
|
||||
return 0;
|
||||
}
|
||||
@ -818,8 +833,8 @@ int main(int argc,char **argv)
|
||||
|
||||
srand((unsigned int)time(0));
|
||||
|
||||
r |= testPhy();
|
||||
r |= testHttp();
|
||||
//r |= testPhy();
|
||||
//r |= testHttp();
|
||||
r |= testSqliteNetworkController();
|
||||
r |= testCrypto();
|
||||
r |= testPacket();
|
||||
|
Loading…
x
Reference in New Issue
Block a user