Starting refactor of controller...
This commit is contained in:
parent
dd21c8a577
commit
c30f74987f
8 changed files with 586 additions and 640 deletions
|
@ -37,16 +37,11 @@
|
|||
#include <utility>
|
||||
#include <stdexcept>
|
||||
#include <set>
|
||||
#include <map>
|
||||
|
||||
#include "../include/ZeroTierOne.h"
|
||||
#include "../node/Constants.hpp"
|
||||
|
||||
#ifdef ZT_USE_SYSTEM_JSON_PARSER
|
||||
#include <json-parser/json.h>
|
||||
#else
|
||||
#include "../ext/json-parser/json.h"
|
||||
#endif
|
||||
|
||||
#include "SqliteNetworkController.hpp"
|
||||
|
||||
#include "../node/Node.hpp"
|
||||
|
@ -60,17 +55,17 @@
|
|||
|
||||
#include "../osdep/OSUtils.hpp"
|
||||
|
||||
// Include ZT_NETCONF_SCHEMA_SQL constant to init database
|
||||
#include "schema.sql.c"
|
||||
// offbase includes and builds upon nlohmann::json
|
||||
using json = nlohmann::json;
|
||||
|
||||
// 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 5
|
||||
#define ZT_NETCONF_SQLITE_SCHEMA_VERSION_STR "5"
|
||||
//#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
|
||||
#define ZT_NETCONF_CONTROLLER_API_VERSION 3
|
||||
|
||||
// Number of requests to remember in member history
|
||||
#define ZT_NETCONF_DB_MEMBER_HISTORY_LENGTH 8
|
||||
|
@ -79,155 +74,19 @@
|
|||
#define ZT_NETCONF_MIN_REQUEST_PERIOD 1000
|
||||
|
||||
// Delay between backups in milliseconds
|
||||
#define ZT_NETCONF_BACKUP_PERIOD 300000
|
||||
//#define ZT_NETCONF_BACKUP_PERIOD 300000
|
||||
|
||||
// Nodes are considered active if they've queried in less than this long
|
||||
#define ZT_NETCONF_NODE_ACTIVE_THRESHOLD ((ZT_NETWORK_AUTOCONF_DELAY * 2) + 5000)
|
||||
|
||||
// Flags for Network 'flags' field in table
|
||||
#define ZT_DB_NETWORK_FLAG_ZT_MANAGED_V4_AUTO_ASSIGN 1
|
||||
#define ZT_DB_NETWORK_FLAG_ZT_MANAGED_V6_RFC4193 2
|
||||
#define ZT_DB_NETWORK_FLAG_ZT_MANAGED_V6_6PLANE 4
|
||||
#define ZT_DB_NETWORK_FLAG_ZT_MANAGED_V6_AUTO_ASSIGN 8
|
||||
|
||||
// Flags with all V6 managed mode flags flipped off -- for masking in update operation and in string form for SQL building
|
||||
#define ZT_DB_NETWORK_FLAG_ZT_MANAGED_V6_MASK_S "268435441"
|
||||
|
||||
// Uncomment to trace Sqlite for debugging
|
||||
//#define ZT_NETCONF_SQLITE_TRACE 1
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
namespace {
|
||||
|
||||
static std::string _jsonEscape(const char *s)
|
||||
{
|
||||
if (!s)
|
||||
return std::string();
|
||||
std::string buf;
|
||||
for(const char *p=s;(*p);++p) {
|
||||
switch(*p) {
|
||||
case '\t': buf.append("\\t"); break;
|
||||
case '\b': buf.append("\\b"); break;
|
||||
case '\r': buf.append("\\r"); break;
|
||||
case '\n': buf.append("\\n"); break;
|
||||
case '\f': buf.append("\\f"); break;
|
||||
case '"': buf.append("\\\""); break;
|
||||
case '\\': buf.append("\\\\"); break;
|
||||
case '/': buf.append("\\/"); break;
|
||||
default: buf.push_back(*p); break;
|
||||
}
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
static std::string _jsonEscape(const std::string &s) { return _jsonEscape(s.c_str()); }
|
||||
|
||||
// Converts an InetAddress to a blob and an int for storage in database
|
||||
static void _ipToBlob(const InetAddress &a,char *ipBlob,int &ipVersion) /* blob[16] */
|
||||
{
|
||||
switch(a.ss_family) {
|
||||
case AF_INET:
|
||||
memset(ipBlob,0,12);
|
||||
memcpy(ipBlob + 12,a.rawIpData(),4);
|
||||
ipVersion = 4;
|
||||
break;
|
||||
case AF_INET6:
|
||||
memcpy(ipBlob,a.rawIpData(),16);
|
||||
ipVersion = 6;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Member.recentHistory is stored in a BLOB as an array of strings containing JSON objects.
|
||||
// This is kind of hacky but efficient and quick to parse and send to the client.
|
||||
class MemberRecentHistory : public std::list<std::string>
|
||||
{
|
||||
public:
|
||||
inline std::string toBlob() const
|
||||
{
|
||||
std::string b;
|
||||
for(const_iterator i(begin());i!=end();++i) {
|
||||
b.append(*i);
|
||||
b.push_back((char)0);
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
inline void fromBlob(const char *blob,unsigned int len)
|
||||
{
|
||||
for(unsigned int i=0,k=0;i<len;++i) {
|
||||
if (!blob[i]) {
|
||||
push_back(std::string(blob + k,i - k));
|
||||
k = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct MemberRecord
|
||||
{
|
||||
sqlite3_int64 rowid;
|
||||
char nodeId[16];
|
||||
bool authorized;
|
||||
bool activeBridge;
|
||||
uint64_t lastRequestTime;
|
||||
MemberRecentHistory recentHistory;
|
||||
|
||||
MemberRecord() :
|
||||
rowid(0),
|
||||
authorized(false),
|
||||
activeBridge(false),
|
||||
lastRequestTime(0)
|
||||
{
|
||||
nodeId[0] = (char)0;
|
||||
}
|
||||
};
|
||||
|
||||
struct NetworkRecord
|
||||
{
|
||||
char id[24];
|
||||
const char *name;
|
||||
int flags;
|
||||
bool isPrivate;
|
||||
bool enableBroadcast;
|
||||
bool allowPassiveBridging;
|
||||
int multicastLimit;
|
||||
uint64_t creationTime;
|
||||
uint64_t revision;
|
||||
uint64_t memberRevisionCounter;
|
||||
|
||||
NetworkRecord() :
|
||||
name((const char *)0),
|
||||
flags(0),
|
||||
isPrivate(true),
|
||||
enableBroadcast(false),
|
||||
allowPassiveBridging(false),
|
||||
multicastLimit(0),
|
||||
creationTime(0),
|
||||
revision(0),
|
||||
memberRevisionCounter(0)
|
||||
{
|
||||
id[0] = (char)0;
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef ZT_NETCONF_SQLITE_TRACE
|
||||
static void sqliteTraceFunc(void *ptr,const char *s)
|
||||
{
|
||||
fprintf(stderr,"SQLITE: %s\n",s);
|
||||
}
|
||||
#endif
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,const char *circuitTestPath) :
|
||||
_node(node),
|
||||
_backupThreadRun(true),
|
||||
_backupNeeded(true),
|
||||
_dbPath(dbPath),
|
||||
_circuitTestPath(circuitTestPath),
|
||||
_db((sqlite3 *)0)
|
||||
_db(dbPath),
|
||||
_dbCommitThreadRun(true)
|
||||
{
|
||||
/*
|
||||
if (sqlite3_open_v2(dbPath,&_db,SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE,(const char *)0) != SQLITE_OK)
|
||||
throw std::runtime_error("SqliteNetworkController cannot open database file");
|
||||
sqlite3_busy_timeout(_db,10000);
|
||||
|
@ -337,11 +196,12 @@ 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 TABLE Relay;\n"
|
||||
"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"
|
||||
" capId integer,\n"
|
||||
" ruleNo integer NOT NULL,\n"
|
||||
" ruleType integer NOT NULL DEFAULT(0),\n"
|
||||
" \"addr\" blob(16),\n"
|
||||
|
@ -353,8 +213,16 @@ SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,c
|
|||
"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"
|
||||
"CREATE INDEX Rule_networkId_capId ON Rule (networkId,capId);\n"
|
||||
"CREATE TABLE MemberTC (\n"
|
||||
" networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"
|
||||
" nodeId char(10) NOT NULL REFERENCES Node(id) ON DELETE CASCADE,\n"
|
||||
" tagId integer,\n"
|
||||
" tagValue integer,\n"
|
||||
" capId integer,\n"
|
||||
" capMaxCustodyChainLength integer NOT NULL DEFAULT(1)\n"
|
||||
");\n"
|
||||
"CREATE INDEX MemberTC_networkId_nodeId ON MemberTC (networkId,nodeId);\n"
|
||||
"UPDATE \"Config\" SET \"v\" = 5 WHERE \"k\" = 'schemaVersion';\n"
|
||||
,0,0,0) != SQLITE_OK) {
|
||||
char err[1024];
|
||||
|
@ -383,7 +251,6 @@ SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,c
|
|||
|
||||
if (
|
||||
|
||||
/* Network */
|
||||
(sqlite3_prepare_v2(_db,"SELECT name,private,enableBroadcast,allowPassiveBridging,\"flags\",multicastLimit,creationTime,revision,memberRevisionCounter,(SELECT COUNT(1) FROM Member WHERE Member.networkId = Network.id AND Member.authorized > 0) FROM Network WHERE id = ?",-1,&_sGetNetworkById,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT revision FROM Network WHERE id = ?",-1,&_sGetNetworkRevision,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"UPDATE Network SET revision = ? WHERE id = ?",-1,&_sSetNetworkRevision,(const char **)0) != SQLITE_OK)
|
||||
|
@ -392,33 +259,23 @@ SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,c
|
|||
||(sqlite3_prepare_v2(_db,"SELECT id FROM Network ORDER BY id ASC",-1,&_sListNetworks,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"UPDATE Network SET memberRevisionCounter = (memberRevisionCounter + 1) WHERE id = ?",-1,&_sIncrementMemberRevisionCounter,(const char **)0) != SQLITE_OK)
|
||||
|
||||
/* Node */
|
||||
||(sqlite3_prepare_v2(_db,"SELECT identity FROM Node WHERE id = ?",-1,&_sGetNodeIdentity,(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 */
|
||||
||(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)
|
||||
|
||||
/* IpAssignmentPool */
|
||||
||(sqlite3_prepare_v2(_db,"SELECT ipRangeStart,ipRangeEnd FROM IpAssignmentPool WHERE networkId = ? AND ipVersion = ?",-1,&_sGetIpAssignmentPools,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT ipRangeStart,ipRangeEnd,ipVersion FROM IpAssignmentPool WHERE networkId = ? ORDER BY ipRangeStart ASC",-1,&_sGetIpAssignmentPools2,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"INSERT INTO IpAssignmentPool (networkId,ipRangeStart,ipRangeEnd,ipVersion) VALUES (?,?,?,?)",-1,&_sCreateIpAssignmentPool,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"DELETE FROM IpAssignmentPool WHERE networkId = ?",-1,&_sDeleteIpAssignmentPoolsForNetwork,(const char **)0) != SQLITE_OK)
|
||||
|
||||
/* IpAssignment */
|
||||
||(sqlite3_prepare_v2(_db,"SELECT ip,ipNetmaskBits,ipVersion FROM IpAssignment WHERE networkId = ? AND nodeId = ? AND \"type\" = 0 ORDER BY ip ASC",-1,&_sGetIpAssignmentsForNode,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT 1 FROM IpAssignment WHERE networkId = ? AND ip = ? AND ipVersion = ? AND \"type\" = ?",-1,&_sCheckIfIpIsAllocated,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"INSERT INTO IpAssignment (networkId,nodeId,\"type\",ip,ipNetmaskBits,ipVersion) VALUES (?,?,?,?,?,?)",-1,&_sAllocateIp,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"DELETE FROM IpAssignment WHERE networkId = ? AND nodeId = ? AND \"type\" = ?",-1,&_sDeleteIpAllocations,(const char **)0) != SQLITE_OK)
|
||||
|
||||
/* Relay */
|
||||
||(sqlite3_prepare_v2(_db,"SELECT \"address\",\"phyAddress\" FROM Relay WHERE \"networkId\" = ? ORDER BY \"address\" ASC",-1,&_sGetRelays,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"DELETE FROM Relay WHERE networkId = ?",-1,&_sDeleteRelaysForNetwork,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"INSERT INTO Relay (\"networkId\",\"address\",\"phyAddress\") VALUES (?,?,?)",-1,&_sCreateRelay,(const char **)0) != SQLITE_OK)
|
||||
|
||||
/* Member */
|
||||
||(sqlite3_prepare_v2(_db,"SELECT rowid,authorized,activeBridge,memberRevision,\"flags\",lastRequestTime,recentHistory FROM Member WHERE networkId = ? AND nodeId = ?",-1,&_sGetMember,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT m.authorized,m.activeBridge,m.memberRevision,n.identity,m.flags,m.lastRequestTime,m.recentHistory FROM Member AS m LEFT OUTER JOIN Node AS n ON n.id = m.nodeId WHERE m.networkId = ? AND m.nodeId = ?",-1,&_sGetMember2,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"INSERT INTO Member (networkId,nodeId,authorized,activeBridge,memberRevision) VALUES (?,?,?,0,(SELECT memberRevisionCounter FROM Network WHERE id = ?))",-1,&_sCreateMember,(const char **)0) != SQLITE_OK)
|
||||
|
@ -431,12 +288,10 @@ SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,c
|
|||
||(sqlite3_prepare_v2(_db,"DELETE FROM Member WHERE networkId = ?",-1,&_sDeleteAllNetworkMembers,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT nodeId,recentHistory FROM Member WHERE networkId = ? AND lastRequestTime >= ?",-1,&_sGetActiveNodesOnNetwork,(const char **)0) != SQLITE_OK)
|
||||
|
||||
/* Route */
|
||||
||(sqlite3_prepare_v2(_db,"INSERT INTO Route (networkId,target,via,targetNetmaskBits,ipVersion,flags,metric) VALUES (?,?,?,?,?,?,?)",-1,&_sCreateRoute,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT DISTINCT target,via,targetNetmaskBits,ipVersion,flags,metric FROM \"Route\" WHERE networkId = ? ORDER BY ipVersion,target,via",-1,&_sGetRoutes,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"DELETE FROM \"Route\" WHERE networkId = ?",-1,&_sDeleteRoutes,(const char **)0) != SQLITE_OK)
|
||||
|
||||
/* Config */
|
||||
||(sqlite3_prepare_v2(_db,"SELECT \"v\" FROM \"Config\" WHERE \"k\" = ?",-1,&_sGetConfig,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"INSERT OR REPLACE INTO \"Config\" (\"k\",\"v\") VALUES (?,?)",-1,&_sSetConfig,(const char **)0) != SQLITE_OK)
|
||||
|
||||
|
@ -446,9 +301,6 @@ SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,c
|
|||
throw std::runtime_error(err);
|
||||
}
|
||||
|
||||
/* Generate a 128-bit / 32-character "instance ID" if one isn't already
|
||||
* defined. Clients can use this to determine if this is the same controller
|
||||
* database they know and love. */
|
||||
sqlite3_reset(_sGetConfig);
|
||||
sqlite3_bind_text(_sGetConfig,1,"instanceId",10,SQLITE_STATIC);
|
||||
if (sqlite3_step(_sGetConfig) != SQLITE_ROW) {
|
||||
|
@ -474,72 +326,32 @@ SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,c
|
|||
#endif
|
||||
|
||||
_backupThread = Thread::start(this);
|
||||
*/
|
||||
|
||||
_dbCommitThread = Thread::start(this);
|
||||
}
|
||||
|
||||
SqliteNetworkController::~SqliteNetworkController()
|
||||
{
|
||||
_backupThreadRun = false;
|
||||
Thread::join(_backupThread);
|
||||
|
||||
Mutex::Lock _l(_lock);
|
||||
if (_db) {
|
||||
sqlite3_finalize(_sGetNetworkById);
|
||||
sqlite3_finalize(_sGetMember);
|
||||
sqlite3_finalize(_sCreateMember);
|
||||
sqlite3_finalize(_sGetNodeIdentity);
|
||||
sqlite3_finalize(_sCreateOrReplaceNode);
|
||||
sqlite3_finalize(_sGetActiveBridges);
|
||||
sqlite3_finalize(_sGetIpAssignmentsForNode);
|
||||
sqlite3_finalize(_sGetIpAssignmentPools);
|
||||
sqlite3_finalize(_sCheckIfIpIsAllocated);
|
||||
sqlite3_finalize(_sAllocateIp);
|
||||
sqlite3_finalize(_sDeleteIpAllocations);
|
||||
sqlite3_finalize(_sGetRelays);
|
||||
sqlite3_finalize(_sListNetworks);
|
||||
sqlite3_finalize(_sListNetworkMembers);
|
||||
sqlite3_finalize(_sGetMember2);
|
||||
sqlite3_finalize(_sGetIpAssignmentPools2);
|
||||
sqlite3_finalize(_sListRules);
|
||||
sqlite3_finalize(_sCreateRule);
|
||||
sqlite3_finalize(_sCreateNetwork);
|
||||
sqlite3_finalize(_sGetNetworkRevision);
|
||||
sqlite3_finalize(_sSetNetworkRevision);
|
||||
sqlite3_finalize(_sDeleteRelaysForNetwork);
|
||||
sqlite3_finalize(_sCreateRelay);
|
||||
sqlite3_finalize(_sDeleteIpAssignmentPoolsForNetwork);
|
||||
sqlite3_finalize(_sDeleteRulesForNetwork);
|
||||
sqlite3_finalize(_sCreateIpAssignmentPool);
|
||||
sqlite3_finalize(_sUpdateMemberAuthorized);
|
||||
sqlite3_finalize(_sUpdateMemberActiveBridge);
|
||||
sqlite3_finalize(_sUpdateMemberHistory);
|
||||
sqlite3_finalize(_sDeleteMember);
|
||||
sqlite3_finalize(_sDeleteAllNetworkMembers);
|
||||
sqlite3_finalize(_sGetActiveNodesOnNetwork);
|
||||
sqlite3_finalize(_sDeleteNetwork);
|
||||
sqlite3_finalize(_sCreateRoute);
|
||||
sqlite3_finalize(_sGetRoutes);
|
||||
sqlite3_finalize(_sDeleteRoutes);
|
||||
sqlite3_finalize(_sIncrementMemberRevisionCounter);
|
||||
sqlite3_finalize(_sGetConfig);
|
||||
sqlite3_finalize(_sSetConfig);
|
||||
sqlite3_close(_db);
|
||||
}
|
||||
_lock.lock();
|
||||
_dbCommitThreadRun = false;
|
||||
_lock.unlock();
|
||||
Thread::join(_dbCommitThread);
|
||||
}
|
||||
|
||||
NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(const InetAddress &fromAddr,const Identity &signingId,const Identity &identity,uint64_t nwid,const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &metaData,NetworkConfig &nc)
|
||||
NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(const InetAddress &fromAddr,const Identity &signingId,const Identity &identity,uint64_t nwid,const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData,NetworkConfig &nc)
|
||||
{
|
||||
if (((!signingId)||(!signingId.hasPrivate()))||(signingId.address().toInt() != (nwid >> 24))) {
|
||||
return NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
char nwids[24],nodeIds[24];
|
||||
Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid);
|
||||
Utils::snprintf(nodeIds,sizeof(nodeIds),"%.10llx",(unsigned long long)identity.address().toInt());
|
||||
|
||||
const uint64_t now = OSUtils::now();
|
||||
|
||||
NetworkRecord network;
|
||||
Utils::snprintf(network.id,sizeof(network.id),"%.16llx",(unsigned long long)nwid);
|
||||
|
||||
MemberRecord member;
|
||||
Utils::snprintf(member.nodeId,sizeof(member.nodeId),"%.10llx",(unsigned long long)identity.address().toInt());
|
||||
|
||||
/*
|
||||
{ // begin lock
|
||||
Mutex::Lock _l(_lock);
|
||||
|
||||
|
@ -874,13 +686,13 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
|
|||
sqlite3_bind_text(_sCheckIfIpIsAllocated,1,network.id,16,SQLITE_STATIC);
|
||||
sqlite3_bind_blob(_sCheckIfIpIsAllocated,2,(const void *)ip6.rawIpData(),16,SQLITE_STATIC);
|
||||
sqlite3_bind_int(_sCheckIfIpIsAllocated,3,6); // 6 == IPv6
|
||||
sqlite3_bind_int(_sCheckIfIpIsAllocated,4,(int)0 /*ZT_IP_ASSIGNMENT_TYPE_ADDRESS*/);
|
||||
sqlite3_bind_int(_sCheckIfIpIsAllocated,4,(int)0);
|
||||
if (sqlite3_step(_sCheckIfIpIsAllocated) != SQLITE_ROW) {
|
||||
// No rows returned, so the IP is available
|
||||
sqlite3_reset(_sAllocateIp);
|
||||
sqlite3_bind_text(_sAllocateIp,1,network.id,16,SQLITE_STATIC);
|
||||
sqlite3_bind_text(_sAllocateIp,2,member.nodeId,10,SQLITE_STATIC);
|
||||
sqlite3_bind_int(_sAllocateIp,3,(int)0 /*ZT_IP_ASSIGNMENT_TYPE_ADDRESS*/);
|
||||
sqlite3_bind_int(_sAllocateIp,3,(int)0);
|
||||
sqlite3_bind_blob(_sAllocateIp,4,(const void *)ip6.rawIpData(),16,SQLITE_STATIC);
|
||||
sqlite3_bind_int(_sAllocateIp,5,routedNetmaskBits); // IP netmask bits from matching route
|
||||
sqlite3_bind_int(_sAllocateIp,6,6); // 6 == IPv6
|
||||
|
@ -943,13 +755,13 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
|
|||
sqlite3_bind_text(_sCheckIfIpIsAllocated,1,network.id,16,SQLITE_STATIC);
|
||||
sqlite3_bind_blob(_sCheckIfIpIsAllocated,2,(const void *)ipBlob,16,SQLITE_STATIC);
|
||||
sqlite3_bind_int(_sCheckIfIpIsAllocated,3,4); // 4 == IPv4
|
||||
sqlite3_bind_int(_sCheckIfIpIsAllocated,4,(int)0 /*ZT_IP_ASSIGNMENT_TYPE_ADDRESS*/);
|
||||
sqlite3_bind_int(_sCheckIfIpIsAllocated,4,(int)0);
|
||||
if (sqlite3_step(_sCheckIfIpIsAllocated) != SQLITE_ROW) {
|
||||
// No rows returned, so the IP is available
|
||||
sqlite3_reset(_sAllocateIp);
|
||||
sqlite3_bind_text(_sAllocateIp,1,network.id,16,SQLITE_STATIC);
|
||||
sqlite3_bind_text(_sAllocateIp,2,member.nodeId,10,SQLITE_STATIC);
|
||||
sqlite3_bind_int(_sAllocateIp,3,(int)0 /*ZT_IP_ASSIGNMENT_TYPE_ADDRESS*/);
|
||||
sqlite3_bind_int(_sAllocateIp,3,(int)0);
|
||||
sqlite3_bind_blob(_sAllocateIp,4,(const void *)ipBlob,16,SQLITE_STATIC);
|
||||
sqlite3_bind_int(_sAllocateIp,5,routedNetmaskBits); // IP netmask bits from matching route
|
||||
sqlite3_bind_int(_sAllocateIp,6,4); // 4 == IPv4
|
||||
|
@ -980,6 +792,7 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
|
|||
}
|
||||
|
||||
return NetworkController::NETCONF_QUERY_OK;
|
||||
*/
|
||||
}
|
||||
|
||||
unsigned int SqliteNetworkController::handleControlPlaneHttpGET(
|
||||
|
@ -1671,76 +1484,19 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpDELETE(
|
|||
void SqliteNetworkController::threadMain()
|
||||
throw()
|
||||
{
|
||||
uint64_t lastBackupTime = OSUtils::now();
|
||||
uint64_t lastCleanupTime = OSUtils::now();
|
||||
|
||||
while (_backupThreadRun) {
|
||||
if ((OSUtils::now() - lastCleanupTime) >= 5000) {
|
||||
const uint64_t now = OSUtils::now();
|
||||
lastCleanupTime = now;
|
||||
|
||||
Mutex::Lock _l(_lock);
|
||||
|
||||
// Clean out really old circuit tests to prevent memory build-up
|
||||
for(std::map< uint64_t,_CircuitTestEntry >::iterator ct(_circuitTests.begin());ct!=_circuitTests.end();) {
|
||||
if (!ct->second.test) {
|
||||
_circuitTests.erase(ct++);
|
||||
} else if ((now - ct->second.test->timestamp) >= ZT_SQLITENETWORKCONTROLLER_CIRCUIT_TEST_TIMEOUT) {
|
||||
_node->circuitTestEnd(ct->second.test);
|
||||
::free((void *)ct->second.test);
|
||||
_circuitTests.erase(ct++);
|
||||
} else ++ct;
|
||||
}
|
||||
}
|
||||
|
||||
if (((OSUtils::now() - lastBackupTime) >= ZT_NETCONF_BACKUP_PERIOD)&&(_backupNeeded)) {
|
||||
lastBackupTime = OSUtils::now();
|
||||
|
||||
char backupPath[4096],backupPath2[4096];
|
||||
Utils::snprintf(backupPath,sizeof(backupPath),"%s.backupInProgress",_dbPath.c_str());
|
||||
Utils::snprintf(backupPath2,sizeof(backupPath),"%s.backup",_dbPath.c_str());
|
||||
OSUtils::rm(backupPath); // delete any unfinished backups
|
||||
|
||||
sqlite3 *bakdb = (sqlite3 *)0;
|
||||
sqlite3_backup *bak = (sqlite3_backup *)0;
|
||||
if (sqlite3_open_v2(backupPath,&bakdb,SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE,(const char *)0) != SQLITE_OK) {
|
||||
fprintf(stderr,"SqliteNetworkController: CRITICAL: backup failed on sqlite3_open_v2()"ZT_EOL_S);
|
||||
continue;
|
||||
}
|
||||
bak = sqlite3_backup_init(bakdb,"main",_db,"main");
|
||||
if (!bak) {
|
||||
sqlite3_close(bakdb);
|
||||
OSUtils::rm(backupPath); // delete any unfinished backups
|
||||
fprintf(stderr,"SqliteNetworkController: CRITICAL: backup failed on sqlite3_backup_init()"ZT_EOL_S);
|
||||
continue;
|
||||
}
|
||||
|
||||
int rc = SQLITE_OK;
|
||||
for(;;) {
|
||||
if (!_backupThreadRun) {
|
||||
sqlite3_backup_finish(bak);
|
||||
sqlite3_close(bakdb);
|
||||
OSUtils::rm(backupPath);
|
||||
return;
|
||||
}
|
||||
_lock.lock();
|
||||
rc = sqlite3_backup_step(bak,64);
|
||||
_lock.unlock();
|
||||
if ((rc == SQLITE_OK)||(rc == SQLITE_LOCKED)||(rc == SQLITE_BUSY))
|
||||
Thread::sleep(50);
|
||||
else break;
|
||||
}
|
||||
|
||||
sqlite3_backup_finish(bak);
|
||||
sqlite3_close(bakdb);
|
||||
|
||||
OSUtils::rm(backupPath2);
|
||||
::rename(backupPath,backupPath2);
|
||||
|
||||
_backupNeeded = false;
|
||||
}
|
||||
|
||||
bool run = true;
|
||||
while(run) {
|
||||
Thread::sleep(250);
|
||||
try {
|
||||
std::vector<std::string> errors;
|
||||
Mutex::Lock _l(_lock);
|
||||
run = _dbCommitThreadRun;
|
||||
if (!_db.commit(&errors)) {
|
||||
// TODO: handle anything really bad
|
||||
}
|
||||
} catch ( ... ) {
|
||||
// TODO: handle anything really bad
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1753,27 +1509,40 @@ unsigned int SqliteNetworkController::_doCPGet(
|
|||
std::string &responseContentType)
|
||||
{
|
||||
// Assumes _lock is locked
|
||||
char json[65536];
|
||||
|
||||
if ((path.size() > 0)&&(path[0] == "network")) {
|
||||
auto networks = _db.get<const json::object_t *>("network");
|
||||
if (!networks) return 404;
|
||||
|
||||
if ((path.size() >= 2)&&(path[1].length() == 16)) {
|
||||
uint64_t nwid = Utils::hexStrToU64(path[1].c_str());
|
||||
const uint64_t nwid = Utils::hexStrToU64(path[1].c_str());
|
||||
char nwids[24];
|
||||
Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid);
|
||||
auto network = _db.get<const json::object_t *>(nwids);
|
||||
if (!network) return 404;
|
||||
|
||||
if (path.size() >= 3) {
|
||||
// /network/<nwid>/...
|
||||
|
||||
if (path[2] == "member") {
|
||||
auto members = network->get<const json::object_t *>("member");
|
||||
if (!members) return 404;
|
||||
|
||||
if (path.size() >= 4) {
|
||||
// Get specific member info
|
||||
|
||||
uint64_t address = Utils::hexStrToU64(path[3].c_str());
|
||||
const uint64_t address = Utils::hexStrToU64(path[3].c_str());
|
||||
char addrs[24];
|
||||
Utils::snprintf(addrs,sizeof(addrs),"%.10llx",address);
|
||||
auto member = members->get<const json::object_t *>(addrs);
|
||||
if (!member) return 404;
|
||||
|
||||
nlohmann::json o(member);
|
||||
o["nwid"] = nwids;
|
||||
o["address"] = addrs;
|
||||
o["controllerInstanceId"] = _instanceId;
|
||||
o["clock"] = OSUtils::now();
|
||||
responseBody = o.dump(2);
|
||||
responseContentType = "application/json";
|
||||
return 200;
|
||||
|
||||
/*
|
||||
sqlite3_reset(_sGetMember2);
|
||||
sqlite3_bind_text(_sGetMember2,1,nwids,16,SQLITE_STATIC);
|
||||
sqlite3_bind_text(_sGetMember2,2,addrs,10,SQLITE_STATIC);
|
||||
|
@ -1838,20 +1607,18 @@ unsigned int SqliteNetworkController::_doCPGet(
|
|||
responseContentType = "application/json";
|
||||
return 200;
|
||||
} // else 404
|
||||
*/
|
||||
|
||||
} else {
|
||||
// List members
|
||||
|
||||
sqlite3_reset(_sListNetworkMembers);
|
||||
sqlite3_bind_text(_sListNetworkMembers,1,nwids,16,SQLITE_STATIC);
|
||||
responseBody.push_back('{');
|
||||
bool firstMember = true;
|
||||
while (sqlite3_step(_sListNetworkMembers) == SQLITE_ROW) {
|
||||
responseBody.append(firstMember ? "\"" : ",\"");
|
||||
firstMember = false;
|
||||
responseBody.append((const char *)sqlite3_column_text(_sListNetworkMembers,0));
|
||||
responseBody.append("\":");
|
||||
responseBody.append((const char *)sqlite3_column_text(_sListNetworkMembers,1));
|
||||
for(auto i(members->begin());i!=members->end();++i) {
|
||||
responseBody.append((i == members->begin()) ? "\"" : ",\"");
|
||||
responseBody.append(i->key());
|
||||
responseBody.append("\":\"");
|
||||
const std::string rc = i->value().value("memberRevision","0");
|
||||
responseBody.append(rc);
|
||||
responseBody.append('"');
|
||||
}
|
||||
responseBody.push_back('}');
|
||||
responseContentType = "application/json";
|
||||
|
@ -1861,33 +1628,23 @@ unsigned int SqliteNetworkController::_doCPGet(
|
|||
|
||||
} else if ((path[2] == "active")&&(path.size() == 3)) {
|
||||
|
||||
sqlite3_reset(_sGetActiveNodesOnNetwork);
|
||||
sqlite3_bind_text(_sGetActiveNodesOnNetwork,1,nwids,16,SQLITE_STATIC);
|
||||
sqlite3_bind_int64(_sGetActiveNodesOnNetwork,2,(int64_t)(OSUtils::now() - ZT_NETCONF_NODE_ACTIVE_THRESHOLD));
|
||||
|
||||
responseBody.push_back('{');
|
||||
bool firstActiveMember = true;
|
||||
while (sqlite3_step(_sGetActiveNodesOnNetwork) == SQLITE_ROW) {
|
||||
const char *nodeId = (const char *)sqlite3_column_text(_sGetActiveNodesOnNetwork,0);
|
||||
const char *rhblob = (const char *)sqlite3_column_blob(_sGetActiveNodesOnNetwork,1);
|
||||
if ((nodeId)&&(rhblob)) {
|
||||
MemberRecentHistory rh;
|
||||
rh.fromBlob(rhblob,sqlite3_column_bytes(_sGetActiveNodesOnNetwork,1));
|
||||
if (rh.size() > 0) {
|
||||
if (firstActiveMember) {
|
||||
firstActiveMember = false;
|
||||
} else {
|
||||
responseBody.push_back(',');
|
||||
}
|
||||
responseBody.push_back('"');
|
||||
responseBody.append(nodeId);
|
||||
bool firstMember = true;
|
||||
const uint64_t threshold = OSUtils::now() - ZT_NETCONF_NODE_ACTIVE_THRESHOLD;
|
||||
for(auto i(members->begin());i!=members->end();++i) {
|
||||
auto recentLog = i->value()->get<const json::array_t *>("recentLog");
|
||||
if ((recentLog)&&(recentLog.size() > 0)) {
|
||||
auto mostRecentLog = recentLog[0];
|
||||
if ((mostRecentLog.is_object())&&((uint64_t)mostRecentLog.value("ts",0ULL) >= threshold)) {
|
||||
responseBody.append((firstMember) ? "\"" : ",\"");
|
||||
firstMember = false;
|
||||
responseBody.append(i->key());
|
||||
responseBody.append("\":");
|
||||
responseBody.append(rh.front());
|
||||
responseBody.append(mostRecentLog.dump());
|
||||
}
|
||||
}
|
||||
}
|
||||
responseBody.push_back('}');
|
||||
|
||||
responseContentType = "application/json";
|
||||
return 200;
|
||||
|
||||
|
@ -1909,249 +1666,42 @@ unsigned int SqliteNetworkController::_doCPGet(
|
|||
|
||||
} else {
|
||||
|
||||
sqlite3_reset(_sGetNetworkById);
|
||||
sqlite3_bind_text(_sGetNetworkById,1,nwids,16,SQLITE_STATIC);
|
||||
if (sqlite3_step(_sGetNetworkById) == SQLITE_ROW) {
|
||||
unsigned int fl = (unsigned int)sqlite3_column_int(_sGetNetworkById,4);
|
||||
std::string v6modes;
|
||||
if ((fl & ZT_DB_NETWORK_FLAG_ZT_MANAGED_V6_RFC4193) != 0)
|
||||
v6modes.append("rfc4193");
|
||||
if ((fl & ZT_DB_NETWORK_FLAG_ZT_MANAGED_V6_6PLANE) != 0) {
|
||||
if (v6modes.length() > 0)
|
||||
v6modes.push_back(',');
|
||||
v6modes.append("6plane");
|
||||
}
|
||||
if ((fl & ZT_DB_NETWORK_FLAG_ZT_MANAGED_V6_AUTO_ASSIGN) != 0) {
|
||||
if (v6modes.length() > 0)
|
||||
v6modes.push_back(',');
|
||||
v6modes.append("zt");
|
||||
}
|
||||
nlohmann::json o(network);
|
||||
o["nwid"] = nwids;
|
||||
o["controllerInstanceId"] = _instanceId;
|
||||
o["clock"] = OSUtils::now();
|
||||
responseBody = o.dump(2);
|
||||
responseContentType = "application/json";
|
||||
return 200;
|
||||
|
||||
Utils::snprintf(json,sizeof(json),
|
||||
"{\n"
|
||||
"\t\"nwid\": \"%s\",\n"
|
||||
"\t\"controllerInstanceId\": \"%s\",\n"
|
||||
"\t\"clock\": %llu,\n"
|
||||
"\t\"name\": \"%s\",\n"
|
||||
"\t\"private\": %s,\n"
|
||||
"\t\"enableBroadcast\": %s,\n"
|
||||
"\t\"allowPassiveBridging\": %s,\n"
|
||||
"\t\"v4AssignMode\": \"%s\",\n"
|
||||
"\t\"v6AssignMode\": \"%s\",\n"
|
||||
"\t\"multicastLimit\": %d,\n"
|
||||
"\t\"creationTime\": %llu,\n"
|
||||
"\t\"revision\": %llu,\n"
|
||||
"\t\"memberRevisionCounter\": %llu,\n"
|
||||
"\t\"authorizedMemberCount\": %llu,\n"
|
||||
"\t\"relays\": [",
|
||||
nwids,
|
||||
_instanceId.c_str(),
|
||||
(unsigned long long)OSUtils::now(),
|
||||
_jsonEscape((const char *)sqlite3_column_text(_sGetNetworkById,0)).c_str(),
|
||||
(sqlite3_column_int(_sGetNetworkById,1) > 0) ? "true" : "false",
|
||||
(sqlite3_column_int(_sGetNetworkById,2) > 0) ? "true" : "false",
|
||||
(sqlite3_column_int(_sGetNetworkById,3) > 0) ? "true" : "false",
|
||||
(((fl & ZT_DB_NETWORK_FLAG_ZT_MANAGED_V4_AUTO_ASSIGN) != 0) ? "zt" : ""),
|
||||
v6modes.c_str(),
|
||||
sqlite3_column_int(_sGetNetworkById,5),
|
||||
(unsigned long long)sqlite3_column_int64(_sGetNetworkById,6),
|
||||
(unsigned long long)sqlite3_column_int64(_sGetNetworkById,7),
|
||||
(unsigned long long)sqlite3_column_int64(_sGetNetworkById,8),
|
||||
(unsigned long long)sqlite3_column_int64(_sGetNetworkById,9));
|
||||
responseBody = json;
|
||||
|
||||
sqlite3_reset(_sGetRelays);
|
||||
sqlite3_bind_text(_sGetRelays,1,nwids,16,SQLITE_STATIC);
|
||||
bool firstRelay = true;
|
||||
while (sqlite3_step(_sGetRelays) == SQLITE_ROW) {
|
||||
responseBody.append(firstRelay ? "\n\t\t" : ",\n\t\t");
|
||||
firstRelay = false;
|
||||
responseBody.append("{\"address\":\"");
|
||||
responseBody.append((const char *)sqlite3_column_text(_sGetRelays,0));
|
||||
responseBody.append("\",\"phyAddress\":\"");
|
||||
responseBody.append(_jsonEscape((const char *)sqlite3_column_text(_sGetRelays,1)));
|
||||
responseBody.append("\"}");
|
||||
}
|
||||
|
||||
responseBody.append("],\n\t\"routes\": [");
|
||||
|
||||
sqlite3_reset(_sGetRoutes);
|
||||
sqlite3_bind_text(_sGetRoutes,1,nwids,16,SQLITE_STATIC);
|
||||
bool firstRoute = true;
|
||||
while (sqlite3_step(_sGetRoutes) == SQLITE_ROW) {
|
||||
responseBody.append(firstRoute ? "\n\t\t" : ",\n\t\t");
|
||||
firstRoute = false;
|
||||
responseBody.append("{\"target\":");
|
||||
char tmp[128];
|
||||
const unsigned char *ip = (const unsigned char *)sqlite3_column_blob(_sGetRoutes,0);
|
||||
switch(sqlite3_column_int(_sGetRoutes,3)) { // ipVersion
|
||||
case 4:
|
||||
Utils::snprintf(tmp,sizeof(tmp),"\"%d.%d.%d.%d/%d\"",(int)ip[12],(int)ip[13],(int)ip[14],(int)ip[15],sqlite3_column_int(_sGetRoutes,2));
|
||||
break;
|
||||
case 6:
|
||||
Utils::snprintf(tmp,sizeof(tmp),"\"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%d\"",(int)ip[0],(int)ip[1],(int)ip[2],(int)ip[3],(int)ip[4],(int)ip[5],(int)ip[6],(int)ip[7],(int)ip[8],(int)ip[9],(int)ip[10],(int)ip[11],(int)ip[12],(int)ip[13],(int)ip[14],(int)ip[15],sqlite3_column_int(_sGetRoutes,2));
|
||||
break;
|
||||
}
|
||||
responseBody.append(tmp);
|
||||
if (sqlite3_column_type(_sGetRoutes,1) == SQLITE_NULL) {
|
||||
responseBody.append(",\"via\":null");
|
||||
} else {
|
||||
responseBody.append(",\"via\":");
|
||||
ip = (const unsigned char *)sqlite3_column_blob(_sGetRoutes,1);
|
||||
switch(sqlite3_column_int(_sGetRoutes,3)) { // ipVersion
|
||||
case 4:
|
||||
Utils::snprintf(tmp,sizeof(tmp),"\"%d.%d.%d.%d\"",(int)ip[12],(int)ip[13],(int)ip[14],(int)ip[15]);
|
||||
break;
|
||||
case 6:
|
||||
Utils::snprintf(tmp,sizeof(tmp),"\"%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x\"",(int)ip[0],(int)ip[1],(int)ip[2],(int)ip[3],(int)ip[4],(int)ip[5],(int)ip[6],(int)ip[7],(int)ip[8],(int)ip[9],(int)ip[10],(int)ip[11],(int)ip[12],(int)ip[13],(int)ip[14],(int)ip[15]);
|
||||
break;
|
||||
}
|
||||
responseBody.append(tmp);
|
||||
}
|
||||
responseBody.append(",\"flags\":");
|
||||
responseBody.append((const char *)sqlite3_column_text(_sGetRoutes,4));
|
||||
responseBody.append(",\"metric\":");
|
||||
responseBody.append((const char *)sqlite3_column_text(_sGetRoutes,5));
|
||||
responseBody.push_back('}');
|
||||
}
|
||||
|
||||
responseBody.append("],\n\t\"ipAssignmentPools\": [");
|
||||
|
||||
sqlite3_reset(_sGetIpAssignmentPools2);
|
||||
sqlite3_bind_text(_sGetIpAssignmentPools2,1,nwids,16,SQLITE_STATIC);
|
||||
bool firstIpAssignmentPool = true;
|
||||
while (sqlite3_step(_sGetIpAssignmentPools2) == SQLITE_ROW) {
|
||||
const char *ipRangeStartB = reinterpret_cast<const char *>(sqlite3_column_blob(_sGetIpAssignmentPools2,0));
|
||||
const char *ipRangeEndB = reinterpret_cast<const char *>(sqlite3_column_blob(_sGetIpAssignmentPools2,1));
|
||||
if ((ipRangeStartB)&&(ipRangeEndB)) {
|
||||
InetAddress ipps,ippe;
|
||||
int ipVersion = sqlite3_column_int(_sGetIpAssignmentPools2,2);
|
||||
if (ipVersion == 4) {
|
||||
ipps.set((const void *)(ipRangeStartB + 12),4,0);
|
||||
ippe.set((const void *)(ipRangeEndB + 12),4,0);
|
||||
} else if (ipVersion == 6) {
|
||||
ipps.set((const void *)ipRangeStartB,16,0);
|
||||
ippe.set((const void *)ipRangeEndB,16,0);
|
||||
}
|
||||
if (ipps) {
|
||||
responseBody.append(firstIpAssignmentPool ? "\n\t\t" : ",\n\t\t");
|
||||
firstIpAssignmentPool = false;
|
||||
Utils::snprintf(json,sizeof(json),"{\"ipRangeStart\":\"%s\",\"ipRangeEnd\":\"%s\"}",
|
||||
_jsonEscape(ipps.toIpString()).c_str(),
|
||||
_jsonEscape(ippe.toIpString()).c_str());
|
||||
responseBody.append(json);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
responseBody.append("],\n\t\"rules\": [");
|
||||
|
||||
sqlite3_reset(_sListRules);
|
||||
sqlite3_bind_text(_sListRules,1,nwids,16,SQLITE_STATIC);
|
||||
bool firstRule = true;
|
||||
while (sqlite3_step(_sListRules) == SQLITE_ROW) {
|
||||
responseBody.append(firstRule ? "\n\t{\n" : ",{\n");
|
||||
firstRule = false;
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"ruleNo\": %lld,\n",sqlite3_column_int64(_sListRules,0));
|
||||
responseBody.append(json);
|
||||
if (sqlite3_column_type(_sListRules,1) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"nodeId\": \"%s\",\n",(const char *)sqlite3_column_text(_sListRules,1));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,2) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"sourcePort\": \"%s\",\n",(const char *)sqlite3_column_text(_sListRules,2));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,3) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"destPort\": \"%s\",\n",(const char *)sqlite3_column_text(_sListRules,3));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,4) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"vlanId\": %d,\n",sqlite3_column_int(_sListRules,4));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,5) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"vlanPcp\": %d,\n",sqlite3_column_int(_sListRules,5));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,6) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"etherType\": %d,\n",sqlite3_column_int(_sListRules,6));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,7) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"macSource\": \"%s\",\n",MAC((const char *)sqlite3_column_text(_sListRules,7)).toString().c_str());
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,8) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"macDest\": \"%s\",\n",MAC((const char *)sqlite3_column_text(_sListRules,8)).toString().c_str());
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,9) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"ipSource\": \"%s\",\n",_jsonEscape((const char *)sqlite3_column_text(_sListRules,9)).c_str());
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,10) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"ipDest\": \"%s\",\n",_jsonEscape((const char *)sqlite3_column_text(_sListRules,10)).c_str());
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,11) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"ipTos\": %d,\n",sqlite3_column_int(_sListRules,11));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,12) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"ipProtocol\": %d,\n",sqlite3_column_int(_sListRules,12));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,13) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"ipSourcePort\": %d,\n",sqlite3_column_int(_sListRules,13));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,14) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"ipDestPort\": %d,\n",sqlite3_column_int(_sListRules,14));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,15) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"flags\": %lu,\n",(unsigned long)sqlite3_column_int64(_sListRules,15));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,16) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"invFlags\": %lu,\n",(unsigned long)sqlite3_column_int64(_sListRules,16));
|
||||
responseBody.append(json);
|
||||
}
|
||||
responseBody.append("\t\t\"action\": \"");
|
||||
responseBody.append(_jsonEscape( (sqlite3_column_type(_sListRules,17) == SQLITE_NULL) ? "drop" : (const char *)sqlite3_column_text(_sListRules,17) ));
|
||||
responseBody.append("\"\n\t}");
|
||||
}
|
||||
|
||||
responseBody.append("]\n}\n");
|
||||
responseContentType = "application/json";
|
||||
return 200;
|
||||
} // else 404
|
||||
}
|
||||
} else if (path.size() == 1) {
|
||||
// list networks
|
||||
sqlite3_reset(_sListNetworks);
|
||||
responseContentType = "application/json";
|
||||
|
||||
responseBody = "[";
|
||||
bool first = true;
|
||||
while (sqlite3_step(_sListNetworks) == SQLITE_ROW) {
|
||||
if (first) {
|
||||
first = false;
|
||||
responseBody.push_back('"');
|
||||
} else responseBody.append(",\"");
|
||||
responseBody.append((const char *)sqlite3_column_text(_sListNetworks,0));
|
||||
responseBody.push_back('"');
|
||||
for(auto i(networks->begin());i!=networks.end();++i) {
|
||||
responseBody.append((i == networks->begin()) ? "\"" : ",\"");
|
||||
responseBody.append(i->key());
|
||||
responseBody.append("\"");
|
||||
}
|
||||
responseBody.push_back(']');
|
||||
responseContentType = "application/json";
|
||||
return 200;
|
||||
|
||||
} // else 404
|
||||
|
||||
} else if ((path.size() > 0)&&(path[0] == "_dump")) {
|
||||
|
||||
responseBody = _db.dump(2);
|
||||
responseContentType = "application/json";
|
||||
return 200;
|
||||
|
||||
} else {
|
||||
// GET /controller returns status and API version if controller is supported
|
||||
|
||||
Utils::snprintf(json,sizeof(json),"{\n\t\"controller\": true,\n\t\"apiVersion\": %d,\n\t\"clock\": %llu,\n\t\"instanceId\": \"%s\"\n}\n",ZT_NETCONF_CONTROLLER_API_VERSION,(unsigned long long)OSUtils::now(),_instanceId.c_str());
|
||||
responseBody = json;
|
||||
responseContentType = "application/json";
|
||||
return 200;
|
||||
|
||||
}
|
||||
|
||||
return 404;
|
||||
|
|
|
@ -30,22 +30,17 @@
|
|||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <sqlite3.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
|
||||
#include "../node/NetworkController.hpp"
|
||||
#include "../node/Mutex.hpp"
|
||||
#include "../osdep/Thread.hpp"
|
||||
|
||||
// Number of in-memory last log entries to maintain per user
|
||||
#define ZT_SQLITENETWORKCONTROLLER_IN_MEMORY_LOG_SIZE 32
|
||||
|
||||
// How long do circuit tests last before they're forgotten?
|
||||
#define ZT_SQLITENETWORKCONTROLLER_CIRCUIT_TEST_TIMEOUT 60000
|
||||
#include "../ext/offbase/offbase.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
|
@ -54,7 +49,7 @@ class Node;
|
|||
class SqliteNetworkController : public NetworkController
|
||||
{
|
||||
public:
|
||||
SqliteNetworkController(Node *node,const char *dbPath,const char *circuitTestPath);
|
||||
SqliteNetworkController(Node *node,const char *dbPath);
|
||||
virtual ~SqliteNetworkController();
|
||||
|
||||
virtual NetworkController::ResultCode doNetworkConfigRequest(
|
||||
|
@ -62,7 +57,7 @@ public:
|
|||
const Identity &signingId,
|
||||
const Identity &identity,
|
||||
uint64_t nwid,
|
||||
const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &metaData,
|
||||
const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData,
|
||||
NetworkConfig &nc);
|
||||
|
||||
unsigned int handleControlPlaneHttpGET(
|
||||
|
@ -92,15 +87,6 @@ public:
|
|||
throw();
|
||||
|
||||
private:
|
||||
/* deprecated
|
||||
enum IpAssignmentType {
|
||||
// IP assignment is a static IP address
|
||||
ZT_IP_ASSIGNMENT_TYPE_ADDRESS = 0,
|
||||
// IP assignment is a network -- a route via this interface, not an address
|
||||
ZT_IP_ASSIGNMENT_TYPE_NETWORK = 1
|
||||
};
|
||||
*/
|
||||
|
||||
unsigned int _doCPGet(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
|
@ -111,13 +97,11 @@ private:
|
|||
|
||||
static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report);
|
||||
|
||||
Node *_node;
|
||||
Thread _backupThread;
|
||||
volatile bool _backupThreadRun;
|
||||
volatile bool _backupNeeded;
|
||||
std::string _dbPath;
|
||||
std::string _circuitTestPath;
|
||||
Node *const _node;
|
||||
std::string _instanceId;
|
||||
offbase _db;
|
||||
Thread _dbCommitThread;
|
||||
volatile bool _dbCommitThreadRun;
|
||||
|
||||
// Circuit tests outstanding
|
||||
struct _CircuitTestEntry
|
||||
|
@ -130,48 +114,6 @@ private:
|
|||
// Last request time by address, for rate limitation
|
||||
std::map< std::pair<uint64_t,uint64_t>,uint64_t > _lastRequestTime;
|
||||
|
||||
sqlite3 *_db;
|
||||
|
||||
sqlite3_stmt *_sGetNetworkById;
|
||||
sqlite3_stmt *_sGetMember;
|
||||
sqlite3_stmt *_sCreateMember;
|
||||
sqlite3_stmt *_sGetNodeIdentity;
|
||||
sqlite3_stmt *_sCreateOrReplaceNode;
|
||||
sqlite3_stmt *_sGetActiveBridges;
|
||||
sqlite3_stmt *_sGetIpAssignmentsForNode;
|
||||
sqlite3_stmt *_sGetIpAssignmentPools;
|
||||
sqlite3_stmt *_sCheckIfIpIsAllocated;
|
||||
sqlite3_stmt *_sAllocateIp;
|
||||
sqlite3_stmt *_sDeleteIpAllocations;
|
||||
sqlite3_stmt *_sGetRelays;
|
||||
sqlite3_stmt *_sListNetworks;
|
||||
sqlite3_stmt *_sListNetworkMembers;
|
||||
sqlite3_stmt *_sGetMember2;
|
||||
sqlite3_stmt *_sGetIpAssignmentPools2;
|
||||
sqlite3_stmt *_sListRules;
|
||||
sqlite3_stmt *_sCreateRule;
|
||||
sqlite3_stmt *_sCreateNetwork;
|
||||
sqlite3_stmt *_sGetNetworkRevision;
|
||||
sqlite3_stmt *_sSetNetworkRevision;
|
||||
sqlite3_stmt *_sDeleteRelaysForNetwork;
|
||||
sqlite3_stmt *_sCreateRelay;
|
||||
sqlite3_stmt *_sDeleteIpAssignmentPoolsForNetwork;
|
||||
sqlite3_stmt *_sDeleteRulesForNetwork;
|
||||
sqlite3_stmt *_sCreateIpAssignmentPool;
|
||||
sqlite3_stmt *_sUpdateMemberAuthorized;
|
||||
sqlite3_stmt *_sUpdateMemberActiveBridge;
|
||||
sqlite3_stmt *_sUpdateMemberHistory;
|
||||
sqlite3_stmt *_sDeleteMember;
|
||||
sqlite3_stmt *_sDeleteAllNetworkMembers;
|
||||
sqlite3_stmt *_sGetActiveNodesOnNetwork;
|
||||
sqlite3_stmt *_sDeleteNetwork;
|
||||
sqlite3_stmt *_sCreateRoute;
|
||||
sqlite3_stmt *_sGetRoutes;
|
||||
sqlite3_stmt *_sDeleteRoutes;
|
||||
sqlite3_stmt *_sIncrementMemberRevisionCounter;
|
||||
sqlite3_stmt *_sGetConfig;
|
||||
sqlite3_stmt *_sSetConfig;
|
||||
|
||||
Mutex _lock;
|
||||
};
|
||||
|
||||
|
|
|
@ -86,17 +86,9 @@ CREATE TABLE Route (
|
|||
|
||||
CREATE INDEX Route_networkId ON Route (networkId);
|
||||
|
||||
CREATE TABLE Relay (
|
||||
networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
|
||||
address char(10) NOT NULL,
|
||||
phyAddress varchar(64) NOT NULL
|
||||
);
|
||||
|
||||
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),
|
||||
capId integer,
|
||||
ruleNo integer NOT NULL,
|
||||
ruleType integer NOT NULL DEFAULT(0),
|
||||
"addr" blob(16),
|
||||
|
@ -106,5 +98,15 @@ CREATE TABLE Rule (
|
|||
"int4" integer
|
||||
);
|
||||
|
||||
CREATE INDEX Rule_networkId_ruleNo ON Rule (networkId, ruleNo);
|
||||
CREATE INDEX Rule_networkId_policyId ON Rule (networkId, policyId);
|
||||
CREATE INDEX Rule_networkId_capId ON Rule (networkId,capId);
|
||||
|
||||
CREATE TABLE MemberTC (
|
||||
networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
|
||||
nodeId char(10) NOT NULL REFERENCES Node(id) ON DELETE CASCADE,
|
||||
tagId integer,
|
||||
tagValue integer,
|
||||
capId integer,
|
||||
capMaxCustodyChainLength integer NOT NULL DEFAULT(1)
|
||||
);
|
||||
|
||||
CREATE INDEX MemberTC_networkId_nodeId ON MemberTC (networkId,nodeId);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue