summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--controller/SqliteNetworkController.cpp133
-rw-r--r--controller/SqliteNetworkController.hpp8
2 files changed, 89 insertions, 52 deletions
diff --git a/controller/SqliteNetworkController.cpp b/controller/SqliteNetworkController.cpp
index bee4fbf1..7338dc29 100644
--- a/controller/SqliteNetworkController.cpp
+++ b/controller/SqliteNetworkController.cpp
@@ -69,11 +69,14 @@
// Drop requests for a given peer and network ID that occur more frequently
// than this (ms).
-#define ZT_NETCONF_MIN_REQUEST_PERIOD 1000
+#define ZT_NETCONF_MIN_REQUEST_PERIOD 500
// Delay between backups in milliseconds
#define ZT_NETCONF_BACKUP_PERIOD 120000
+// Number of NodeHistory entries to maintain per node and network (can be changed)
+#define ZT_NETCONF_NODE_HISTORY_LENGTH 16
+
namespace ZeroTier {
namespace {
@@ -200,6 +203,13 @@ SqliteNetworkController::SqliteNetworkController(Node *node,const char *dbPath,c
||(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)
+ /* NodeHistory */
+ ||(sqlite3_prepare_v2(_db,"SELECT IFNULL(MAX(networkVisitCounter),0) FROM NodeHistory WHERE networkId = ? AND nodeId = ?",-1,&_sGetMaxNodeHistoryNetworkVisitCounter,(const char **)0) != SQLITE_OK)
+ ||(sqlite3_prepare_v2(_db,"INSERT INTO NodeHistory (nodeId,networkId,networkVisitCounter,networkRequestAuthorized,requestTime,networkRequestMetaData,fromAddress) VALUES (?,?,?,?,?,?,?)",-1,&_sAddNodeHistoryEntry,(const char **)0) != SQLITE_OK)
+ ||(sqlite3_prepare_v2(_db,"DELETE FROM NodeHistory WHERE networkId = ? AND nodeId = ? AND networkVisitCounter <= ?",-1,&_sDeleteOldNodeHistoryEntries,(const char **)0) != SQLITE_OK)
+ ||(sqlite3_prepare_v2(_db,"SELECT DISTINCT nodeId FROM NodeHistory WHERE networkId = ? AND requestTime >= ? AND networkRequestAuthorized != 0 ORDER BY nodeId ASC",-1,&_sGetActiveNodesOnNetwork,(const char **)0) != SQLITE_OK)
+ ||(sqlite3_prepare_v2(_db,"SELECT networkVisitCounter,networkRequestAuthorized,requestTime,networkRequestMetaData,fromAddress FROM NodeHistory WHERE networkId = ? AND nodeId = ? ORDER BY requestTime DESC",-1,&_sGetNodeHistory,(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)
@@ -290,6 +300,11 @@ SqliteNetworkController::~SqliteNetworkController()
sqlite3_finalize(_sCreateMember);
sqlite3_finalize(_sGetNodeIdentity);
sqlite3_finalize(_sCreateOrReplaceNode);
+ sqlite3_finalize(_sGetMaxNodeHistoryNetworkVisitCounter);
+ sqlite3_finalize(_sAddNodeHistoryEntry);
+ sqlite3_finalize(_sDeleteOldNodeHistoryEntries);
+ sqlite3_finalize(_sGetActiveNodesOnNetwork);
+ sqlite3_finalize(_sGetNodeHistory);
sqlite3_finalize(_sGetEtherTypesFromRuleTable);
sqlite3_finalize(_sGetActiveBridges);
sqlite3_finalize(_sGetIpAssignmentsForNode);
@@ -1198,46 +1213,36 @@ unsigned int SqliteNetworkController::_doCPGet(
(unsigned int)sqlite3_column_int(_sGetIpAssignmentsForNode2,1)
);
responseBody.append(firstIp ? "\"" : ",\"");
- firstIp = false;
responseBody.append(_jsonEscape(ip.toString()));
responseBody.push_back('"');
+ firstIp = false;
}
responseBody.append("],\n\t\"recentLog\": [");
- /*
- {
- std::map< std::pair<Address,uint64_t>,_LLEntry >::const_iterator lli(_lastLog.find(std::pair<Address,uint64_t>(Address(address),nwid)));
- if (lli != _lastLog.end()) {
- const _LLEntry &lastLogEntry = lli->second;
- uint64_t eptr = lastLogEntry.totalRequests;
- for(int k=0;k<ZT_SQLITENETWORKCONTROLLER_IN_MEMORY_LOG_SIZE;++k) {
- if (!eptr--)
- break;
- const unsigned long ptr = (unsigned long)eptr % ZT_SQLITENETWORKCONTROLLER_IN_MEMORY_LOG_SIZE;
-
- char tsbuf[64];
- Utils::snprintf(tsbuf,sizeof(tsbuf),"%llu",(unsigned long long)lastLogEntry.l[ptr].ts);
-
- responseBody.append((k == 0) ? "{" : ",{");
- responseBody.append("\"ts\":");
- responseBody.append(tsbuf);
- responseBody.append(lastLogEntry.l[ptr].authorized ? ",\"authorized\":false,\"version\":" : ",\"authorized\":true,\"version\":");
- if (lastLogEntry.l[ptr].version[0]) {
- responseBody.push_back('"');
- responseBody.append(_jsonEscape(lastLogEntry.l[ptr].version));
- responseBody.append("\",\"fromAddr\":");
- } else responseBody.append("null,\"fromAddr\":");
- if (lastLogEntry.l[ptr].fromAddr) {
- responseBody.push_back('"');
- responseBody.append(_jsonEscape(lastLogEntry.l[ptr].fromAddr.toString()));
- responseBody.append("\"}");
- } else responseBody.append("null}");
- }
- }
+ sqlite3_reset(_sGetNodeHistory);
+ sqlite3_bind_text(_sGetNodeHistory,1,nwids,16,SQLITE_STATIC);
+ sqlite3_bind_text(_sGetNodeHistory,2,addrs,10,SQLITE_STATIC);
+ bool firstHistory = true;
+ while (sqlite3_step(_sGetNodeHistory) == SQLITE_ROW) {
+ responseBody.append(firstHistory ? "{" : ",{");
+ responseBody.append("\"ts\":");
+ responseBody.append((const char *)sqlite3_column_text(_sGetNodeHistory,2));
+ responseBody.append((sqlite3_column_int(_sGetNodeHistory,1) == 0) ? ",\"authorized\":false,\"version\":" : ",\"authorized\":true,\"metaData\":");
+ const char *md = (const char *)sqlite3_column_text(_sGetNodeHistory,3);
+ if (md) {
+ responseBody.push_back('"');
+ responseBody.append(_jsonEscape(md));
+ responseBody.append("\",\"fromAddr\":");
+ } else responseBody.append("null,\"fromAddr\":");
+ const char *fa = (const char *)sqlite3_column_text(_sGetNodeHistory,4);
+ if (fa) {
+ responseBody.push_back('"');
+ responseBody.append(_jsonEscape(fa));
+ responseBody.append("\"}");
+ } else responseBody.append("null}");
+ firstHistory = false;
}
- */
-
responseBody.append("]\n}\n");
responseContentType = "application/json";
@@ -1589,12 +1594,12 @@ NetworkController::ResultCode SqliteNetworkController::_doNetworkConfigRequest(c
const uint64_t now = OSUtils::now();
// Check rate limit circuit breaker to prevent flooding
- /*
- _LLEntry &lastLogEntry = _lastLog[std::pair<Address,uint64_t>(identity.address(),nwid)];
- if ((now - lastLogEntry.lastRequestTime) <= ZT_NETCONF_MIN_REQUEST_PERIOD)
- return NetworkController::NETCONF_QUERY_IGNORE;
- lastLogEntry.lastRequestTime = now;
- */
+ {
+ uint64_t &lrt = _lastRequestTime[identity.address()];
+ if ((now - lrt) <= ZT_NETCONF_MIN_REQUEST_PERIOD)
+ return NetworkController::NETCONF_QUERY_IGNORE;
+ lrt = now;
+ }
NetworkRecord network;
memset(&network,0,sizeof(network));
@@ -1680,21 +1685,45 @@ NetworkController::ResultCode SqliteNetworkController::_doNetworkConfigRequest(c
sqlite3_step(_sIncrementMemberRevisionCounter);
}
- // Add log entry to in-memory circular log
+ // Update NodeHistory with new log entry and delete expired entries
- /*
{
- const unsigned long ptr = (unsigned long)lastLogEntry.totalRequests % ZT_SQLITENETWORKCONTROLLER_IN_MEMORY_LOG_SIZE;
- lastLogEntry.l[ptr].ts = now;
- lastLogEntry.l[ptr].fromAddr = fromAddr;
- if ((clientMajorVersion > 0)||(clientMinorVersion > 0)||(clientRevision > 0))
- Utils::snprintf(lastLogEntry.l[ptr].version,sizeof(lastLogEntry.l[ptr].version),"%u.%u.%u",clientMajorVersion,clientMinorVersion,clientRevision);
- else lastLogEntry.l[ptr].version[0] = (char)0;
- lastLogEntry.l[ptr].authorized = member.authorized;
- ++lastLogEntry.totalRequests;
- // TODO: push or save these somewhere
+ int64_t nextVC = 1;
+ sqlite3_reset(_sGetMaxNodeHistoryNetworkVisitCounter);
+ sqlite3_bind_text(_sGetMaxNodeHistoryNetworkVisitCounter,1,network.id,16,SQLITE_STATIC);
+ sqlite3_bind_text(_sGetMaxNodeHistoryNetworkVisitCounter,2,member.nodeId,10,SQLITE_STATIC);
+ if (sqlite3_step(_sGetMaxNodeHistoryNetworkVisitCounter) == SQLITE_ROW) {
+ nextVC = (int64_t)sqlite3_column_int64(_sGetMaxNodeHistoryNetworkVisitCounter,0) + 1;
+ }
+
+ std::string mdstr(metaData.toString());
+ if (mdstr.length() > 1024)
+ mdstr = mdstr.substr(0,1024);
+ std::string fastr;
+ if (fromAddr)
+ fastr = fromAddr.toString();
+
+ sqlite3_reset(_sAddNodeHistoryEntry);
+ sqlite3_bind_text(_sAddNodeHistoryEntry,1,member.nodeId,10,SQLITE_STATIC);
+ sqlite3_bind_text(_sAddNodeHistoryEntry,2,network.id,16,SQLITE_STATIC);
+ sqlite3_bind_int64(_sAddNodeHistoryEntry,3,nextVC);
+ sqlite3_bind_int(_sAddNodeHistoryEntry,4,(member.authorized ? 1 : 0));
+ sqlite3_bind_int64(_sAddNodeHistoryEntry,5,(long long)now);
+ sqlite3_bind_text(_sAddNodeHistoryEntry,6,mdstr.c_str(),-1,SQLITE_STATIC);
+ if (fastr.length() > 0)
+ sqlite3_bind_text(_sAddNodeHistoryEntry,7,fastr.c_str(),-1,SQLITE_STATIC);
+ else sqlite3_bind_null(_sAddNodeHistoryEntry,7);
+ sqlite3_step(_sAddNodeHistoryEntry);
+
+ nextVC -= ZT_NETCONF_NODE_HISTORY_LENGTH;
+ if (nextVC >= 0) {
+ sqlite3_reset(_sDeleteOldNodeHistoryEntries);
+ sqlite3_bind_text(_sDeleteOldNodeHistoryEntries,1,network.id,16,SQLITE_STATIC);
+ sqlite3_bind_text(_sDeleteOldNodeHistoryEntries,2,member.nodeId,10,SQLITE_STATIC);
+ sqlite3_bind_int64(_sDeleteOldNodeHistoryEntries,3,nextVC);
+ sqlite3_step(_sDeleteOldNodeHistoryEntries);
+ }
}
- */
// Check member authorization
diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp
index 6562058a..22441f11 100644
--- a/controller/SqliteNetworkController.hpp
+++ b/controller/SqliteNetworkController.hpp
@@ -131,6 +131,9 @@ private:
};
std::map< uint64_t,_CircuitTestEntry > _circuitTests;
+ // Last request time by address, for rate limitation
+ std::map< Address,uint64_t > _lastRequestTime;
+
sqlite3 *_db;
sqlite3_stmt *_sGetNetworkById;
@@ -138,6 +141,11 @@ private:
sqlite3_stmt *_sCreateMember;
sqlite3_stmt *_sGetNodeIdentity;
sqlite3_stmt *_sCreateOrReplaceNode;
+ sqlite3_stmt *_sGetMaxNodeHistoryNetworkVisitCounter;
+ sqlite3_stmt *_sAddNodeHistoryEntry;
+ sqlite3_stmt *_sDeleteOldNodeHistoryEntries;
+ sqlite3_stmt *_sGetActiveNodesOnNetwork;
+ sqlite3_stmt *_sGetNodeHistory;
sqlite3_stmt *_sGetEtherTypesFromRuleTable;
sqlite3_stmt *_sGetActiveBridges;
sqlite3_stmt *_sGetIpAssignmentsForNode;