u.object.length;++rk) {
- if ((!strcmp(rj->u.object.values[rk].name,"ruleId"))&&(rj->u.object.values[rk].value->type == json_integer))
- rule.ruleId = &(rj->u.object.values[rk].value->u.integer);
+ if ((!strcmp(rj->u.object.values[rk].name,"ruleNo"))&&(rj->u.object.values[rk].value->type == json_integer))
+ rule.ruleNo = &(rj->u.object.values[rk].value->u.integer);
else if ((!strcmp(rj->u.object.values[rk].name,"nodeId"))&&(rj->u.object.values[rk].value->type == json_string))
rule.nodeId = rj->u.object.values[rk].value->u.string.ptr;
else if ((!strcmp(rj->u.object.values[rk].name,"vlanId"))&&(rj->u.object.values[rk].value->type == json_integer))
@@ -909,11 +983,11 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
rule.action = rj->u.object.values[rk].value->u.string.ptr;
}
- if ((rule.ruleId)&&(rule.action)&&(rule.action[0])) {
+ if ((rule.ruleNo)&&(rule.action)&&(rule.action[0])) {
char mactmp1[16],mactmp2[16];
sqlite3_reset(_sCreateRule);
sqlite3_bind_text(_sCreateRule,1,nwids,16,SQLITE_STATIC);
- sqlite3_bind_int64(_sCreateRule,2,*rule.ruleId);
+ sqlite3_bind_int64(_sCreateRule,2,*rule.ruleNo);
// Optional values: null by default
for(int i=3;i<=16;++i)
@@ -964,7 +1038,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
sqlite3_bind_text(_sSetNetworkRevision,2,nwids,16,SQLITE_STATIC);
sqlite3_step(_sSetNetworkRevision);
- return _doCPGet(path,urlArgs,headers,body,responseBody,responseContentType);
+ return _doCPGet(path_copy,urlArgs,headers,body,responseBody,responseContentType);
}
} // else 404
@@ -993,6 +1067,11 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpDELETE(
char nwids[24];
Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid);
+ sqlite3_reset(_sGetNetworkById);
+ sqlite3_bind_text(_sGetNetworkById,1,nwids,16,SQLITE_STATIC);
+ if (sqlite3_step(_sGetNetworkById) != SQLITE_ROW)
+ return 404;
+
if (path.size() >= 3) {
if ((path.size() == 4)&&(path[2] == "member")&&(path[3].length() == 10)) {
@@ -1000,6 +1079,12 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpDELETE(
char addrs[24];
Utils::snprintf(addrs,sizeof(addrs),"%.10llx",address);
+ sqlite3_reset(_sGetMember);
+ sqlite3_bind_text(_sGetMember,1,nwids,16,SQLITE_STATIC);
+ sqlite3_bind_text(_sGetMember,2,addrs,10,SQLITE_STATIC);
+ if (sqlite3_step(_sGetMember) != SQLITE_ROW)
+ return 404;
+
sqlite3_reset(_sDeleteIpAllocations);
sqlite3_bind_text(_sDeleteIpAllocations,1,nwids,16,SQLITE_STATIC);
sqlite3_bind_text(_sDeleteIpAllocations,2,addrs,10,SQLITE_STATIC);
@@ -1016,10 +1101,9 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpDELETE(
} else {
- sqlite3_reset(_sDeleteNetworkAndRelated);
- for(int i=1;i<=7;++i)
- sqlite3_bind_text(_sDeleteNetworkAndRelated,i,nwids,16,SQLITE_STATIC);
- return ((sqlite3_step(_sDeleteNetworkAndRelated) == SQLITE_DONE) ? 200 : 500);
+ sqlite3_reset(_sDeleteNetwork);
+ sqlite3_bind_text(_sDeleteNetwork,1,nwids,16,SQLITE_STATIC);
+ return ((sqlite3_step(_sDeleteNetwork) == SQLITE_DONE) ? 200 : 500);
}
} // else 404
@@ -1082,8 +1166,15 @@ unsigned int SqliteNetworkController::_doCPGet(
sqlite3_bind_text(_sGetIpAssignmentsForNode2,1,nwids,16,SQLITE_STATIC);
sqlite3_bind_text(_sGetIpAssignmentsForNode2,2,addrs,10,SQLITE_STATIC);
bool firstIp = true;
- while (sqlite3_step(_sGetIpAssignmentPools2) == SQLITE_ROW) {
- InetAddress ip((const void *)sqlite3_column_blob(_sGetIpAssignmentsForNode2,0),(sqlite3_column_int(_sGetIpAssignmentsForNode2,2) == 6) ? 16 : 4,(unsigned int)sqlite3_column_int(_sGetIpAssignmentPools2,1));
+ while (sqlite3_step(_sGetIpAssignmentsForNode2) == SQLITE_ROW) {
+ int ipversion = sqlite3_column_int(_sGetIpAssignmentsForNode2,2);
+ char ipBlob[16];
+ memcpy(ipBlob,(const void *)sqlite3_column_blob(_sGetIpAssignmentsForNode2,0),16);
+ InetAddress ip(
+ (const void *)(ipversion == 6 ? ipBlob : &ipBlob[12]),
+ (ipversion == 6 ? 16 : 4),
+ (unsigned int)sqlite3_column_int(_sGetIpAssignmentsForNode2,1)
+ );
responseBody.append(firstIp ? "\"" : ",\"");
firstIp = false;
responseBody.append(_jsonEscape(ip.toString()));
@@ -1202,6 +1293,49 @@ unsigned int SqliteNetworkController::_doCPGet(
responseBody.append(_jsonEscape((const char *)sqlite3_column_text(_sGetRelays,1)));
responseBody.append("\"}");
}
+ responseBody.append("],\n\t\"gateways\": [");
+
+ sqlite3_reset(_sGetGateways);
+ sqlite3_bind_text(_sGetGateways,1,nwids,16,SQLITE_STATIC);
+ bool firstGateway = true;
+ while (sqlite3_step(_sGetGateways) == SQLITE_ROW) {
+ char tmp[128];
+ const unsigned char *ip = (const unsigned char *)sqlite3_column_blob(_sGetGateways,0);
+ switch(sqlite3_column_int(_sGetGateways,1)) { // ipVersion
+ case 4:
+ Utils::snprintf(tmp,sizeof(tmp),"%s%d.%d.%d.%d/%d\"",
+ (firstGateway) ? "\"" : ",\"",
+ (int)ip[0],
+ (int)ip[1],
+ (int)ip[2],
+ (int)ip[3],
+ (int)sqlite3_column_int(_sGetGateways,2)); // metric
+ break;
+ case 6:
+ Utils::snprintf(tmp,sizeof(tmp),"%s%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x:%.2x%.2x/%d\"",
+ (firstGateway) ? "\"" : ",\"",
+ (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],
+ (int)sqlite3_column_int(_sGetGateways,2)); // metric
+ break;
+ }
+ responseBody.append(tmp);
+ firstGateway = false;
+ }
responseBody.append("],\n\t\"ipAssignmentPools\": [");
sqlite3_reset(_sGetIpAssignmentPools2);
@@ -1223,7 +1357,7 @@ unsigned int SqliteNetworkController::_doCPGet(
bool firstRule = true;
while (sqlite3_step(_sListRules) == SQLITE_ROW) {
responseBody.append(firstRule ? "\n\t{\n" : ",{\n");
- Utils::snprintf(json,sizeof(json),"\t\t\"ruleId\": %lld,\n",sqlite3_column_int64(_sListRules,0));
+ 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));
diff --git a/controller/SqliteNetworkController.hpp b/controller/SqliteNetworkController.hpp
index 5c92cc0b1..9cdbc4040 100644
--- a/controller/SqliteNetworkController.hpp
+++ b/controller/SqliteNetworkController.hpp
@@ -99,7 +99,6 @@ private:
sqlite3_stmt *_sUpdateNode;
sqlite3_stmt *_sUpdateNode2;
sqlite3_stmt *_sGetEtherTypesFromRuleTable;
- sqlite3_stmt *_sGetMulticastRates;
sqlite3_stmt *_sGetActiveBridges;
sqlite3_stmt *_sGetIpAssignmentsForNode;
sqlite3_stmt *_sGetIpAssignmentPools;
@@ -122,8 +121,13 @@ private:
sqlite3_stmt *_sDeleteIpAssignmentPoolsForNetwork;
sqlite3_stmt *_sDeleteRulesForNetwork;
sqlite3_stmt *_sCreateIpAssignmentPool;
+ sqlite3_stmt *_sUpdateMemberAuthorized;
+ sqlite3_stmt *_sUpdateMemberActiveBridge;
sqlite3_stmt *_sDeleteMember;
- sqlite3_stmt *_sDeleteNetworkAndRelated;
+ sqlite3_stmt *_sDeleteNetwork;
+ sqlite3_stmt *_sGetGateways;
+ sqlite3_stmt *_sDeleteGateways;
+ sqlite3_stmt *_sCreateGateway;
Mutex _lock;
};
diff --git a/controller/schema.sql b/controller/schema.sql
index b5646ee90..d2261b2af 100644
--- a/controller/schema.sql
+++ b/controller/schema.sql
@@ -3,53 +3,6 @@ CREATE TABLE Config (
v varchar(1024) NOT NULL
);
-CREATE TABLE IpAssignment (
- networkId char(16) NOT NULL,
- nodeId char(10) NOT NULL,
- ip blob(16) NOT NULL,
- ipNetmaskBits integer NOT NULL DEFAULT(0),
- ipVersion integer NOT NULL DEFAULT(4)
-);
-
-CREATE INDEX IpAssignment_networkId_ip ON IpAssignment (networkId, ip);
-
-CREATE INDEX IpAssignment_networkId_nodeId ON IpAssignment (networkId, nodeId);
-
-CREATE INDEX IpAssignment_networkId ON IpAssignment (networkId);
-
-CREATE TABLE IpAssignmentPool (
- networkId char(16) NOT NULL,
- ipNetwork blob(16) NOT NULL,
- ipNetmaskBits integer NOT NULL,
- ipVersion integer NOT NULL DEFAULT(4)
-);
-
-CREATE INDEX IpAssignmentPool_networkId ON IpAssignmentPool (networkId);
-
-CREATE TABLE Member (
- networkId char(16) NOT NULL,
- nodeId char(10) NOT NULL,
- authorized integer NOT NULL DEFAULT(0),
- activeBridge integer NOT NULL DEFAULT(0)
-);
-
-CREATE INDEX Member_networkId ON Member (networkId);
-
-CREATE INDEX Member_networkId_activeBridge ON Member(networkId, activeBridge);
-
-CREATE UNIQUE INDEX Member_networkId_nodeId ON Member (networkId, nodeId);
-
-CREATE TABLE MulticastRate (
- networkId char(16) NOT NULL,
- mgMac char(12) NOT NULL,
- mgAdi integer NOT NULL DEFAULT(0),
- preload integer NOT NULL,
- maxBalance integer NOT NULL,
- accrual integer NOT NULL
-);
-
-CREATE INDEX MulticastRate_networkId ON MulticastRate (networkId);
-
CREATE TABLE Network (
id char(16) PRIMARY KEY NOT NULL,
name varchar(128) NOT NULL,
@@ -63,16 +16,6 @@ CREATE TABLE Network (
revision integer NOT NULL DEFAULT(1)
);
-CREATE TABLE Relay (
- networkId char(16) NOT NULL,
- nodeId char(10) NOT NULL,
- phyAddress varchar(64) NOT NULL
-);
-
-CREATE INDEX Relay_networkId ON Relay (networkId);
-
-CREATE UNIQUE INDEX Relay_networkId_nodeId ON Relay (networkId, nodeId);
-
CREATE TABLE Node (
id char(10) PRIMARY KEY NOT NULL,
identity varchar(4096) NOT NULL,
@@ -81,10 +24,59 @@ CREATE TABLE Node (
firstSeen integer NOT NULL DEFAULT(0)
);
+CREATE TABLE Gateway (
+ networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
+ ip blob(16) NOT NULL,
+ ipVersion integer NOT NULL DEFAULT(4),
+ metric integer NOT NULL DEFAULT(0)
+);
+
+CREATE UNIQUE INDEX Gateway_networkId_ip ON Gateway (networkId, ip);
+
+CREATE TABLE IpAssignment (
+ networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
+ nodeId char(10) NOT NULL REFERENCES Node(id) ON DELETE CASCADE,
+ ip blob(16) NOT NULL,
+ ipNetmaskBits integer NOT NULL DEFAULT(0),
+ ipVersion integer NOT NULL DEFAULT(4)
+);
+
+CREATE UNIQUE INDEX IpAssignment_networkId_ip ON IpAssignment (networkId, ip);
+
+CREATE INDEX IpAssignment_networkId_nodeId ON IpAssignment (networkId, nodeId);
+
+CREATE TABLE IpAssignmentPool (
+ networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
+ ipNetwork blob(16) NOT NULL,
+ ipNetmaskBits integer NOT NULL,
+ ipVersion integer NOT NULL DEFAULT(4)
+);
+
+CREATE INDEX IpAssignmentPool_networkId ON IpAssignmentPool (networkId);
+
+CREATE TABLE Member (
+ networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
+ nodeId char(10) NOT NULL REFERENCES Node(id) ON DELETE CASCADE,
+ authorized integer NOT NULL DEFAULT(0),
+ activeBridge integer NOT NULL DEFAULT(0),
+ PRIMARY KEY (networkId, nodeId)
+);
+
+CREATE INDEX Member_networkId_activeBridge ON Member(networkId, activeBridge);
+
+CREATE TABLE Relay (
+ networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
+ nodeId char(10) NOT NULL REFERENCES Node(id) ON DELETE CASCADE,
+ phyAddress varchar(64) NOT NULL,
+ PRIMARY KEY (networkId, nodeId)
+);
+
+CREATE INDEX Relay_networkId ON Relay (networkId);
+
CREATE TABLE Rule (
- networkId char(16) NOT NULL,
- ruleId integer NOT NULL,
- nodeId char(10),
+ networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
+ ruleNo integer NOT NULL,
+ nodeId char(10) NOT NULL REFERENCES Node(id) ON DELETE CASCADE,
vlanId integer,
vlanPcp integer,
etherType integer,
@@ -101,4 +93,4 @@ CREATE TABLE Rule (
"action" varchar(4096) NOT NULL DEFAULT('accept')
);
-CREATE INDEX Rule_networkId ON Rule (networkId);
\ No newline at end of file
+CREATE UNIQUE INDEX Rule_networkId_ruleNo ON Rule (networkId, ruleNo);
diff --git a/controller/schema.sql.c b/controller/schema.sql.c
index 1384b9008..1157facc5 100644
--- a/controller/schema.sql.c
+++ b/controller/schema.sql.c
@@ -4,53 +4,6 @@
" v varchar(1024) NOT NULL\n"\
");\n"\
"\n"\
-"CREATE TABLE IpAssignment (\n"\
-" networkId char(16) NOT NULL,\n"\
-" nodeId char(10) NOT NULL,\n"\
-" ip blob(16) NOT NULL,\n"\
-" ipNetmaskBits integer NOT NULL DEFAULT(0),\n"\
-" ipVersion integer NOT NULL DEFAULT(4)\n"\
-");\n"\
-"\n"\
-"CREATE INDEX IpAssignment_networkId_ip ON IpAssignment (networkId, ip);\n"\
-"\n"\
-"CREATE INDEX IpAssignment_networkId_nodeId ON IpAssignment (networkId, nodeId);\n"\
-"\n"\
-"CREATE INDEX IpAssignment_networkId ON IpAssignment (networkId);\n"\
-"\n"\
-"CREATE TABLE IpAssignmentPool (\n"\
-" networkId char(16) NOT NULL,\n"\
-" ipNetwork blob(16) NOT NULL,\n"\
-" ipNetmaskBits integer NOT NULL,\n"\
-" ipVersion integer NOT NULL DEFAULT(4)\n"\
-");\n"\
-"\n"\
-"CREATE INDEX IpAssignmentPool_networkId ON IpAssignmentPool (networkId);\n"\
-"\n"\
-"CREATE TABLE Member (\n"\
-" networkId char(16) NOT NULL,\n"\
-" nodeId char(10) NOT NULL,\n"\
-" authorized integer NOT NULL DEFAULT(0),\n"\
-" activeBridge integer NOT NULL DEFAULT(0)\n"\
-");\n"\
-"\n"\
-"CREATE INDEX Member_networkId ON Member (networkId);\n"\
-"\n"\
-"CREATE INDEX Member_networkId_activeBridge ON Member(networkId, activeBridge);\n"\
-"\n"\
-"CREATE UNIQUE INDEX Member_networkId_nodeId ON Member (networkId, nodeId);\n"\
-"\n"\
-"CREATE TABLE MulticastRate (\n"\
-" networkId char(16) NOT NULL,\n"\
-" mgMac char(12) NOT NULL,\n"\
-" mgAdi integer NOT NULL DEFAULT(0),\n"\
-" preload integer NOT NULL,\n"\
-" maxBalance integer NOT NULL,\n"\
-" accrual integer NOT NULL\n"\
-");\n"\
-"\n"\
-"CREATE INDEX MulticastRate_networkId ON MulticastRate (networkId);\n"\
-"\n"\
"CREATE TABLE Network (\n"\
" id char(16) PRIMARY KEY NOT NULL,\n"\
" name varchar(128) NOT NULL,\n"\
@@ -64,16 +17,6 @@
" revision integer NOT NULL DEFAULT(1)\n"\
");\n"\
"\n"\
-"CREATE TABLE Relay (\n"\
-" networkId char(16) NOT NULL,\n"\
-" nodeId char(10) NOT NULL,\n"\
-" phyAddress varchar(64) NOT NULL\n"\
-");\n"\
-"\n"\
-"CREATE INDEX Relay_networkId ON Relay (networkId);\n"\
-"\n"\
-"CREATE UNIQUE INDEX Relay_networkId_nodeId ON Relay (networkId, nodeId);\n"\
-"\n"\
"CREATE TABLE Node (\n"\
" id char(10) PRIMARY KEY NOT NULL,\n"\
" identity varchar(4096) NOT NULL,\n"\
@@ -82,10 +25,59 @@
" firstSeen integer NOT NULL DEFAULT(0)\n"\
");\n"\
"\n"\
+"CREATE TABLE Gateway (\n"\
+" networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"\
+" ip blob(16) NOT NULL,\n"\
+" ipVersion integer NOT NULL DEFAULT(4),\n"\
+" metric integer NOT NULL DEFAULT(0)\n"\
+");\n"\
+"\n"\
+"CREATE UNIQUE INDEX Gateway_networkId_ip ON Gateway (networkId, ip);\n"\
+"\n"\
+"CREATE TABLE IpAssignment (\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"\
+" ip blob(16) NOT NULL,\n"\
+" ipNetmaskBits integer NOT NULL DEFAULT(0),\n"\
+" ipVersion integer NOT NULL DEFAULT(4)\n"\
+");\n"\
+"\n"\
+"CREATE UNIQUE INDEX IpAssignment_networkId_ip ON IpAssignment (networkId, ip);\n"\
+"\n"\
+"CREATE INDEX IpAssignment_networkId_nodeId ON IpAssignment (networkId, nodeId);\n"\
+"\n"\
+"CREATE TABLE IpAssignmentPool (\n"\
+" networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"\
+" ipNetwork blob(16) NOT NULL,\n"\
+" ipNetmaskBits integer NOT NULL,\n"\
+" ipVersion integer NOT NULL DEFAULT(4)\n"\
+");\n"\
+"\n"\
+"CREATE INDEX IpAssignmentPool_networkId ON IpAssignmentPool (networkId);\n"\
+"\n"\
+"CREATE TABLE Member (\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"\
+" authorized integer NOT NULL DEFAULT(0),\n"\
+" activeBridge integer NOT NULL DEFAULT(0),\n"\
+" PRIMARY KEY (networkId, nodeId)\n"\
+");\n"\
+"\n"\
+"CREATE INDEX Member_networkId_activeBridge ON Member(networkId, activeBridge);\n"\
+"\n"\
+"CREATE TABLE Relay (\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"\
+" phyAddress varchar(64) NOT NULL,\n"\
+" PRIMARY KEY (networkId, nodeId)\n"\
+");\n"\
+"\n"\
+"CREATE INDEX Relay_networkId ON Relay (networkId);\n"\
+"\n"\
"CREATE TABLE Rule (\n"\
-" networkId char(16) NOT NULL,\n"\
-" ruleId integer NOT NULL,\n"\
-" nodeId char(10),\n"\
+" networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"\
+" ruleNo integer NOT NULL,\n"\
+" nodeId char(10) NOT NULL REFERENCES Node(id) ON DELETE CASCADE,\n"\
" vlanId integer,\n"\
" vlanPcp integer,\n"\
" etherType integer,\n"\
@@ -102,5 +94,5 @@
" \"action\" varchar(4096) NOT NULL DEFAULT('accept')\n"\
");\n"\
"\n"\
-"CREATE INDEX Rule_networkId ON Rule (networkId);\n"\
+"CREATE UNIQUE INDEX Rule_networkId_ruleNo ON Rule (networkId, ruleNo);\n"\
""
diff --git a/ext/installfiles/linux/buildinstaller.sh b/ext/installfiles/linux/buildinstaller.sh
index 496ba32ce..4f661b8d5 100755
--- a/ext/installfiles/linux/buildinstaller.sh
+++ b/ext/installfiles/linux/buildinstaller.sh
@@ -49,9 +49,12 @@ case "$system" in
echo "Assembling Linux installer for $machine and version $vmajor.$vminor.$revision"
- mkdir -p 'build-installer/var/lib/zerotier-one'
+ mkdir -p 'build-installer/var/lib/zerotier-one/ui'
cp -fp 'ext/installfiles/linux/uninstall.sh' 'build-installer/var/lib/zerotier-one'
cp -fp 'zerotier-one' 'build-installer/var/lib/zerotier-one'
+ for f in ui/*.html ui/*.js ui/*.css ui/*.jsx ; do
+ cp -fp "$f" 'build-installer/var/lib/zerotier-one/ui'
+ done
mkdir -p 'build-installer/tmp'
cp -fp 'ext/installfiles/linux/init.d/zerotier-one' 'build-installer/tmp/init.d_zerotier-one'
cp -fp 'ext/installfiles/linux/systemd/zerotier-one.service' 'build-installer/tmp/systemd_zerotier-one.service'
diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h
index 9b82c8d6f..b6ff69abe 100644
--- a/include/ZeroTierOne.h
+++ b/include/ZeroTierOne.h
@@ -251,7 +251,7 @@ enum ZT1_Event
/**
* A more recent version was observed on the network
*
- * Right now this is only triggered if a hub or supernode reports a
+ * Right now this is only triggered if a hub or rootserver reports a
* more recent version, and only once. It can be used to trigger a
* software update check.
*
@@ -559,8 +559,8 @@ typedef struct
*/
enum ZT1_PeerRole {
ZT1_PEER_ROLE_LEAF = 0, // ordinary node
- ZT1_PEER_ROLE_HUB = 1, // locally federated hub
- ZT1_PEER_ROLE_SUPERNODE = 2 // planetary supernode
+ ZT1_PEER_ROLE_RELAY = 1, // relay node
+ ZT1_PEER_ROLE_ROOT = 2 // root server
};
/**
diff --git a/java/jni/ZT1_jniutils.cpp b/java/jni/ZT1_jniutils.cpp
index e6404e87e..8779c3c35 100644
--- a/java/jni/ZT1_jniutils.cpp
+++ b/java/jni/ZT1_jniutils.cpp
@@ -174,8 +174,8 @@ jobject createPeerRole(JNIEnv *env, ZT1_PeerRole role)
case ZT1_PEER_ROLE_HUB:
fieldName = "PEER_ROLE_HUB";
break;
- case ZT1_PEER_ROLE_SUPERNODE:
- fieldName = "PEER_ROLE_SUPERNODE";
+ case ZT1_PEER_ROLE_ROOTSERVER:
+ fieldName = "PEER_ROLE_ROOTSERVER";
break;
}
diff --git a/java/src/com/zerotier/sdk/Event.java b/java/src/com/zerotier/sdk/Event.java
index d315990b1..436b1b226 100644
--- a/java/src/com/zerotier/sdk/Event.java
+++ b/java/src/com/zerotier/sdk/Event.java
@@ -90,7 +90,7 @@ public enum Event {
/**
* A more recent version was observed on the network
*
- * Right now this is only triggered if a hub or supernode reports a
+ *
Right now this is only triggered if a hub or rootserver reports a
* more recent version, and only once. It can be used to trigger a
* software update check.
*
diff --git a/java/src/com/zerotier/sdk/PeerRole.java b/java/src/com/zerotier/sdk/PeerRole.java
index 56c3ac0c8..7a5156e1b 100644
--- a/java/src/com/zerotier/sdk/PeerRole.java
+++ b/java/src/com/zerotier/sdk/PeerRole.java
@@ -39,7 +39,7 @@ public enum PeerRole {
PEER_ROLE_HUB,
/**
- * planetary supernode
+ * planetary rootserver
*/
- PEER_ROLE_SUPERNODE
+ PEER_ROLE_ROOTSERVER
}
\ No newline at end of file
diff --git a/js/zt1-api-client/constrain-types.js b/js/zt1-api-client/constrain-types.js
deleted file mode 100644
index 5b1137d59..000000000
--- a/js/zt1-api-client/constrain-types.js
+++ /dev/null
@@ -1,58 +0,0 @@
-'use strict'
-
-function convertType(v,t)
-{
- if (Array.isArray(t)) {
- var r = v;
- if (t.length !== 0) {
- if (Array.isArray(v)) {
- r = [];
- for(var i=0;i
case Packet::ERROR_OBJ_NOT_FOUND:
if (inReVerb == Packet::VERB_WHOIS) {
- if (RR->topology->isSupernode(peer->address()))
+ if (RR->topology->isRoot(peer->identity()))
RR->sw->cancelWhoisRequest(Address(field(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH));
} else if (inReVerb == Packet::VERB_NETWORK_CONFIG_REQUEST) {
SharedPtr network(RR->node->network(at(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
@@ -128,7 +128,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr
break;
case Packet::ERROR_IDENTITY_COLLISION:
- if (RR->topology->isSupernode(peer->address()))
+ if (RR->topology->isRoot(peer->identity()))
RR->node->postEvent(ZT1_EVENT_FATAL_ERROR_IDENTITY_COLLISION);
break;
@@ -268,7 +268,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR)
peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision);
bool trusted = false;
- if (RR->topology->isSupernode(id.address())) {
+ if (RR->topology->isRoot(id)) {
RR->node->postNewerVersionIfNewer(vMajor,vMinor,vRevision);
trusted = true;
}
@@ -353,7 +353,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p
peer->setRemoteVersion(vProto,vMajor,vMinor,vRevision);
bool trusted = false;
- if (RR->topology->isSupernode(peer->address())) {
+ if (RR->topology->isRoot(peer->identity())) {
RR->node->postNewerVersionIfNewer(vMajor,vMinor,vRevision);
trusted = true;
}
@@ -362,10 +362,10 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,const SharedPtr &p
} break;
case Packet::VERB_WHOIS: {
- // Right now only supernodes are allowed to send OK(WHOIS) to prevent
- // poisoning attacks. Further decentralization will require some other
- // kind of trust mechanism.
- if (RR->topology->isSupernode(peer->address())) {
+ /* Right now only root servers are allowed to send OK(WHOIS) to prevent
+ * poisoning attacks. Further decentralization will require some other
+ * kind of trust mechanism. */
+ if (RR->topology->isRoot(peer->identity())) {
const Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY);
if (id.locallyValidate())
RR->sw->doAnythingWaitingForPeer(RR->topology->addPeer(SharedPtr(new Peer(RR->identity,id))));
@@ -689,6 +689,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
outp.append((uint16_t)netconfStr.length());
outp.append(netconfStr.data(),(unsigned int)netconfStr.length());
outp.compress();
+ outp.armor(peer->key(),true);
if (outp.size() > ZT_PROTO_MAX_PACKET_LENGTH) {
TRACE("NETWORK_CONFIG_REQUEST failed: internal error: netconf size %u is too large",(unsigned int)netconfStr.length());
} else {
diff --git a/node/InetAddress.hpp b/node/InetAddress.hpp
index 5b7251745..16e3f4d52 100644
--- a/node/InetAddress.hpp
+++ b/node/InetAddress.hpp
@@ -265,6 +265,16 @@ struct InetAddress : public sockaddr_storage
*/
inline unsigned int netmaskBits() const throw() { return port(); }
+ /**
+ * Alias for port()
+ *
+ * This just aliases port() because for gateways we use this field to
+ * store the gateway metric.
+ *
+ * @return Gateway metric
+ */
+ inline unsigned int metric() const throw() { return port(); }
+
/**
* Construct a full netmask as an InetAddress
*/
diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp
index 7da2b14c3..8a15bac13 100644
--- a/node/Multicaster.cpp
+++ b/node/Multicaster.cpp
@@ -216,7 +216,7 @@ void Multicaster::send(
if ((now - gs.lastExplicitGather) >= ZT_MULTICAST_EXPLICIT_GATHER_DELAY) {
gs.lastExplicitGather = now;
- SharedPtr sn(RR->topology->getBestSupernode());
+ SharedPtr sn(RR->topology->getBestRoot());
if (sn) {
TRACE(">>MC upstream GATHER up to %u for group %.16llx/%s",gatherLimit,nwid,mg.toString().c_str());
@@ -269,61 +269,18 @@ void Multicaster::send(
// Free allocated memory buffer if any
if (indexes != idxbuf)
delete [] indexes;
-
-#ifdef ZT_SUPPORT_LEGACY_MULTICAST
- // This sends a P5 multicast up to our supernode, who then
- // redistributes it manually down to all <1.0.0 peers for
- // legacy support. These peers don't support the new multicast
- // frame type, so even if they receive it they will ignore it.
- {
- SharedPtr sn(RR->topology->getBestSupernode());
- if (sn) {
- uint32_t rn = RR->prng->next32();
- Packet outp(sn->address(),RR->identity.address(),Packet::VERB_P5_MULTICAST_FRAME);
-
- outp.append((uint16_t)0xffff); // do not forward
- outp.append((unsigned char)0,320 + 1024); // empty queue and bloom filter
-
- outp.append((unsigned char)((com) ? ZT_PROTO_VERB_P5_MULTICAST_FRAME_FLAGS_HAS_MEMBERSHIP_CERTIFICATE : 0));
- outp.append((uint64_t)nwid);
- outp.append((uint16_t)0);
- outp.append((unsigned char)0);
- outp.append((unsigned char)0);
- RR->identity.address().appendTo(outp);
- outp.append((const void *)&rn,3); // random multicast ID
- if (src)
- src.appendTo(outp);
- else MAC(RR->identity.address(),nwid).appendTo(outp);
- mg.mac().appendTo(outp);
- outp.append((uint32_t)mg.adi());
- outp.append((uint16_t)etherType);
- outp.append((uint16_t)len);
- outp.append(data,len);
- unsigned int signedPortionLen = outp.size() - ZT_PROTO_VERB_P5_MULTICAST_FRAME_IDX__START_OF_SIGNED_PORTION;
-
- C25519::Signature sig(RR->identity.sign(outp.field(ZT_PROTO_VERB_P5_MULTICAST_FRAME_IDX__START_OF_SIGNED_PORTION,signedPortionLen),signedPortionLen));
-
- outp.append((uint16_t)sig.size());
- outp.append(sig.data,(unsigned int)sig.size());
-
- if (com) com->serialize(outp);
-
- outp.compress();
- outp.armor(sn->key(),true);
- sn->send(RR,outp.data(),outp.size(),now);
- }
- }
-#endif // ZT_SUPPORT_LEGACY_MULTICAST
}
void Multicaster::clean(uint64_t now)
{
Mutex::Lock _l(_groups_m);
for(std::map< std::pair,MulticastGroupStatus >::iterator mm(_groups.begin());mm!=_groups.end();) {
- for(std::list::iterator tx(mm->second.txQueue.begin());tx!=mm->second.txQueue.end();) {
- if ((tx->expired(now))||(tx->atLimit()))
- mm->second.txQueue.erase(tx++);
- else ++tx;
+ for(std::vector::iterator tx(mm->second.txQueue.begin());tx!=mm->second.txQueue.end();) {
+ if ((tx->expired(now))||(tx->atLimit())) {
+ // erase element (replace by last)
+ *tx = mm->second.txQueue.back();
+ mm->second.txQueue.pop_back();
+ } else ++tx;
}
unsigned long count = 0;
@@ -371,14 +328,18 @@ void Multicaster::_add(uint64_t now,uint64_t nwid,const MulticastGroup &mg,Multi
//TRACE("..MC %s joined multicast group %.16llx/%s via %s",member.toString().c_str(),nwid,mg.toString().c_str(),((learnedFrom) ? learnedFrom.toString().c_str() : "(direct)"));
- for(std::list::iterator tx(gs.txQueue.begin());tx!=gs.txQueue.end();) {
+ for(std::vector::iterator tx(gs.txQueue.begin());tx!=gs.txQueue.end();) {
if (tx->atLimit()) {
- gs.txQueue.erase(tx++);
+ // erase element (replace by last)
+ *tx = gs.txQueue.back();
+ gs.txQueue.pop_back();
} else {
tx->sendIfNew(RR,member);
- if (tx->atLimit())
- gs.txQueue.erase(tx++);
- else ++tx;
+ if (tx->atLimit()) {
+ // erase element (replace by last)
+ *tx = gs.txQueue.back();
+ gs.txQueue.pop_back();
+ } else ++tx;
}
}
}
diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp
index c6c93b1ff..281222b84 100644
--- a/node/Multicaster.hpp
+++ b/node/Multicaster.hpp
@@ -70,7 +70,7 @@ private:
MulticastGroupStatus() : lastExplicitGather(0) {}
uint64_t lastExplicitGather;
- std::list txQueue; // pending outbound multicasts
+ std::vector txQueue; // pending outbound multicasts
std::vector members; // members of this group
};
diff --git a/node/Network.cpp b/node/Network.cpp
index e513f43f9..c072e9785 100644
--- a/node/Network.cpp
+++ b/node/Network.cpp
@@ -286,18 +286,28 @@ void Network::addMembershipCertificate(const CertificateOfMembership &cert,bool
return;
}
- SharedPtr signer(RR->topology->getPeer(cert.signedBy()));
+ if (cert.signedBy() == RR->identity.address()) {
+ // We are the controller: RR->identity.address() == controller() == cert.signedBy()
+ // So, verify that we signed th cert ourself
+ if (!cert.verify(RR->identity)) {
+ TRACE("rejected network membership certificate for %.16llx self signed by %s: signature check failed",(unsigned long long)_id,cert.signedBy().toString().c_str());
+ return;
+ }
+ } else {
- if (!signer) {
- // This would be rather odd, since this is our controller... could happen
- // if we get packets before we've gotten config.
- RR->sw->requestWhois(cert.signedBy());
- return;
- }
+ SharedPtr signer(RR->topology->getPeer(cert.signedBy()));
- if (!cert.verify(signer->identity())) {
- TRACE("rejected network membership certificate for %.16llx signed by %s: signature check failed",(unsigned long long)_id,cert.signedBy().toString().c_str());
- return;
+ if (!signer) {
+ // This would be rather odd, since this is our controller... could happen
+ // if we get packets before we've gotten config.
+ RR->sw->requestWhois(cert.signedBy());
+ return;
+ }
+
+ if (!cert.verify(signer->identity())) {
+ TRACE("rejected network membership certificate for %.16llx signed by %s: signature check failed",(unsigned long long)_id,cert.signedBy().toString().c_str());
+ return;
+ }
}
}
@@ -357,20 +367,6 @@ void Network::clean()
}
}
-bool Network::updateAndCheckMulticastBalance(const MulticastGroup &mg,unsigned int bytes)
-{
- const uint64_t now = RR->node->now();
- Mutex::Lock _l(_lock);
- if (!_config)
- return false;
- std::map< MulticastGroup,BandwidthAccount >::iterator bal(_multicastRateAccounts.find(mg));
- if (bal == _multicastRateAccounts.end()) {
- NetworkConfig::MulticastRate r(_config->multicastRate(mg));
- bal = _multicastRateAccounts.insert(std::pair< MulticastGroup,BandwidthAccount >(mg,BandwidthAccount(r.preload,r.maxBalance,r.accrual,now))).first;
- }
- return bal->second.deduct(bytes,now);
-}
-
void Network::learnBridgeRoute(const MAC &mac,const Address &addr)
{
Mutex::Lock _l(_lock);
@@ -518,13 +514,13 @@ public:
RR(renv),
_now(renv->node->now()),
_network(nw),
- _supernodeAddresses(renv->topology->supernodeAddresses()),
+ _rootAddresses(renv->topology->rootAddresses()),
_allMulticastGroups(nw->_allMulticastGroups())
{}
inline void operator()(Topology &t,const SharedPtr &p)
{
- if ( ( (p->hasActiveDirectPath(_now)) && (_network->_isAllowed(p->address())) ) || (std::find(_supernodeAddresses.begin(),_supernodeAddresses.end(),p->address()) != _supernodeAddresses.end()) ) {
+ if ( ( (p->hasActiveDirectPath(_now)) && (_network->_isAllowed(p->address())) ) || (std::find(_rootAddresses.begin(),_rootAddresses.end(),p->address()) != _rootAddresses.end()) ) {
Packet outp(p->address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
for(std::vector::iterator mg(_allMulticastGroups.begin());mg!=_allMulticastGroups.end();++mg) {
@@ -551,7 +547,7 @@ private:
const RuntimeEnvironment *RR;
uint64_t _now;
Network *_network;
- std::vector _supernodeAddresses;
+ std::vector _rootAddresses;
std::vector _allMulticastGroups;
};
diff --git a/node/Network.hpp b/node/Network.hpp
index 7976d9018..daa4554e6 100644
--- a/node/Network.hpp
+++ b/node/Network.hpp
@@ -47,7 +47,6 @@
#include "MulticastGroup.hpp"
#include "MAC.hpp"
#include "Dictionary.hpp"
-#include "BandwidthAccount.hpp"
#include "Multicaster.hpp"
#include "NetworkConfig.hpp"
#include "CertificateOfMembership.hpp"
@@ -237,15 +236,6 @@ public:
_externalConfig(ec);
}
- /**
- * Update and check multicast rate balance for a multicast group
- *
- * @param mg Multicast group
- * @param bytes Size of packet
- * @return True if packet is within budget
- */
- bool updateAndCheckMulticastBalance(const MulticastGroup &mg,unsigned int bytes);
-
/**
* Get current network config or throw exception
*
@@ -370,7 +360,6 @@ private:
std::vector< MulticastGroup > _myMulticastGroups; // multicast groups that we belong to including those behind us (updated periodically)
std::map< MulticastGroup,uint64_t > _multicastGroupsBehindMe; // multicast groups bridged to us and when we last saw activity on each
- std::map< MulticastGroup,BandwidthAccount > _multicastRateAccounts;
std::map _remoteBridgeRoutes; // remote addresses where given MACs are reachable
diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp
index 4b9620a6c..8d682947f 100644
--- a/node/NetworkConfig.cpp
+++ b/node/NetworkConfig.cpp
@@ -32,10 +32,6 @@
namespace ZeroTier {
-// This is fast enough for things like Apple's mDNS spam, so it should serve
-// as a good default for your average network.
-const NetworkConfig::MulticastRate NetworkConfig::DEFAULT_MULTICAST_RATE(40000,60000,80);
-
SharedPtr NetworkConfig::createTestNetworkConfig(const Address &self)
{
SharedPtr nc(new NetworkConfig());
@@ -85,18 +81,6 @@ std::vector NetworkConfig::allowedEtherTypes() const
return ets;
}
-const NetworkConfig::MulticastRate &NetworkConfig::multicastRate(const MulticastGroup &mg) const
- throw()
-{
- std::map::const_iterator r(_multicastRates.find(mg));
- if (r == _multicastRates.end()) {
- r = _multicastRates.find(MulticastGroup()); // zero MG signifies network's default rate
- if (r == _multicastRates.end())
- return DEFAULT_MULTICAST_RATE; // neither specific nor default found in network config
- }
- return r->second;
-}
-
void NetworkConfig::_fromDictionary(const Dictionary &d)
{
static const std::string zero("0");
@@ -163,6 +147,13 @@ void NetworkConfig::_fromDictionary(const Dictionary &d)
std::sort(_staticIps.begin(),_staticIps.end());
std::unique(_staticIps.begin(),_staticIps.end());
+ std::vector gatewaysSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_GATEWAYS,"").c_str(),",","",""));
+ for(std::vector::const_iterator gwstr(gatewaysSplit.begin());gwstr!=gatewaysSplit.end();++gwstr) {
+ InetAddress gw(*gwstr);
+ if ((std::find(_gateways.begin(),_gateways.end(),gw) == _gateways.end())&&((gw.ss_family == AF_INET)||(gw.ss_family == AF_INET6)))
+ _gateways.push_back(gw);
+ }
+
std::vector activeBridgesSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES,"").c_str(),",","",""));
for(std::vector::const_iterator a(activeBridgesSplit.begin());a!=activeBridgesSplit.end();++a) {
if (a->length() == ZT_ADDRESS_LENGTH_HEX) { // ignore empty or garbage fields
@@ -174,13 +165,6 @@ void NetworkConfig::_fromDictionary(const Dictionary &d)
std::sort(_activeBridges.begin(),_activeBridges.end());
std::unique(_activeBridges.begin(),_activeBridges.end());
- Dictionary multicastRateEntries(d.get(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_RATES,std::string()));
- for(Dictionary::const_iterator i(multicastRateEntries.begin());i!=multicastRateEntries.end();++i) {
- std::vector params(Utils::split(i->second.c_str(),",","",""));
- if (params.size() >= 3)
- _multicastRates[MulticastGroup(i->first)] = MulticastRate(Utils::hexStrToUInt(params[0].c_str()),Utils::hexStrToUInt(params[1].c_str()),Utils::hexStrToUInt(params[2].c_str()));
- }
-
std::vector relaysSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_RELAYS,"").c_str(),",","",""));
for(std::vector::const_iterator r(relaysSplit.begin());r!=relaysSplit.end();++r) {
std::size_t semi(r->find(';')); // address;ip/port,...
@@ -211,15 +195,9 @@ bool NetworkConfig::operator==(const NetworkConfig &nc) const
if (_name != nc._name) return false;
if (_description != nc._description) return false;
if (_staticIps != nc._staticIps) return false;
+ if (_gateways != nc._gateways) return false;
if (_activeBridges != nc._activeBridges) return false;
- if (_multicastRates.size() == nc._multicastRates.size()) {
- // uclibc++ doesn't seem to implement map<> != map<> correctly, so do
- // it ourselves. Note that this depends on the maps being sorted.
- for(std::map::const_iterator a(_multicastRates.begin()),b(nc._multicastRates.begin());a!=_multicastRates.end();++a,++b) {
- if ((a->first != b->first)||(a->second != b->second))
- return false;
- }
- } else return false;
+ if (_relays != nc._relays) return false;
if (_com != nc._com) return false;
return true;
}
diff --git a/node/NetworkConfig.hpp b/node/NetworkConfig.hpp
index 89d1aec50..75395fd53 100644
--- a/node/NetworkConfig.hpp
+++ b/node/NetworkConfig.hpp
@@ -49,24 +49,58 @@ namespace ZeroTier {
// These dictionary keys are short so they don't take up much room in
// netconf response packets.
+
+// integer(hex)[,integer(hex),...]
#define ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES "et"
+
+// network ID
#define ZT_NETWORKCONFIG_DICT_KEY_NETWORK_ID "nwid"
+
+// integer(hex)
#define ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP "ts"
+
+// integer(hex)
#define ZT_NETWORKCONFIG_DICT_KEY_REVISION "r"
+
+// address of member
#define ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO "id"
+
+// integer(hex)
#define ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT "ml"
-#define ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_RATES "mr"
+
+// 0/1
#define ZT_NETWORKCONFIG_DICT_KEY_PRIVATE "p"
+
+// text
#define ZT_NETWORKCONFIG_DICT_KEY_NAME "n"
+
+// text
#define ZT_NETWORKCONFIG_DICT_KEY_DESC "d"
+
+// IP/bits[,IP/bits,...]
#define ZT_NETWORKCONFIG_DICT_KEY_IPV4_STATIC "v4s"
+
+// IP/bits[,IP/bits,...]
#define ZT_NETWORKCONFIG_DICT_KEY_IPV6_STATIC "v6s"
+
+// serialized CertificateOfMembership
#define ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP "com"
+
+// 0/1
#define ZT_NETWORKCONFIG_DICT_KEY_ENABLE_BROADCAST "eb"
+
+// 0/1
#define ZT_NETWORKCONFIG_DICT_KEY_ALLOW_PASSIVE_BRIDGING "pb"
+
+// node[,node,...]
#define ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES "ab"
+
+// node;IP/port[,node;IP/port]
#define ZT_NETWORKCONFIG_DICT_KEY_RELAYS "rl"
+// IP/metric[,IP/metric,...]
+#define ZT_NETWORKCONFIG_DICT_KEY_GATEWAYS "gw"
+
/**
* Network configuration received from network controller nodes
*
@@ -77,27 +111,6 @@ class NetworkConfig
friend class SharedPtr;
public:
- /**
- * Tuple of multicast rate parameters
- */
- struct MulticastRate
- {
- MulticastRate() throw() {}
- MulticastRate(uint32_t pl,uint32_t maxb,uint32_t acc) throw() : preload(pl),maxBalance(maxb),accrual(acc) {}
-
- uint32_t preload;
- uint32_t maxBalance;
- uint32_t accrual;
-
- inline bool operator==(const MulticastRate &mr) const { return ((preload == mr.preload)&&(maxBalance == mr.maxBalance)&&(accrual == mr.accrual)); }
- inline bool operator!=(const MulticastRate &mr) const { return (!(*this == mr)); }
- };
-
- /**
- * A hard-coded default multicast rate for networks that don't specify
- */
- static const MulticastRate DEFAULT_MULTICAST_RATE;
-
/**
* Create an instance of a NetworkConfig for the test network ID
*
@@ -139,13 +152,13 @@ public:
inline uint64_t revision() const throw() { return _revision; }
inline const Address &issuedTo() const throw() { return _issuedTo; }
inline unsigned int multicastLimit() const throw() { return _multicastLimit; }
- inline const std::map &multicastRates() const throw() { return _multicastRates; }
inline bool allowPassiveBridging() const throw() { return _allowPassiveBridging; }
inline bool isPublic() const throw() { return (!_private); }
inline bool isPrivate() const throw() { return _private; }
inline const std::string &name() const throw() { return _name; }
inline const std::string &description() const throw() { return _description; }
inline const std::vector &staticIps() const throw() { return _staticIps; }
+ inline const std::vector &gateways() const throw() { return _gateways; }
inline const std::vector &activeBridges() const throw() { return _activeBridges; }
inline const std::vector< std::pair > &relays() const throw() { return _relays; }
inline const CertificateOfMembership &com() const throw() { return _com; }
@@ -160,13 +173,6 @@ public:
return ( (_allowPassiveBridging) || (std::find(_activeBridges.begin(),_activeBridges.end(),fromPeer) != _activeBridges.end()) );
}
- /**
- * @param mg Multicast group
- * @return Multicast rate or DEFAULT_MULTICAST_RATE if not set
- */
- const MulticastRate &multicastRate(const MulticastGroup &mg) const
- throw();
-
bool operator==(const NetworkConfig &nc) const;
inline bool operator!=(const NetworkConfig &nc) const { return (!(*this == nc)); }
@@ -188,9 +194,9 @@ private:
std::string _name;
std::string _description;
std::vector _staticIps;
+ std::vector _gateways;
std::vector _activeBridges;
std::vector< std::pair > _relays;
- std::map _multicastRates;
CertificateOfMembership _com;
AtomicCounter __refCount;
diff --git a/node/Node.cpp b/node/Node.cpp
index 9f195a106..850114341 100644
--- a/node/Node.cpp
+++ b/node/Node.cpp
@@ -133,7 +133,7 @@ Node::Node(
if (!rt.size())
rt.fromString(ZT_DEFAULTS.defaultRootTopology);
}
- RR->topology->setSupernodes(Dictionary(rt.get("supernodes","")));
+ RR->topology->setRootServers(Dictionary(rt.get("rootservers","")));
postEvent(ZT1_EVENT_UP);
}
@@ -141,7 +141,7 @@ Node::Node(
Node::~Node()
{
Mutex::Lock _l(_networks_m);
- _networks.clear();
+ _networks.clear(); // ensure that networks are destroyed before shutdown
delete RR->sa;
delete RR->topology;
delete RR->antiRec;
@@ -189,7 +189,7 @@ public:
RR(renv),
_now(now),
_relays(relays),
- _supernodes(RR->topology->supernodeAddresses())
+ _rootAddresses(RR->topology->rootAddresses())
{
}
@@ -205,7 +205,7 @@ public:
}
}
- if ((isRelay)||(std::find(_supernodes.begin(),_supernodes.end(),p->address()) != _supernodes.end())) {
+ if ((isRelay)||(std::find(_rootAddresses.begin(),_rootAddresses.end(),p->address()) != _rootAddresses.end())) {
p->doPingAndKeepalive(RR,_now);
if (p->lastReceive() > lastReceiveFromUpstream)
lastReceiveFromUpstream = p->lastReceive();
@@ -219,7 +219,7 @@ private:
const RuntimeEnvironment *RR;
uint64_t _now;
const std::vector< std::pair > &_relays;
- std::vector _supernodes;
+ std::vector _rootAddresses;
};
ZT1_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *nextBackgroundTaskDeadline)
@@ -236,7 +236,7 @@ ZT1_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *next
std::vector< SharedPtr > needConfig;
{
Mutex::Lock _l(_networks_m);
- for(std::map< uint64_t,SharedPtr >::const_iterator n(_networks.begin());n!=_networks.end();++n) {
+ for(std::vector< std::pair< uint64_t,SharedPtr > >::const_iterator n(_networks.begin());n!=_networks.end();++n) {
SharedPtr nc(n->second->config2());
if (((now - n->second->lastConfigUpdate()) >= ZT_NETWORK_AUTOCONF_DELAY)||(!nc))
needConfig.push_back(n->second);
@@ -260,7 +260,7 @@ ZT1_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *next
}
}
- // Ping living or supernode/relay peers
+ // Ping living or root server/relay peers
_PingPeersThatNeedPing pfunc(RR,now,networkRelays);
RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc);
@@ -310,20 +310,22 @@ ZT1_ResultCode Node::processBackgroundTasks(uint64_t now,volatile uint64_t *next
ZT1_ResultCode Node::join(uint64_t nwid)
{
Mutex::Lock _l(_networks_m);
- SharedPtr &nwe = _networks[nwid];
- if (!nwe)
- nwe = SharedPtr(new Network(RR,nwid));
+ SharedPtr nw = _network(nwid);
+ if(!nw)
+ _networks.push_back(std::pair< uint64_t,SharedPtr >(nwid,SharedPtr(new Network(RR,nwid))));
+ std::sort(_networks.begin(),_networks.end()); // will sort by nwid since it's the first in a pair<>
return ZT1_RESULT_OK;
}
ZT1_ResultCode Node::leave(uint64_t nwid)
{
+ std::vector< std::pair< uint64_t,SharedPtr > > newn;
Mutex::Lock _l(_networks_m);
- std::map< uint64_t,SharedPtr >::iterator nw(_networks.find(nwid));
- if (nw != _networks.end()) {
- nw->second->destroy();
- _networks.erase(nw);
+ for(std::vector< std::pair< uint64_t,SharedPtr > >::const_iterator n(_networks.begin());n!=_networks.end();++n) {
+ if (n->first != nwid)
+ newn.push_back(*n);
}
+ _networks.swap(newn);
return ZT1_RESULT_OK;
}
@@ -384,7 +386,7 @@ ZT1_PeerList *Node::peers() const
p->versionRev = -1;
}
p->latency = pi->second->latency();
- p->role = RR->topology->isSupernode(pi->second->address()) ? ZT1_PEER_ROLE_SUPERNODE : ZT1_PEER_ROLE_LEAF;
+ p->role = RR->topology->isRoot(pi->second->identity()) ? ZT1_PEER_ROLE_ROOT : ZT1_PEER_ROLE_LEAF;
std::vector paths(pi->second->paths());
Path *bestPath = pi->second->getBestPath(_now);
@@ -406,10 +408,10 @@ ZT1_PeerList *Node::peers() const
ZT1_VirtualNetworkConfig *Node::networkConfig(uint64_t nwid) const
{
Mutex::Lock _l(_networks_m);
- std::map< uint64_t,SharedPtr >::const_iterator nw(_networks.find(nwid));
- if (nw != _networks.end()) {
+ SharedPtr nw = _network(nwid);
+ if(nw) {
ZT1_VirtualNetworkConfig *nc = (ZT1_VirtualNetworkConfig *)::malloc(sizeof(ZT1_VirtualNetworkConfig));
- nw->second->externalConfig(nc);
+ nw->externalConfig(nc);
return nc;
}
return (ZT1_VirtualNetworkConfig *)0;
@@ -426,7 +428,7 @@ ZT1_VirtualNetworkList *Node::networks() const
nl->networks = (ZT1_VirtualNetworkConfig *)(buf + sizeof(ZT1_VirtualNetworkList));
nl->networkCount = 0;
- for(std::map< uint64_t,SharedPtr >::const_iterator n(_networks.begin());n!=_networks.end();++n)
+ for(std::vector< std::pair< uint64_t,SharedPtr > >::const_iterator n(_networks.begin());n!=_networks.end();++n)
n->second->externalConfig(&(nl->networks[nl->networkCount++]));
return nl;
diff --git a/node/Node.hpp b/node/Node.hpp
index 1d9372e46..2d2898b57 100644
--- a/node/Node.hpp
+++ b/node/Node.hpp
@@ -155,19 +155,19 @@ public:
len);
}
- inline SharedPtr network(uint64_t nwid)
+ inline SharedPtr network(uint64_t nwid) const
{
Mutex::Lock _l(_networks_m);
- std::map< uint64_t,SharedPtr >::iterator nw(_networks.find(nwid));
- return ((nw == _networks.end()) ? SharedPtr() : nw->second);
+ return _network(nwid);
}
inline std::vector< SharedPtr > allNetworks() const
{
- Mutex::Lock _l(_networks_m);
std::vector< SharedPtr > nw;
- for(std::map< uint64_t,SharedPtr >::const_iterator n(_networks.begin());n!=_networks.end();++n)
- nw.push_back(n->second);
+ Mutex::Lock _l(_networks_m);
+ nw.reserve(_networks.size());
+ for(std::vector< std::pair< uint64_t, SharedPtr > >::const_iterator i=_networks.begin();i!=_networks.end();++i)
+ nw.push_back(i->second);
return nw;
}
@@ -208,6 +208,16 @@ public:
#endif
private:
+ inline SharedPtr _network(uint64_t nwid) const
+ {
+ // assumes _networks_m is locked
+ for(std::vector< std::pair< uint64_t, SharedPtr > >::const_iterator i=_networks.begin();i!=_networks.end();++i) {
+ if (i->first == nwid)
+ return i->second;
+ }
+ return SharedPtr();
+ }
+
RuntimeEnvironment _RR;
RuntimeEnvironment *RR;
@@ -223,7 +233,7 @@ private:
//Dictionary _localConfig; // persisted as local.conf
//Mutex _localConfig_m;
- std::map< uint64_t,SharedPtr > _networks;
+ std::vector< std::pair< uint64_t, SharedPtr > > _networks;
Mutex _networks_m;
Mutex _backgroundTasksLock;
diff --git a/node/Packet.cpp b/node/Packet.cpp
index a81873ffd..f75d1df08 100644
--- a/node/Packet.cpp
+++ b/node/Packet.cpp
@@ -51,6 +51,7 @@ const char *Packet::verbString(Verb v)
case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER";
case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME";
case VERB_SET_EPHEMERAL_KEY: return "SET_EPHEMERAL_KEY";
+ case VERB_CMA: return "CMA";
}
return "(unknown)";
}
diff --git a/node/Packet.hpp b/node/Packet.hpp
index 2dfb75e4b..49201b712 100644
--- a/node/Packet.hpp
+++ b/node/Packet.hpp
@@ -513,8 +513,8 @@ public:
* Destination address types and formats (not all of these are used now):
* 0 - None -- no destination address data present
* 1 - Ethernet address -- format: <[6] Ethernet MAC>
- * 4 - 6-byte IPv4 address -- format: <[4] IP>, <[2] port>
- * 6 - 18-byte IPv6 address -- format: <[16] IP>, <[2] port>
+ * 4 - 6-byte IPv4 UDP address/port -- format: <[4] IP>, <[2] port>
+ * 6 - 18-byte IPv6 UDP address/port -- format: <[16] IP>, <[2] port>
*
* OK payload:
* <[8] timestamp (echoed from original HELLO)>
@@ -626,7 +626,7 @@ public:
* [... additional tuples of network/address/adi ...]
*
* LIKEs are sent to peers with whom you have a direct peer to peer
- * connection, and always including supernodes.
+ * connection, and always including root servers.
*
* OK/ERROR are not generated.
*/
@@ -770,6 +770,9 @@ public:
VERB_MULTICAST_FRAME = 14,
/* Ephemeral (PFS) key push:
+ * <[2] flags (unused and reserved, must be 0)>
+ * <[2] length of padding / extra field section>
+ * <[...] padding / extra field section>
* <[8] 64-bit PFS key set ID sender holds for recipient (0==none)>
* <[8] 64-bit PFS key set ID of this key set>
* [... begin PFS key record ...]
@@ -791,6 +794,12 @@ public:
* the first record with common symmetric cipher, public key type,
* and relevant flags must be used.
*
+ * The padding section may be filled with an arbitrary amount of random
+ * or empty payload. This may be used as a countermeasure to prevent PFS
+ * key pushes from being recognized by packet size vs. other packets in
+ * the stream. This also provides potential space for additional fields
+ * that might be indicated in the future by flags.
+ *
* Flags (all unspecified flags must be zero):
* 0x01 - FIPS mode, only use record if FIPS compliant crypto in use
*
@@ -814,7 +823,24 @@ public:
* <[8] PFS key set ID of received key set>
* <[1] index in record list of chosen key record>
*/
- VERB_SET_EPHEMERAL_KEY = 15
+ VERB_SET_EPHEMERAL_KEY = 15,
+
+ /* "Call me at" -- push of potential endpoints for direct communication:
+ * <[1] flags>
+ * <[2] number of addresses>
+ * <[...] address types and addresses>
+ *
+ * Address types and addresses are of the same format as the destination
+ * address type and address in HELLO.
+ *
+ * The receiver may, upon receiving a CMA push, attempt to establish a
+ * direct link to one or more of the indicated addresses. Senders should
+ * only send CMA pushes to peers that they have some relationship
+ * with such as a shared network membership or a mutual trust.
+ *
+ * OK/ERROR are not generated.
+ */
+ VERB_CMA = 16
};
/**
diff --git a/node/Peer.cpp b/node/Peer.cpp
index d788d0063..96caa72cf 100644
--- a/node/Peer.cpp
+++ b/node/Peer.cpp
@@ -122,16 +122,16 @@ void Peer::received(
/* Announce multicast groups of interest to direct peers if they are
* considered authorized members of a given network. Also announce to
- * supernodes and network controllers. */
+ * root servers and network controllers. */
if ((pathIsConfirmed)&&((now - _lastAnnouncedTo) >= ((ZT_MULTICAST_LIKE_EXPIRE / 2) - 1000))) {
_lastAnnouncedTo = now;
- const bool isSupernode = RR->topology->isSupernode(_id.address());
+ const bool isRoot = RR->topology->isRoot(_id);
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_MULTICAST_LIKE);
const std::vector< SharedPtr > networks(RR->node->allNetworks());
for(std::vector< SharedPtr >::const_iterator n(networks.begin());n!=networks.end();++n) {
- if ( (isSupernode) || ((*n)->isAllowed(_id.address())) ) {
+ if ( (isRoot) || ((*n)->isAllowed(_id.address())) ) {
const std::vector mgs((*n)->allMulticastGroups());
for(std::vector::const_iterator mg(mgs.begin());mg!=mgs.end();++mg) {
if ((outp.size() + 18) > ZT_UDP_DEFAULT_PAYLOAD_MTU) {
diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp
index d7c0e5cc4..9f7c41d7d 100644
--- a/node/SelfAwareness.cpp
+++ b/node/SelfAwareness.cpp
@@ -118,7 +118,7 @@ void SelfAwareness::iam(const Address &reporter,const InetAddress &reporterPhysi
// For all peers for whom we forgot an address, send a packet indirectly if
// they are still considered alive so that we will re-establish direct links.
- SharedPtr sn(RR->topology->getBestSupernode());
+ SharedPtr sn(RR->topology->getBestRoot());
if (sn) {
Path *snp = sn->getBestPath(now);
if (snp) {
diff --git a/node/Switch.cpp b/node/Switch.cpp
index 0aa0b664b..236c1e660 100644
--- a/node/Switch.cpp
+++ b/node/Switch.cpp
@@ -145,12 +145,6 @@ void Switch::onLocalEthernet(const SharedPtr &network,const MAC &from,c
if (fromBridged)
network->learnBridgedMulticastGroup(mg,RR->node->now());
- // Check multicast/broadcast bandwidth quotas and reject if quota exceeded
- if (!network->updateAndCheckMulticastBalance(mg,len)) {
- TRACE("%.16llx: didn't multicast %u bytes, quota exceeded for multicast group %s",network->id(),len,mg.toString().c_str());
- return;
- }
-
//TRACE("%.16llx: MULTICAST %s -> %s %s %u",network->id(),from.toString().c_str(),mg.toString().c_str(),etherTypeName(etherType),len);
RR->mc->send(
@@ -320,8 +314,8 @@ bool Switch::unite(const Address &p1,const Address &p2,bool force)
* P2 in randomized order in terms of which gets sent first. This is done
* since in a few cases NAT-t can be sensitive to slight timing differences
* in terms of when the two peers initiate. Normally this is accounted for
- * by the nearly-simultaneous RENDEZVOUS kickoff from the supernode, but
- * given that supernodes are hosted on cloud providers this can in some
+ * by the nearly-simultaneous RENDEZVOUS kickoff from the relay, but
+ * given that relay are hosted on cloud providers this can in some
* cases have a few ms of latency between packet departures. By randomizing
* the order we make each attempted NAT-t favor one or the other going
* first, meaning if it doesn't succeed the first time it might the second
@@ -565,8 +559,8 @@ void Switch::_handleRemotePacketFragment(const InetAddress &fromAddr,const void
// It wouldn't hurt anything, just redundant and unnecessary.
SharedPtr relayTo = RR->topology->getPeer(destination);
if ((!relayTo)||(!relayTo->send(RR,fragment.data(),fragment.size(),RR->node->now()))) {
- // Don't know peer or no direct path -- so relay via supernode
- relayTo = RR->topology->getBestSupernode();
+ // Don't know peer or no direct path -- so relay via root server
+ relayTo = RR->topology->getBestRoot();
if (relayTo)
relayTo->send(RR,fragment.data(),fragment.size(),RR->node->now());
}
@@ -641,8 +635,8 @@ void Switch::_handleRemotePacketHead(const InetAddress &fromAddr,const void *dat
if ((relayTo)&&((relayTo->send(RR,packet->data(),packet->size(),RR->node->now())))) {
unite(source,destination,false);
} else {
- // Don't know peer or no direct path -- so relay via supernode
- relayTo = RR->topology->getBestSupernode(&source,1,true);
+ // Don't know peer or no direct path -- so relay via root server
+ relayTo = RR->topology->getBestRoot(&source,1,true);
if (relayTo)
relayTo->send(RR,packet->data(),packet->size(),RR->node->now());
}
@@ -712,13 +706,13 @@ void Switch::_handleBeacon(const InetAddress &fromAddr,const Buffer supernode(RR->topology->getBestSupernode(peersAlreadyConsulted,numPeersAlreadyConsulted,false));
- if (supernode) {
- Packet outp(supernode->address(),RR->identity.address(),Packet::VERB_WHOIS);
+ SharedPtr root(RR->topology->getBestRoot(peersAlreadyConsulted,numPeersAlreadyConsulted,false));
+ if (root) {
+ Packet outp(root->address(),RR->identity.address(),Packet::VERB_WHOIS);
addr.appendTo(outp);
- outp.armor(supernode->key(),true);
- if (supernode->send(RR,outp.data(),outp.size(),RR->node->now()))
- return supernode->address();
+ outp.armor(root->key(),true);
+ if (root->send(RR,outp.data(),outp.size(),RR->node->now()))
+ return root->address();
}
return Address();
}
@@ -752,7 +746,7 @@ bool Switch::_trySend(const Packet &packet,bool encrypt,uint64_t nwid)
}
if (!relay)
- relay = RR->topology->getBestSupernode();
+ relay = RR->topology->getBestRoot();
if (!(relay)||(!(viaPath = relay->getBestPath(now))))
return false;
diff --git a/node/Topology.cpp b/node/Topology.cpp
index 5fcc2e612..2b1cc31fe 100644
--- a/node/Topology.cpp
+++ b/node/Topology.cpp
@@ -36,7 +36,7 @@ namespace ZeroTier {
Topology::Topology(const RuntimeEnvironment *renv) :
RR(renv),
- _amSupernode(false)
+ _amRoot(false)
{
}
@@ -44,16 +44,16 @@ Topology::~Topology()
{
}
-void Topology::setSupernodes(const std::map< Identity,std::vector > &sn)
+void Topology::setRootServers(const std::map< Identity,std::vector > &sn)
{
Mutex::Lock _l(_lock);
- if (_supernodes == sn)
+ if (_roots == sn)
return; // no change
- _supernodes = sn;
- _supernodeAddresses.clear();
- _supernodePeers.clear();
+ _roots = sn;
+ _rootAddresses.clear();
+ _rootPeers.clear();
const uint64_t now = RR->node->now();
for(std::map< Identity,std::vector >::const_iterator i(sn.begin());i!=sn.end();++i) {
@@ -64,17 +64,17 @@ void Topology::setSupernodes(const std::map< Identity,std::vector >
for(std::vector::const_iterator j(i->second.begin());j!=i->second.end();++j)
p->addPath(Path(*j,true));
p->use(now);
- _supernodePeers.push_back(p);
+ _rootPeers.push_back(p);
}
- _supernodeAddresses.push_back(i->first.address());
+ _rootAddresses.push_back(i->first.address());
}
- std::sort(_supernodeAddresses.begin(),_supernodeAddresses.end());
+ std::sort(_rootAddresses.begin(),_rootAddresses.end());
- _amSupernode = (_supernodes.find(RR->identity) != _supernodes.end());
+ _amRoot = (_roots.find(RR->identity) != _roots.end());
}
-void Topology::setSupernodes(const Dictionary &sn)
+void Topology::setRootServers(const Dictionary &sn)
{
std::map< Identity,std::vector > m;
for(Dictionary::const_iterator d(sn.begin());d!=sn.end();++d) {
@@ -86,11 +86,11 @@ void Topology::setSupernodes(const Dictionary &sn)
if (udp.length() > 0)
a.push_back(InetAddress(udp));
} catch ( ... ) {
- TRACE("supernode list contained invalid entry for: %s",d->first.c_str());
+ TRACE("root server list contained invalid entry for: %s",d->first.c_str());
}
}
}
- this->setSupernodes(m);
+ this->setRootServers(m);
}
SharedPtr Topology::addPeer(const SharedPtr &peer)
@@ -141,28 +141,28 @@ SharedPtr Topology::getPeer(const Address &zta)
return SharedPtr();
}
-SharedPtr Topology::getBestSupernode(const Address *avoid,unsigned int avoidCount,bool strictAvoid)
+SharedPtr Topology::getBestRoot(const Address *avoid,unsigned int avoidCount,bool strictAvoid)
{
- SharedPtr bestSupernode;
+ SharedPtr bestRoot;
const uint64_t now = RR->node->now();
Mutex::Lock _l(_lock);
- if (_amSupernode) {
- /* If I am a supernode, the "best" supernode is the one whose address
+ if (_amRoot) {
+ /* If I am a root server, the "best" root server is the one whose address
* is numerically greater than mine (with wrap at top of list). This
* causes packets searching for a route to pretty much literally
* circumnavigate the globe rather than bouncing between just two. */
- if (_supernodeAddresses.size() > 1) { // gotta be one other than me for this to work
- std::vector::const_iterator sna(std::find(_supernodeAddresses.begin(),_supernodeAddresses.end(),RR->identity.address()));
- if (sna != _supernodeAddresses.end()) { // sanity check -- _amSupernode should've been false in this case
+ if (_rootAddresses.size() > 1) { // gotta be one other than me for this to work
+ std::vector::const_iterator sna(std::find(_rootAddresses.begin(),_rootAddresses.end(),RR->identity.address()));
+ if (sna != _rootAddresses.end()) { // sanity check -- _amRoot should've been false in this case
for(;;) {
- if (++sna == _supernodeAddresses.end())
- sna = _supernodeAddresses.begin(); // wrap around at end
+ if (++sna == _rootAddresses.end())
+ sna = _rootAddresses.begin(); // wrap around at end
if (*sna != RR->identity.address()) { // pick one other than us -- starting from me+1 in sorted set order
std::map< Address,SharedPtr >::const_iterator p(_activePeers.find(*sna));
if ((p != _activePeers.end())&&(p->second->hasActiveDirectPath(now))) {
- bestSupernode = p->second;
+ bestRoot = p->second;
break;
}
}
@@ -170,80 +170,87 @@ SharedPtr Topology::getBestSupernode(const Address *avoid,unsigned int avo
}
}
} else {
- /* If I am not a supernode, the best supernode is the active one with
+ /* If I am not a root server, the best root server is the active one with
* the lowest latency. */
- unsigned int l,bestSupernodeLatency = 65536;
+ unsigned int l,bestLatency = 65536;
uint64_t lds,ldr;
- // First look for a best supernode by comparing latencies, but exclude
- // supernodes that have not responded to direct messages in order to
+ // First look for a best root by comparing latencies, but exclude
+ // root servers that have not responded to direct messages in order to
// try to exclude any that are dead or unreachable.
- for(std::vector< SharedPtr >::const_iterator sn(_supernodePeers.begin());sn!=_supernodePeers.end();) {
+ for(std::vector< SharedPtr >::const_iterator sn(_rootPeers.begin());sn!=_rootPeers.end();) {
// Skip explicitly avoided relays
for(unsigned int i=0;iaddress())
- goto keep_searching_for_supernodes;
+ goto keep_searching_for_roots;
}
// Skip possibly comatose or unreachable relays
lds = (*sn)->lastDirectSend();
ldr = (*sn)->lastDirectReceive();
if ((lds)&&(lds > ldr)&&((lds - ldr) > ZT_PEER_RELAY_CONVERSATION_LATENCY_THRESHOLD))
- goto keep_searching_for_supernodes;
+ goto keep_searching_for_roots;
if ((*sn)->hasActiveDirectPath(now)) {
l = (*sn)->latency();
- if (bestSupernode) {
- if ((l)&&(l < bestSupernodeLatency)) {
- bestSupernodeLatency = l;
- bestSupernode = *sn;
+ if (bestRoot) {
+ if ((l)&&(l < bestLatency)) {
+ bestLatency = l;
+ bestRoot = *sn;
}
} else {
if (l)
- bestSupernodeLatency = l;
- bestSupernode = *sn;
+ bestLatency = l;
+ bestRoot = *sn;
}
}
-keep_searching_for_supernodes:
+keep_searching_for_roots:
++sn;
}
- if (bestSupernode) {
- bestSupernode->use(now);
- return bestSupernode;
+ if (bestRoot) {
+ bestRoot->use(now);
+ return bestRoot;
} else if (strictAvoid)
return SharedPtr();
// If we have nothing from above, just pick one without avoidance criteria.
- for(std::vector< SharedPtr >::const_iterator sn=_supernodePeers.begin();sn!=_supernodePeers.end();++sn) {
+ for(std::vector< SharedPtr >::const_iterator sn=_rootPeers.begin();sn!=_rootPeers.end();++sn) {
if ((*sn)->hasActiveDirectPath(now)) {
unsigned int l = (*sn)->latency();
- if (bestSupernode) {
- if ((l)&&(l < bestSupernodeLatency)) {
- bestSupernodeLatency = l;
- bestSupernode = *sn;
+ if (bestRoot) {
+ if ((l)&&(l < bestLatency)) {
+ bestLatency = l;
+ bestRoot = *sn;
}
} else {
if (l)
- bestSupernodeLatency = l;
- bestSupernode = *sn;
+ bestLatency = l;
+ bestRoot = *sn;
}
}
}
}
- if (bestSupernode)
- bestSupernode->use(now);
- return bestSupernode;
+ if (bestRoot)
+ bestRoot->use(now);
+ return bestRoot;
+}
+
+bool Topology::isRoot(const Identity &id) const
+ throw()
+{
+ Mutex::Lock _l(_lock);
+ return (_roots.count(id) != 0);
}
void Topology::clean(uint64_t now)
{
Mutex::Lock _l(_lock);
for(std::map< Address,SharedPtr >::iterator p(_activePeers.begin());p!=_activePeers.end();) {
- if (((now - p->second->lastUsed()) >= ZT_PEER_IN_MEMORY_EXPIRATION)&&(std::find(_supernodeAddresses.begin(),_supernodeAddresses.end(),p->first) == _supernodeAddresses.end())) {
+ if (((now - p->second->lastUsed()) >= ZT_PEER_IN_MEMORY_EXPIRATION)&&(std::find(_rootAddresses.begin(),_rootAddresses.end(),p->first) == _rootAddresses.end())) {
_activePeers.erase(p++);
} else ++p;
}
diff --git a/node/Topology.hpp b/node/Topology.hpp
index 56a9709fc..c878bcc6e 100644
--- a/node/Topology.hpp
+++ b/node/Topology.hpp
@@ -59,21 +59,19 @@ public:
~Topology();
/**
- * Set up supernodes for this network
- *
- * @param sn Supernodes for this network
+ * @param sn Root server identities and addresses
*/
- void setSupernodes(const std::map< Identity,std::vector > &sn);
+ void setRootServers(const std::map< Identity,std::vector > &sn);
/**
- * Set up supernodes for this network
+ * Set up root servers for this network
*
* This performs no signature verification of any kind. The caller must
* check the signature of the root topology dictionary first.
*
- * @param sn Supernodes dictionary from root-topology
+ * @param sn 'rootservers' key from root-topology Dictionary (deserialized as Dictionary)
*/
- void setSupernodes(const Dictionary &sn);
+ void setRootServers(const Dictionary &sn);
/**
* Add a peer to database
@@ -95,65 +93,52 @@ public:
SharedPtr getPeer(const Address &zta);
/**
- * @return Vector of peers that are supernodes
+ * @return Vector of peers that are root servers
*/
- inline std::vector< SharedPtr > supernodePeers() const
+ inline std::vector< SharedPtr > rootPeers() const
{
Mutex::Lock _l(_lock);
- return _supernodePeers;
+ return _rootPeers;
}
/**
- * @return Number of supernodes
- */
- inline unsigned int numSupernodes() const
- {
- Mutex::Lock _l(_lock);
- return (unsigned int)_supernodePeers.size();
- }
-
- /**
- * Get the current favorite supernode
+ * Get the current favorite root server
*
- * @return Supernode with lowest latency or NULL if none
+ * @return Root server with lowest latency or NULL if none
*/
- inline SharedPtr getBestSupernode()
+ inline SharedPtr getBestRoot()
{
- return getBestSupernode((const Address *)0,0,false);
+ return getBestRoot((const Address *)0,0,false);
}
/**
- * Get the best supernode, avoiding supernodes listed in an array
+ * Get the best root server, avoiding root servers listed in an array
*
- * This will get the best supernode (lowest latency, etc.) but will
- * try to avoid the listed supernodes, only using them if no others
+ * This will get the best root server (lowest latency, etc.) but will
+ * try to avoid the listed root servers, only using them if no others
* are available.
*
* @param avoid Nodes to avoid
* @param avoidCount Number of nodes to avoid
- * @param strictAvoid If false, consider avoided supernodes anyway if no non-avoid supernodes are available
- * @return Supernode or NULL if none
+ * @param strictAvoid If false, consider avoided root servers anyway if no non-avoid root servers are available
+ * @return Root server or NULL if none available
*/
- SharedPtr getBestSupernode(const Address *avoid,unsigned int avoidCount,bool strictAvoid);
+ SharedPtr getBestRoot(const Address *avoid,unsigned int avoidCount,bool strictAvoid);
/**
- * @param zta ZeroTier address
- * @return True if this is a designated supernode
+ * @param id Identity to check
+ * @return True if this is a designated root server
*/
- inline bool isSupernode(const Address &zta) const
- throw()
- {
- Mutex::Lock _l(_lock);
- return (std::find(_supernodeAddresses.begin(),_supernodeAddresses.end(),zta) != _supernodeAddresses.end());
- }
+ bool isRoot(const Identity &id) const
+ throw();
/**
- * @return Vector of supernode addresses
+ * @return Vector of root server addresses
*/
- inline std::vector supernodeAddresses() const
+ inline std::vector rootAddresses() const
{
Mutex::Lock _l(_lock);
- return _supernodeAddresses;
+ return _rootAddresses;
}
/**
@@ -206,13 +191,13 @@ private:
const RuntimeEnvironment *RR;
std::map< Address,SharedPtr > _activePeers;
- std::map< Identity,std::vector > _supernodes;
- std::vector< Address > _supernodeAddresses;
- std::vector< SharedPtr > _supernodePeers;
+ std::map< Identity,std::vector > _roots;
+ std::vector< Address > _rootAddresses;
+ std::vector< SharedPtr > _rootPeers;
Mutex _lock;
- bool _amSupernode;
+ bool _amRoot;
};
} // namespace ZeroTier
diff --git a/osdep/Phy.hpp b/osdep/Phy.hpp
index 23fd2ee24..ec01625ba 100644
--- a/osdep/Phy.hpp
+++ b/osdep/Phy.hpp
@@ -123,12 +123,13 @@ private:
enum PhySocketType
{
- ZT_PHY_SOCKET_TCP_OUT_PENDING = 0x00,
- ZT_PHY_SOCKET_TCP_OUT_CONNECTED = 0x01,
- ZT_PHY_SOCKET_TCP_IN = 0x02,
- ZT_PHY_SOCKET_TCP_LISTEN = 0x03,
- ZT_PHY_SOCKET_RAW = 0x04,
- ZT_PHY_SOCKET_UDP = 0x05
+ ZT_PHY_SOCKET_CLOSED = 0x00, // socket is closed, will be removed on next poll()
+ ZT_PHY_SOCKET_TCP_OUT_PENDING = 0x01,
+ ZT_PHY_SOCKET_TCP_OUT_CONNECTED = 0x02,
+ ZT_PHY_SOCKET_TCP_IN = 0x03,
+ ZT_PHY_SOCKET_TCP_LISTEN = 0x04,
+ ZT_PHY_SOCKET_RAW = 0x05,
+ ZT_PHY_SOCKET_UDP = 0x06
};
struct PhySocketImpl
@@ -205,8 +206,10 @@ public:
~Phy()
{
- while (!_socks.empty())
- this->close((PhySocket *)&(_socks.front()),true);
+ for(typename std::list::const_iterator s(_socks.begin());s!=_socks.end();++s) {
+ if (s->type != ZT_PHY_SOCKET_CLOSED)
+ this->close((PhySocket *)&(*s),true);
+ }
ZT_PHY_CLOSE_SOCKET(_whackReceiveSocket);
ZT_PHY_CLOSE_SOCKET(_whackSendSocket);
}
@@ -620,11 +623,7 @@ public:
#endif
}
- bool atEnd = false;
- for(typename std::list::iterator s(_socks.begin()),nexts;(!atEnd);s=nexts) {
- nexts = s; ++nexts; // we can delete the linked list item, so traverse now
- atEnd = (nexts == _socks.end()); // if we delete the last element, s!=_socks.end() will no longer terminate our loop
-
+ for(typename std::list::iterator s(_socks.begin());s!=_socks.end();) {
switch (s->type) {
case ZT_PHY_SOCKET_TCP_OUT_PENDING:
@@ -724,6 +723,10 @@ public:
break;
}
+
+ if (s->type == ZT_PHY_SOCKET_CLOSED)
+ _socks.erase(s++);
+ else ++s;
}
}
@@ -736,6 +739,8 @@ public:
if (!sock)
return;
PhySocketImpl &sws = *(reinterpret_cast(sock));
+ if (sws.type == ZT_PHY_SOCKET_CLOSED)
+ return;
FD_CLR(sws.sock,&_readfds);
FD_CLR(sws.sock,&_writefds);
@@ -765,21 +770,15 @@ public:
break;
}
- long oldSock = (long)sws.sock;
+ // Causes entry to be deleted from list in poll(), ignored elsewhere
+ sws.type = ZT_PHY_SOCKET_CLOSED;
- for(typename std::list::iterator s(_socks.begin());s!=_socks.end();++s) {
- if (reinterpret_cast(&(*s)) == sock) {
- _socks.erase(s);
- break;
- }
- }
-
- if (oldSock >= _nfds) {
+ if (sws.sock >= _nfds) {
long nfds = (long)_whackSendSocket;
if ((long)_whackReceiveSocket > nfds)
nfds = (long)_whackReceiveSocket;
for(typename std::list::iterator s(_socks.begin());s!=_socks.end();++s) {
- if ((long)s->sock > nfds)
+ if ((s->type != ZT_PHY_SOCKET_CLOSED)&&((long)s->sock > nfds))
nfds = (long)s->sock;
}
_nfds = nfds;
diff --git a/osdep/WindowsEthernetTap.cpp b/osdep/WindowsEthernetTap.cpp
index b373d9e27..d477f2e3d 100644
--- a/osdep/WindowsEthernetTap.cpp
+++ b/osdep/WindowsEthernetTap.cpp
@@ -92,9 +92,6 @@ static const WindowsEthernetTapEnv WINENV;
// Only create or delete devices one at a time
static Mutex _systemTapInitLock;
-// Incrementing this causes everyone currently open to close and reopen
-static volatile int _systemTapResetStatus = 0;
-
} // anonymous namespace
WindowsEthernetTap::WindowsEthernetTap(
@@ -268,12 +265,6 @@ WindowsEthernetTap::WindowsEthernetTap(
}
} else break; // no more keys or error occurred
}
-
- // When we create a new tap device from scratch, existing taps for
- // some reason go into 'unplugged' state. This can be fixed by
- // closing and re-opening them. Incrementing this causes all
- // existing tap threads to do this.
- ++_systemTapResetStatus;
}
if (_netCfgInstanceId.length() > 0) {
@@ -299,7 +290,6 @@ WindowsEthernetTap::WindowsEthernetTap(
throw std::runtime_error("unable to find or create tap adapter");
}
- // Convert device GUID junk... blech... is there an easier way to do this?
{
char nobraces[128];
const char *nbtmp1 = _netCfgInstanceId.c_str();
@@ -573,191 +563,199 @@ void WindowsEthernetTap::scanMulticastGroups(std::vector &added,
void WindowsEthernetTap::threadMain()
throw()
{
- char tapPath[256];
- OVERLAPPED tapOvlRead,tapOvlWrite;
+ char tapReadBuf[ZT_IF_MTU + 32];
+ char tapPath[128];
HANDLE wait4[3];
- char *tapReadBuf = (char *)0;
-
- /* No idea why I did this. I did it a long time ago and there was only a
- * a snarky comment. But I'd never do crap like this without a reason, so
- * I am leaving it alone with a more descriptive snarky comment. */
- while (!tapReadBuf) {
- tapReadBuf = (char *)::malloc(ZT_IF_MTU + 32);
- if (!tapReadBuf)
- Sleep(1000);
- }
+ OVERLAPPED tapOvlRead,tapOvlWrite;
Utils::snprintf(tapPath,sizeof(tapPath),"\\\\.\\Global\\%s.tap",_netCfgInstanceId.c_str());
- int prevTapResetStatus = _systemTapResetStatus;
- bool throwOneAway = true; // Restart once on startup, because Windows.
- bool powerCycle = true; // If true, "power cycle" the device, because Windows.
- while (_run) {
- if (powerCycle) {
- _disableTapDevice();
- Sleep(500);
+
+ try {
+ while (_run) {
_enableTapDevice();
Sleep(500);
- }
- _tap = CreateFileA(tapPath,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM|FILE_FLAG_OVERLAPPED,NULL);
- if (_tap == INVALID_HANDLE_VALUE) {
- fprintf(stderr,"Error opening %s -- retrying.\r\n",tapPath);
- powerCycle = true;
- continue;
- }
-
- {
- uint32_t tmpi = 1;
- DWORD bytesReturned = 0;
- DeviceIoControl(_tap,TAP_WIN_IOCTL_SET_MEDIA_STATUS,&tmpi,sizeof(tmpi),&tmpi,sizeof(tmpi),&bytesReturned,NULL);
- }
-
- {
-#ifdef ZT_WINDOWS_CREATE_FAKE_DEFAULT_ROUTE
- /* This inserts a fake default route and a fake ARP entry, forcing
- * Windows to detect this as a "real" network and apply proper
- * firewall rules.
- *
- * This hack is completely stupid, but Windows made me do it
- * by being broken and insane.
- *
- * Background: Windows tries to detect its network location by
- * matching it to the ARP address of the default route. Networks
- * without default routes are "unidentified networks" and cannot
- * have their firewall classification changed by the user (easily).
- *
- * Yes, you read that right.
- *
- * The common workaround is to set *NdisDeviceType to 1, which
- * totally disables all Windows firewall functionality. This is
- * the answer you'll find on most forums for things like OpenVPN.
- *
- * Yes, you read that right.
- *
- * The default route workaround is also known, but for this to
- * work there must be a known default IP that resolves to a known
- * ARP address. This works for an OpenVPN tunnel, but not here
- * because this isn't a tunnel. It's a mesh. There is no "other
- * end," or any other known always on IP.
- *
- * So let's make a fake one and shove it in there along with its
- * fake static ARP entry. Also makes it instant-on and static.
- *
- * We'll have to see what DHCP does with this. In the future we
- * probably will not want to do this on DHCP-enabled networks, so
- * when we enable DHCP we will go in and yank this wacko hacko from
- * the routing table before doing so.
- *
- * Like Jesse Pinkman would say: "YEEEEAAH BITCH!" */
- const uint32_t fakeIp = htonl(0x19fffffe); // 25.255.255.254 -- unrouted IPv4 block
- for(int i=0;i<8;++i) {
- MIB_IPNET_ROW2 ipnr;
- memset(&ipnr,0,sizeof(ipnr));
- ipnr.Address.si_family = AF_INET;
- ipnr.Address.Ipv4.sin_addr.s_addr = fakeIp;
- ipnr.InterfaceLuid.Value = _deviceLuid.Value;
- ipnr.PhysicalAddress[0] = _mac[0] ^ 0x10; // just make something up that's consistent and not part of this net
- ipnr.PhysicalAddress[1] = 0x00;
- ipnr.PhysicalAddress[2] = (UCHAR)((_deviceGuid.Data1 >> 24) & 0xff);
- ipnr.PhysicalAddress[3] = (UCHAR)((_deviceGuid.Data1 >> 16) & 0xff);
- ipnr.PhysicalAddress[4] = (UCHAR)((_deviceGuid.Data1 >> 8) & 0xff);
- ipnr.PhysicalAddress[5] = (UCHAR)(_deviceGuid.Data1 & 0xff);
- ipnr.PhysicalAddressLength = 6;
- ipnr.State = NlnsPermanent;
- ipnr.IsRouter = 1;
- ipnr.IsUnreachable = 0;
- ipnr.ReachabilityTime.LastReachable = 0x0fffffff;
- ipnr.ReachabilityTime.LastUnreachable = 1;
- DWORD result = CreateIpNetEntry2(&ipnr);
- if (result != NO_ERROR)
- Sleep(500);
- else break;
+ _tap = CreateFileA(tapPath,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_SYSTEM|FILE_FLAG_OVERLAPPED,NULL);
+ if (_tap == INVALID_HANDLE_VALUE) {
+ _disableTapDevice();
+ _enableTapDevice();
+ Sleep(1000);
+ continue;
}
- for(int i=0;i<8;++i) {
- MIB_IPFORWARD_ROW2 nr;
- memset(&nr,0,sizeof(nr));
- InitializeIpForwardEntry(&nr);
- nr.InterfaceLuid.Value = _deviceLuid.Value;
- nr.DestinationPrefix.Prefix.si_family = AF_INET; // rest is left as 0.0.0.0/0
- nr.NextHop.si_family = AF_INET;
- nr.NextHop.Ipv4.sin_addr.s_addr = fakeIp;
- nr.Metric = 9999; // do not use as real default route
- nr.Protocol = MIB_IPPROTO_NETMGMT;
- DWORD result = CreateIpForwardEntry2(&nr);
- if (result != NO_ERROR)
- Sleep(500);
- else break;
+
+ {
+ uint32_t tmpi = 1;
+ DWORD bytesReturned = 0;
+ DeviceIoControl(_tap,TAP_WIN_IOCTL_SET_MEDIA_STATUS,&tmpi,sizeof(tmpi),&tmpi,sizeof(tmpi),&bytesReturned,NULL);
+ }
+
+#ifdef ZT_WINDOWS_CREATE_FAKE_DEFAULT_ROUTE
+ {
+ /* This inserts a fake default route and a fake ARP entry, forcing
+ * Windows to detect this as a "real" network and apply proper
+ * firewall rules.
+ *
+ * This hack is completely stupid, but Windows made me do it
+ * by being broken and insane.
+ *
+ * Background: Windows tries to detect its network location by
+ * matching it to the ARP address of the default route. Networks
+ * without default routes are "unidentified networks" and cannot
+ * have their firewall classification changed by the user (easily).
+ *
+ * Yes, you read that right.
+ *
+ * The common workaround is to set *NdisDeviceType to 1, which
+ * totally disables all Windows firewall functionality. This is
+ * the answer you'll find on most forums for things like OpenVPN.
+ *
+ * Yes, you read that right.
+ *
+ * The default route workaround is also known, but for this to
+ * work there must be a known default IP that resolves to a known
+ * ARP address. This works for an OpenVPN tunnel, but not here
+ * because this isn't a tunnel. It's a mesh. There is no "other
+ * end," or any other known always on IP.
+ *
+ * So let's make a fake one and shove it in there along with its
+ * fake static ARP entry. Also makes it instant-on and static.
+ *
+ * We'll have to see what DHCP does with this. In the future we
+ * probably will not want to do this on DHCP-enabled networks, so
+ * when we enable DHCP we will go in and yank this wacko hacko from
+ * the routing table before doing so.
+ *
+ * Like Jesse Pinkman would say: "YEEEEAAH BITCH!" */
+ const uint32_t fakeIp = htonl(0x19fffffe); // 25.255.255.254 -- unrouted IPv4 block
+ for(int i=0;i<8;++i) {
+ MIB_IPNET_ROW2 ipnr;
+ memset(&ipnr,0,sizeof(ipnr));
+ ipnr.Address.si_family = AF_INET;
+ ipnr.Address.Ipv4.sin_addr.s_addr = fakeIp;
+ ipnr.InterfaceLuid.Value = _deviceLuid.Value;
+ ipnr.PhysicalAddress[0] = _mac[0] ^ 0x10; // just make something up that's consistent and not part of this net
+ ipnr.PhysicalAddress[1] = 0x00;
+ ipnr.PhysicalAddress[2] = (UCHAR)((_deviceGuid.Data1 >> 24) & 0xff);
+ ipnr.PhysicalAddress[3] = (UCHAR)((_deviceGuid.Data1 >> 16) & 0xff);
+ ipnr.PhysicalAddress[4] = (UCHAR)((_deviceGuid.Data1 >> 8) & 0xff);
+ ipnr.PhysicalAddress[5] = (UCHAR)(_deviceGuid.Data1 & 0xff);
+ ipnr.PhysicalAddressLength = 6;
+ ipnr.State = NlnsPermanent;
+ ipnr.IsRouter = 1;
+ ipnr.IsUnreachable = 0;
+ ipnr.ReachabilityTime.LastReachable = 0x0fffffff;
+ ipnr.ReachabilityTime.LastUnreachable = 1;
+ DWORD result = CreateIpNetEntry2(&ipnr);
+ if (result != NO_ERROR)
+ Sleep(500);
+ else break;
+ }
+ for(int i=0;i<8;++i) {
+ MIB_IPFORWARD_ROW2 nr;
+ memset(&nr,0,sizeof(nr));
+ InitializeIpForwardEntry(&nr);
+ nr.InterfaceLuid.Value = _deviceLuid.Value;
+ nr.DestinationPrefix.Prefix.si_family = AF_INET; // rest is left as 0.0.0.0/0
+ nr.NextHop.si_family = AF_INET;
+ nr.NextHop.Ipv4.sin_addr.s_addr = fakeIp;
+ nr.Metric = 9999; // do not use as real default route
+ nr.Protocol = MIB_IPPROTO_NETMGMT;
+ DWORD result = CreateIpForwardEntry2(&nr);
+ if (result != NO_ERROR)
+ Sleep(500);
+ else break;
+ }
}
#endif
- }
- memset(&tapOvlRead,0,sizeof(tapOvlRead));
- tapOvlRead.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
- memset(&tapOvlWrite,0,sizeof(tapOvlWrite));
- tapOvlWrite.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
+ memset(&tapOvlRead,0,sizeof(tapOvlRead));
+ tapOvlRead.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
+ memset(&tapOvlWrite,0,sizeof(tapOvlWrite));
+ tapOvlWrite.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
- wait4[0] = _injectSemaphore;
- wait4[1] = tapOvlRead.hEvent;
- wait4[2] = tapOvlWrite.hEvent; // only included if writeInProgress is true
+ wait4[0] = _injectSemaphore;
+ wait4[1] = tapOvlRead.hEvent;
+ wait4[2] = tapOvlWrite.hEvent; // only included if writeInProgress is true
- ReadFile(_tap,tapReadBuf,sizeof(tapReadBuf),NULL,&tapOvlRead);
- bool writeInProgress = false;
- while (_run) {
- if ((prevTapResetStatus != _systemTapResetStatus)||(throwOneAway)) {
- powerCycle = throwOneAway;
- throwOneAway = false;
- prevTapResetStatus = _systemTapResetStatus;
- break; // this will cause us to close and reopen the tap
- }
- DWORD r = WaitForMultipleObjectsEx(writeInProgress ? 3 : 2,wait4,FALSE,2500,TRUE);
- if (!_run) break; // will also break outer while(_run)
+ ReadFile(_tap,tapReadBuf,sizeof(tapReadBuf),NULL,&tapOvlRead);
+ bool writeInProgress = false;
+ ULONGLONG timeOfLastBorkCheck = GetTickCount64();
+ while (_run) {
+ DWORD waitResult = WaitForMultipleObjectsEx(writeInProgress ? 3 : 2,wait4,FALSE,2500,TRUE);
+ if (!_run) break; // will also break outer while(_run)
- if ((r == WAIT_TIMEOUT)||(r == WAIT_FAILED))
- continue;
-
- if (HasOverlappedIoCompleted(&tapOvlRead)) {
- DWORD bytesRead = 0;
- if (GetOverlappedResult(_tap,&tapOvlRead,&bytesRead,FALSE)) {
- if ((bytesRead > 14)&&(_enabled)) {
- MAC to(tapReadBuf,6);
- MAC from(tapReadBuf + 6,6);
- unsigned int etherType = ((((unsigned int)tapReadBuf[12]) & 0xff) << 8) | (((unsigned int)tapReadBuf[13]) & 0xff);
- try {
- // TODO: decode vlans
- _handler(_arg,_nwid,from,to,etherType,0,tapReadBuf + 14,bytesRead - 14);
- } catch ( ... ) {} // handlers should not throw
+ // Check for issues with adapter and close/reopen if any are detected. This
+ // check fixes a while boatload of Windows adapter 'coma' issues after
+ // sleep/wake and when adapters are added/removed. Basically if the tap
+ // device is borked, whack it.
+ {
+ ULONGLONG tc = GetTickCount64();
+ if ((tc - timeOfLastBorkCheck) >= 2500) {
+ timeOfLastBorkCheck = tc;
+ MIB_IF_TABLE2 *ift = NULL;
+ if ((GetIfTable2(&ift) == NO_ERROR)&&(ift)) {
+ bool isBorked = false;
+ for(ULONG r=0;rNumEntries;++r) {
+ if (ift->Table[r].InterfaceLuid.Value == _deviceLuid.Value) {
+ if ((ift->Table[r].InterfaceAndOperStatusFlags.NotMediaConnected)||(ift->Table[r].MediaConnectState == MediaConnectStateDisconnected))
+ isBorked = true;
+ break;
+ }
+ }
+ FreeMibTable(ift);
+ if (isBorked) {
+ // Close and reopen tap device if there's an issue (outer loop)
+ break;
+ }
+ }
}
}
- ReadFile(_tap,tapReadBuf,ZT_IF_MTU + 32,NULL,&tapOvlRead);
+
+ if ((waitResult == WAIT_TIMEOUT)||(waitResult == WAIT_FAILED))
+ continue;
+
+ if (HasOverlappedIoCompleted(&tapOvlRead)) {
+ DWORD bytesRead = 0;
+ if (GetOverlappedResult(_tap,&tapOvlRead,&bytesRead,FALSE)) {
+ if ((bytesRead > 14)&&(_enabled)) {
+ MAC to(tapReadBuf,6);
+ MAC from(tapReadBuf + 6,6);
+ unsigned int etherType = ((((unsigned int)tapReadBuf[12]) & 0xff) << 8) | (((unsigned int)tapReadBuf[13]) & 0xff);
+ try {
+ // TODO: decode vlans
+ _handler(_arg,_nwid,from,to,etherType,0,tapReadBuf + 14,bytesRead - 14);
+ } catch ( ... ) {} // handlers should not throw
+ }
+ }
+ ReadFile(_tap,tapReadBuf,ZT_IF_MTU + 32,NULL,&tapOvlRead);
+ }
+
+ if (writeInProgress) {
+ if (HasOverlappedIoCompleted(&tapOvlWrite)) {
+ writeInProgress = false;
+ _injectPending_m.lock();
+ _injectPending.pop();
+ } else continue; // still writing, so skip code below and wait
+ } else _injectPending_m.lock();
+
+ if (!_injectPending.empty()) {
+ WriteFile(_tap,_injectPending.front().first.data,_injectPending.front().second,NULL,&tapOvlWrite);
+ writeInProgress = true;
+ }
+
+ _injectPending_m.unlock();
}
- if (writeInProgress) {
- if (HasOverlappedIoCompleted(&tapOvlWrite)) {
- writeInProgress = false;
- _injectPending_m.lock();
- _injectPending.pop();
- } else continue; // still writing, so skip code below and wait
- } else _injectPending_m.lock();
+ CancelIo(_tap);
- if (!_injectPending.empty()) {
- WriteFile(_tap,_injectPending.front().first.data,_injectPending.front().second,NULL,&tapOvlWrite);
- writeInProgress = true;
- }
+ CloseHandle(tapOvlRead.hEvent);
+ CloseHandle(tapOvlWrite.hEvent);
+ CloseHandle(_tap);
+ _tap = INVALID_HANDLE_VALUE;
- _injectPending_m.unlock();
+ // We will restart and re-open the tap unless _run == false
}
-
- CancelIo(_tap);
-
- CloseHandle(tapOvlRead.hEvent);
- CloseHandle(tapOvlWrite.hEvent);
- CloseHandle(_tap);
- _tap = INVALID_HANDLE_VALUE;
-
- // We will restart and re-open the tap unless _run == false
- }
-
- ::free(tapReadBuf);
+ } catch ( ... ) {} // catch unexpected exceptions -- this should not happen but would prevent program crash or other weird issues since threads should not throw
}
void WindowsEthernetTap::destroyAllPersistentTapDevices(const char *pathToHelpers)
diff --git a/osdep/WindowsEthernetTap.hpp b/osdep/WindowsEthernetTap.hpp
index 670467633..944b53f33 100644
--- a/osdep/WindowsEthernetTap.hpp
+++ b/osdep/WindowsEthernetTap.hpp
@@ -98,8 +98,8 @@ private:
GUID _deviceGuid;
NET_LUID _deviceLuid;
- std::string _netCfgInstanceId; // NetCfgInstanceId, a GUID
- std::string _deviceInstanceId; // DeviceInstanceID, another kind of "instance ID"
+ std::string _netCfgInstanceId;
+ std::string _deviceInstanceId;
std::vector _multicastGroups;
diff --git a/root-topology/README.md b/root-topology/README.md
index 2614d3d9d..c9c3a9083 100644
--- a/root-topology/README.md
+++ b/root-topology/README.md
@@ -2,9 +2,9 @@ This folder contains the source files to compile the signed network root topolog
Keys in the root topology dictionary are:
- * **supernodes**: contains another Dictionary mapping supernode address to supernode definition
- * **##########**: supernode address, contains supernode definition
- * **id**: supernode identity (public) in string-serialized format
+ * **rootservers**: contains another Dictionary mapping rootserver address to rootserver definition
+ * **##########**: rootserver address, contains rootserver definition
+ * **id**: rootserver identity (public) in string-serialized format
* **udp**: comma-delimited list of ip/port UDP addresses of node
* **tcp**: *DEPRECATED* comma-delimited list of ip/port TCP addresses of node
* **desc**: human-readable description (optional)
diff --git a/root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.c b/root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.c
index 1de95c717..96835e058 100644
--- a/root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.c
+++ b/root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.c
@@ -1,98 +1,90 @@
static unsigned char ZT_DEFAULT_ROOT_TOPOLOGY[] = {
- 0x73, 0x75, 0x70, 0x65, 0x72, 0x6e, 0x6f, 0x64, 0x65, 0x73, 0x3d, 0x37, 0x65, 0x31, 0x39, 0x38,
- 0x37, 0x36, 0x61, 0x62, 0x61, 0x5c, 0x3d, 0x69, 0x64, 0x5c, 0x5c, 0x5c, 0x3d, 0x37, 0x65, 0x31,
- 0x39, 0x38, 0x37, 0x36, 0x61, 0x62, 0x61, 0x3a, 0x30, 0x3a, 0x32, 0x61, 0x36, 0x65, 0x32, 0x62,
- 0x32, 0x33, 0x31, 0x38, 0x39, 0x33, 0x30, 0x66, 0x36, 0x30, 0x65, 0x62, 0x30, 0x39, 0x37, 0x66,
- 0x37, 0x30, 0x64, 0x30, 0x66, 0x34, 0x62, 0x30, 0x32, 0x38, 0x62, 0x32, 0x63, 0x64, 0x36, 0x64,
- 0x33, 0x64, 0x30, 0x63, 0x36, 0x33, 0x63, 0x30, 0x31, 0x34, 0x62, 0x39, 0x30, 0x33, 0x39, 0x66,
- 0x66, 0x33, 0x35, 0x33, 0x39, 0x30, 0x65, 0x34, 0x31, 0x31, 0x38, 0x31, 0x66, 0x32, 0x31, 0x36,
- 0x66, 0x62, 0x32, 0x65, 0x36, 0x66, 0x61, 0x38, 0x64, 0x39, 0x35, 0x63, 0x31, 0x65, 0x65, 0x39,
- 0x36, 0x36, 0x37, 0x31, 0x35, 0x36, 0x34, 0x31, 0x31, 0x39, 0x30, 0x35, 0x63, 0x33, 0x64, 0x63,
- 0x63, 0x66, 0x65, 0x61, 0x37, 0x38, 0x64, 0x38, 0x63, 0x36, 0x64, 0x66, 0x61, 0x66, 0x62, 0x61,
- 0x36, 0x38, 0x38, 0x31, 0x37, 0x30, 0x62, 0x33, 0x66, 0x61, 0x5c, 0x5c, 0x6e, 0x75, 0x64, 0x70,
- 0x5c, 0x5c, 0x5c, 0x3d, 0x31, 0x39, 0x38, 0x2e, 0x31, 0x39, 0x39, 0x2e, 0x39, 0x37, 0x2e, 0x32,
- 0x32, 0x30, 0x2f, 0x39, 0x39, 0x39, 0x33, 0x5c, 0x5c, 0x6e, 0x74, 0x63, 0x70, 0x5c, 0x5c, 0x5c,
- 0x3d, 0x31, 0x39, 0x38, 0x2e, 0x31, 0x39, 0x39, 0x2e, 0x39, 0x37, 0x2e, 0x32, 0x32, 0x30, 0x2f,
- 0x34, 0x34, 0x33, 0x5c, 0x5c, 0x6e, 0x64, 0x65, 0x73, 0x63, 0x5c, 0x5c, 0x5c, 0x3d, 0x53, 0x61,
- 0x6e, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2c, 0x20, 0x43, 0x61, 0x6c,
- 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x2c, 0x20, 0x55, 0x53, 0x41, 0x5c, 0x5c, 0x6e, 0x64,
- 0x6e, 0x73, 0x5c, 0x5c, 0x5c, 0x3d, 0x6e, 0x79, 0x61, 0x72, 0x6c, 0x61, 0x74, 0x68, 0x6f, 0x74,
- 0x65, 0x70, 0x2e, 0x7a, 0x65, 0x72, 0x6f, 0x74, 0x69, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x5c,
- 0x5c, 0x6e, 0x5c, 0x6e, 0x38, 0x38, 0x34, 0x31, 0x34, 0x30, 0x38, 0x61, 0x32, 0x65, 0x5c, 0x3d,
- 0x69, 0x64, 0x5c, 0x5c, 0x5c, 0x3d, 0x38, 0x38, 0x34, 0x31, 0x34, 0x30, 0x38, 0x61, 0x32, 0x65,
- 0x3a, 0x30, 0x3a, 0x62, 0x62, 0x31, 0x64, 0x33, 0x31, 0x66, 0x32, 0x63, 0x33, 0x32, 0x33, 0x65,
- 0x32, 0x36, 0x34, 0x65, 0x39, 0x65, 0x36, 0x34, 0x31, 0x37, 0x32, 0x63, 0x31, 0x61, 0x37, 0x34,
- 0x66, 0x37, 0x37, 0x38, 0x39, 0x39, 0x35, 0x35, 0x35, 0x65, 0x64, 0x31, 0x30, 0x37, 0x35, 0x31,
- 0x63, 0x64, 0x35, 0x36, 0x65, 0x38, 0x36, 0x34, 0x30, 0x35, 0x63, 0x64, 0x65, 0x31, 0x31, 0x38,
- 0x64, 0x30, 0x32, 0x64, 0x66, 0x66, 0x65, 0x35, 0x35, 0x35, 0x64, 0x34, 0x36, 0x32, 0x63, 0x63,
- 0x66, 0x36, 0x61, 0x38, 0x35, 0x62, 0x35, 0x36, 0x33, 0x31, 0x63, 0x31, 0x32, 0x33, 0x35, 0x30,
- 0x63, 0x38, 0x64, 0x35, 0x64, 0x63, 0x34, 0x30, 0x39, 0x62, 0x61, 0x31, 0x30, 0x62, 0x39, 0x30,
- 0x32, 0x35, 0x64, 0x30, 0x66, 0x34, 0x34, 0x35, 0x63, 0x66, 0x34, 0x34, 0x39, 0x64, 0x39, 0x32,
- 0x62, 0x31, 0x63, 0x5c, 0x5c, 0x6e, 0x75, 0x64, 0x70, 0x5c, 0x5c, 0x5c, 0x3d, 0x31, 0x30, 0x37,
- 0x2e, 0x31, 0x39, 0x31, 0x2e, 0x34, 0x36, 0x2e, 0x32, 0x31, 0x30, 0x2f, 0x39, 0x39, 0x39, 0x33,
- 0x5c, 0x5c, 0x6e, 0x74, 0x63, 0x70, 0x5c, 0x5c, 0x5c, 0x3d, 0x31, 0x30, 0x37, 0x2e, 0x31, 0x39,
- 0x31, 0x2e, 0x34, 0x36, 0x2e, 0x32, 0x31, 0x30, 0x2f, 0x34, 0x34, 0x33, 0x5c, 0x5c, 0x6e, 0x64,
- 0x65, 0x73, 0x63, 0x5c, 0x5c, 0x5c, 0x3d, 0x50, 0x61, 0x72, 0x69, 0x73, 0x2c, 0x20, 0x46, 0x72,
- 0x61, 0x6e, 0x63, 0x65, 0x5c, 0x5c, 0x6e, 0x64, 0x6e, 0x73, 0x5c, 0x5c, 0x5c, 0x3d, 0x73, 0x68,
- 0x6f, 0x67, 0x67, 0x6f, 0x74, 0x68, 0x2e, 0x7a, 0x65, 0x72, 0x6f, 0x74, 0x69, 0x65, 0x72, 0x2e,
- 0x63, 0x6f, 0x6d, 0x5c, 0x5c, 0x6e, 0x5c, 0x6e, 0x38, 0x61, 0x63, 0x66, 0x30, 0x35, 0x39, 0x66,
- 0x65, 0x33, 0x5c, 0x3d, 0x69, 0x64, 0x5c, 0x5c, 0x5c, 0x3d, 0x38, 0x61, 0x63, 0x66, 0x30, 0x35,
- 0x39, 0x66, 0x65, 0x33, 0x3a, 0x30, 0x3a, 0x34, 0x38, 0x32, 0x66, 0x36, 0x65, 0x65, 0x35, 0x64,
- 0x66, 0x65, 0x39, 0x30, 0x32, 0x33, 0x31, 0x39, 0x62, 0x34, 0x31, 0x39, 0x64, 0x65, 0x35, 0x62,
- 0x64, 0x63, 0x37, 0x36, 0x35, 0x32, 0x30, 0x39, 0x63, 0x30, 0x65, 0x63, 0x64, 0x61, 0x33, 0x38,
- 0x63, 0x34, 0x64, 0x36, 0x65, 0x34, 0x66, 0x63, 0x66, 0x30, 0x64, 0x33, 0x33, 0x36, 0x35, 0x38,
- 0x33, 0x39, 0x38, 0x62, 0x34, 0x35, 0x32, 0x37, 0x64, 0x63, 0x64, 0x32, 0x32, 0x66, 0x39, 0x33,
- 0x31, 0x31, 0x32, 0x66, 0x62, 0x39, 0x62, 0x65, 0x66, 0x64, 0x30, 0x32, 0x66, 0x64, 0x37, 0x38,
- 0x62, 0x66, 0x37, 0x32, 0x36, 0x31, 0x62, 0x33, 0x33, 0x33, 0x66, 0x63, 0x31, 0x30, 0x35, 0x64,
- 0x31, 0x39, 0x32, 0x61, 0x36, 0x32, 0x33, 0x63, 0x61, 0x39, 0x65, 0x35, 0x30, 0x66, 0x63, 0x36,
- 0x30, 0x62, 0x33, 0x37, 0x34, 0x61, 0x35, 0x5c, 0x5c, 0x6e, 0x75, 0x64, 0x70, 0x5c, 0x5c, 0x5c,
- 0x3d, 0x31, 0x36, 0x32, 0x2e, 0x32, 0x34, 0x33, 0x2e, 0x37, 0x37, 0x2e, 0x31, 0x31, 0x31, 0x2f,
- 0x39, 0x39, 0x39, 0x33, 0x5c, 0x5c, 0x6e, 0x74, 0x63, 0x70, 0x5c, 0x5c, 0x5c, 0x3d, 0x31, 0x36,
- 0x32, 0x2e, 0x32, 0x34, 0x33, 0x2e, 0x37, 0x37, 0x2e, 0x31, 0x31, 0x31, 0x2f, 0x34, 0x34, 0x33,
- 0x5c, 0x5c, 0x6e, 0x64, 0x65, 0x73, 0x63, 0x5c, 0x5c, 0x5c, 0x3d, 0x4e, 0x65, 0x77, 0x20, 0x59,
- 0x6f, 0x72, 0x6b, 0x2c, 0x20, 0x4e, 0x65, 0x77, 0x20, 0x59, 0x6f, 0x72, 0x6b, 0x2c, 0x20, 0x55,
- 0x53, 0x41, 0x5c, 0x5c, 0x6e, 0x64, 0x6e, 0x73, 0x5c, 0x5c, 0x5c, 0x3d, 0x63, 0x74, 0x68, 0x75,
- 0x6c, 0x68, 0x75, 0x2e, 0x7a, 0x65, 0x72, 0x6f, 0x74, 0x69, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d,
- 0x5c, 0x5c, 0x6e, 0x5c, 0x6e, 0x39, 0x64, 0x32, 0x31, 0x39, 0x30, 0x33, 0x39, 0x66, 0x33, 0x5c,
- 0x3d, 0x69, 0x64, 0x5c, 0x5c, 0x5c, 0x3d, 0x39, 0x64, 0x32, 0x31, 0x39, 0x30, 0x33, 0x39, 0x66,
- 0x33, 0x3a, 0x30, 0x3a, 0x30, 0x31, 0x66, 0x30, 0x39, 0x32, 0x32, 0x61, 0x39, 0x38, 0x65, 0x33,
- 0x62, 0x33, 0x34, 0x65, 0x62, 0x63, 0x62, 0x66, 0x66, 0x33, 0x33, 0x33, 0x32, 0x36, 0x39, 0x64,
- 0x63, 0x32, 0x36, 0x35, 0x64, 0x37, 0x61, 0x30, 0x32, 0x30, 0x61, 0x61, 0x62, 0x36, 0x39, 0x64,
- 0x37, 0x32, 0x62, 0x65, 0x34, 0x64, 0x34, 0x61, 0x63, 0x63, 0x39, 0x63, 0x38, 0x63, 0x39, 0x32,
- 0x39, 0x34, 0x37, 0x38, 0x35, 0x37, 0x37, 0x31, 0x32, 0x35, 0x36, 0x63, 0x64, 0x31, 0x64, 0x39,
- 0x34, 0x32, 0x61, 0x39, 0x30, 0x64, 0x31, 0x62, 0x64, 0x31, 0x64, 0x32, 0x64, 0x63, 0x61, 0x33,
- 0x65, 0x61, 0x38, 0x34, 0x65, 0x66, 0x37, 0x64, 0x38, 0x35, 0x61, 0x66, 0x65, 0x36, 0x36, 0x31,
- 0x31, 0x66, 0x62, 0x34, 0x33, 0x66, 0x66, 0x30, 0x62, 0x37, 0x34, 0x31, 0x32, 0x36, 0x64, 0x39,
- 0x30, 0x61, 0x36, 0x65, 0x5c, 0x5c, 0x6e, 0x75, 0x64, 0x70, 0x5c, 0x5c, 0x5c, 0x3d, 0x31, 0x32,
- 0x38, 0x2e, 0x31, 0x39, 0x39, 0x2e, 0x31, 0x39, 0x37, 0x2e, 0x32, 0x31, 0x37, 0x2f, 0x39, 0x39,
- 0x39, 0x33, 0x5c, 0x5c, 0x6e, 0x74, 0x63, 0x70, 0x5c, 0x5c, 0x5c, 0x3d, 0x31, 0x32, 0x38, 0x2e,
- 0x31, 0x39, 0x39, 0x2e, 0x31, 0x39, 0x37, 0x2e, 0x32, 0x31, 0x37, 0x2f, 0x34, 0x34, 0x33, 0x5c,
- 0x5c, 0x6e, 0x64, 0x65, 0x73, 0x63, 0x5c, 0x5c, 0x5c, 0x3d, 0x53, 0x69, 0x6e, 0x67, 0x61, 0x70,
- 0x6f, 0x72, 0x65, 0x5c, 0x5c, 0x6e, 0x64, 0x6e, 0x73, 0x5c, 0x5c, 0x5c, 0x3d, 0x6d, 0x69, 0x2d,
- 0x67, 0x6f, 0x2e, 0x7a, 0x65, 0x72, 0x6f, 0x74, 0x69, 0x65, 0x72, 0x2e, 0x63, 0x6f, 0x6d, 0x5c,
- 0x5c, 0x6e, 0x5c, 0x6e, 0x0a, 0x7e, 0x21, 0x65, 0x64, 0x32, 0x35, 0x35, 0x31, 0x39, 0x3d, 0x62,
- 0x37, 0x34, 0x39, 0x33, 0x66, 0x35, 0x61, 0x34, 0x62, 0x37, 0x39, 0x61, 0x31, 0x64, 0x63, 0x63,
- 0x34, 0x32, 0x33, 0x66, 0x64, 0x32, 0x35, 0x64, 0x32, 0x64, 0x38, 0x61, 0x61, 0x38, 0x64, 0x36,
- 0x32, 0x39, 0x33, 0x63, 0x34, 0x39, 0x30, 0x61, 0x31, 0x32, 0x63, 0x65, 0x62, 0x36, 0x33, 0x39,
- 0x35, 0x34, 0x31, 0x37, 0x64, 0x64, 0x35, 0x38, 0x36, 0x38, 0x63, 0x31, 0x37, 0x62, 0x66, 0x62,
- 0x63, 0x65, 0x65, 0x36, 0x38, 0x35, 0x64, 0x65, 0x35, 0x38, 0x30, 0x31, 0x39, 0x64, 0x32, 0x31,
- 0x66, 0x39, 0x32, 0x35, 0x37, 0x36, 0x61, 0x37, 0x38, 0x61, 0x34, 0x35, 0x32, 0x33, 0x35, 0x64,
- 0x33, 0x34, 0x32, 0x65, 0x66, 0x61, 0x32, 0x61, 0x30, 0x30, 0x61, 0x35, 0x34, 0x34, 0x64, 0x65,
- 0x64, 0x33, 0x34, 0x37, 0x36, 0x36, 0x64, 0x64, 0x33, 0x32, 0x64, 0x36, 0x66, 0x30, 0x65, 0x31,
- 0x31, 0x38, 0x30, 0x39, 0x31, 0x39, 0x37, 0x66, 0x39, 0x62, 0x61, 0x65, 0x65, 0x64, 0x66, 0x34,
- 0x63, 0x36, 0x61, 0x30, 0x65, 0x38, 0x64, 0x32, 0x64, 0x36, 0x35, 0x37, 0x64, 0x32, 0x38, 0x30,
- 0x61, 0x35, 0x37, 0x39, 0x66, 0x32, 0x66, 0x32, 0x34, 0x37, 0x38, 0x62, 0x32, 0x66, 0x37, 0x63,
- 0x37, 0x61, 0x30, 0x38, 0x30, 0x38, 0x39, 0x61, 0x35, 0x30, 0x31, 0x36, 0x62, 0x35, 0x35, 0x0a,
- 0x7e, 0x21, 0x73, 0x69, 0x67, 0x69, 0x64, 0x3d, 0x37, 0x37, 0x37, 0x39, 0x32, 0x62, 0x31, 0x63,
- 0x30, 0x32, 0x3a, 0x30, 0x3a, 0x62, 0x35, 0x63, 0x33, 0x36, 0x31, 0x65, 0x38, 0x65, 0x39, 0x63,
- 0x32, 0x31, 0x35, 0x34, 0x65, 0x38, 0x32, 0x63, 0x33, 0x65, 0x39, 0x30, 0x32, 0x66, 0x64, 0x66,
- 0x63, 0x33, 0x33, 0x37, 0x34, 0x36, 0x38, 0x62, 0x30, 0x39, 0x32, 0x61, 0x37, 0x63, 0x34, 0x64,
- 0x38, 0x64, 0x63, 0x36, 0x38, 0x35, 0x63, 0x33, 0x37, 0x65, 0x62, 0x31, 0x30, 0x65, 0x65, 0x34,
- 0x66, 0x33, 0x63, 0x31, 0x37, 0x63, 0x63, 0x30, 0x62, 0x62, 0x31, 0x64, 0x30, 0x32, 0x34, 0x31,
- 0x36, 0x37, 0x65, 0x38, 0x63, 0x62, 0x30, 0x38, 0x32, 0x34, 0x64, 0x31, 0x32, 0x32, 0x36, 0x33,
- 0x34, 0x32, 0x38, 0x33, 0x37, 0x33, 0x35, 0x38, 0x32, 0x64, 0x61, 0x33, 0x64, 0x30, 0x61, 0x39,
- 0x61, 0x31, 0x34, 0x62, 0x33, 0x36, 0x65, 0x34, 0x35, 0x34, 0x36, 0x63, 0x33, 0x31, 0x37, 0x65,
- 0x38, 0x31, 0x31, 0x65, 0x36, 0x0a, 0x7e, 0x21, 0x73, 0x69, 0x67, 0x74, 0x73, 0x3d, 0x31, 0x34,
- 0x61, 0x65, 0x34, 0x32, 0x64, 0x30, 0x33, 0x31, 0x34, 0x0a
+ 0x72, 0x6f, 0x6f, 0x74, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x73, 0x3d, 0x37, 0x65, 0x31, 0x39,
+ 0x38, 0x37, 0x36, 0x61, 0x62, 0x61, 0x5c, 0x3d, 0x69, 0x64, 0x5c, 0x5c, 0x5c, 0x3d, 0x37, 0x65,
+ 0x31, 0x39, 0x38, 0x37, 0x36, 0x61, 0x62, 0x61, 0x3a, 0x30, 0x3a, 0x32, 0x61, 0x36, 0x65, 0x32,
+ 0x62, 0x32, 0x33, 0x31, 0x38, 0x39, 0x33, 0x30, 0x66, 0x36, 0x30, 0x65, 0x62, 0x30, 0x39, 0x37,
+ 0x66, 0x37, 0x30, 0x64, 0x30, 0x66, 0x34, 0x62, 0x30, 0x32, 0x38, 0x62, 0x32, 0x63, 0x64, 0x36,
+ 0x64, 0x33, 0x64, 0x30, 0x63, 0x36, 0x33, 0x63, 0x30, 0x31, 0x34, 0x62, 0x39, 0x30, 0x33, 0x39,
+ 0x66, 0x66, 0x33, 0x35, 0x33, 0x39, 0x30, 0x65, 0x34, 0x31, 0x31, 0x38, 0x31, 0x66, 0x32, 0x31,
+ 0x36, 0x66, 0x62, 0x32, 0x65, 0x36, 0x66, 0x61, 0x38, 0x64, 0x39, 0x35, 0x63, 0x31, 0x65, 0x65,
+ 0x39, 0x36, 0x36, 0x37, 0x31, 0x35, 0x36, 0x34, 0x31, 0x31, 0x39, 0x30, 0x35, 0x63, 0x33, 0x64,
+ 0x63, 0x63, 0x66, 0x65, 0x61, 0x37, 0x38, 0x64, 0x38, 0x63, 0x36, 0x64, 0x66, 0x61, 0x66, 0x62,
+ 0x61, 0x36, 0x38, 0x38, 0x31, 0x37, 0x30, 0x62, 0x33, 0x66, 0x61, 0x5c, 0x5c, 0x6e, 0x75, 0x64,
+ 0x70, 0x5c, 0x5c, 0x5c, 0x3d, 0x31, 0x39, 0x38, 0x2e, 0x31, 0x39, 0x39, 0x2e, 0x39, 0x37, 0x2e,
+ 0x32, 0x32, 0x30, 0x2f, 0x39, 0x39, 0x39, 0x33, 0x5c, 0x5c, 0x6e, 0x74, 0x63, 0x70, 0x5c, 0x5c,
+ 0x5c, 0x3d, 0x31, 0x39, 0x38, 0x2e, 0x31, 0x39, 0x39, 0x2e, 0x39, 0x37, 0x2e, 0x32, 0x32, 0x30,
+ 0x2f, 0x34, 0x34, 0x33, 0x5c, 0x5c, 0x6e, 0x64, 0x65, 0x73, 0x63, 0x5c, 0x5c, 0x5c, 0x3d, 0x53,
+ 0x61, 0x6e, 0x20, 0x46, 0x72, 0x61, 0x6e, 0x63, 0x69, 0x73, 0x63, 0x6f, 0x2c, 0x20, 0x43, 0x61,
+ 0x6c, 0x69, 0x66, 0x6f, 0x72, 0x6e, 0x69, 0x61, 0x2c, 0x20, 0x55, 0x53, 0x41, 0x5c, 0x5c, 0x6e,
+ 0x5c, 0x6e, 0x38, 0x38, 0x34, 0x31, 0x34, 0x30, 0x38, 0x61, 0x32, 0x65, 0x5c, 0x3d, 0x69, 0x64,
+ 0x5c, 0x5c, 0x5c, 0x3d, 0x38, 0x38, 0x34, 0x31, 0x34, 0x30, 0x38, 0x61, 0x32, 0x65, 0x3a, 0x30,
+ 0x3a, 0x62, 0x62, 0x31, 0x64, 0x33, 0x31, 0x66, 0x32, 0x63, 0x33, 0x32, 0x33, 0x65, 0x32, 0x36,
+ 0x34, 0x65, 0x39, 0x65, 0x36, 0x34, 0x31, 0x37, 0x32, 0x63, 0x31, 0x61, 0x37, 0x34, 0x66, 0x37,
+ 0x37, 0x38, 0x39, 0x39, 0x35, 0x35, 0x35, 0x65, 0x64, 0x31, 0x30, 0x37, 0x35, 0x31, 0x63, 0x64,
+ 0x35, 0x36, 0x65, 0x38, 0x36, 0x34, 0x30, 0x35, 0x63, 0x64, 0x65, 0x31, 0x31, 0x38, 0x64, 0x30,
+ 0x32, 0x64, 0x66, 0x66, 0x65, 0x35, 0x35, 0x35, 0x64, 0x34, 0x36, 0x32, 0x63, 0x63, 0x66, 0x36,
+ 0x61, 0x38, 0x35, 0x62, 0x35, 0x36, 0x33, 0x31, 0x63, 0x31, 0x32, 0x33, 0x35, 0x30, 0x63, 0x38,
+ 0x64, 0x35, 0x64, 0x63, 0x34, 0x30, 0x39, 0x62, 0x61, 0x31, 0x30, 0x62, 0x39, 0x30, 0x32, 0x35,
+ 0x64, 0x30, 0x66, 0x34, 0x34, 0x35, 0x63, 0x66, 0x34, 0x34, 0x39, 0x64, 0x39, 0x32, 0x62, 0x31,
+ 0x63, 0x5c, 0x5c, 0x6e, 0x75, 0x64, 0x70, 0x5c, 0x5c, 0x5c, 0x3d, 0x31, 0x30, 0x37, 0x2e, 0x31,
+ 0x39, 0x31, 0x2e, 0x34, 0x36, 0x2e, 0x32, 0x31, 0x30, 0x2f, 0x39, 0x39, 0x39, 0x33, 0x5c, 0x5c,
+ 0x6e, 0x74, 0x63, 0x70, 0x5c, 0x5c, 0x5c, 0x3d, 0x31, 0x30, 0x37, 0x2e, 0x31, 0x39, 0x31, 0x2e,
+ 0x34, 0x36, 0x2e, 0x32, 0x31, 0x30, 0x2f, 0x34, 0x34, 0x33, 0x5c, 0x5c, 0x6e, 0x64, 0x65, 0x73,
+ 0x63, 0x5c, 0x5c, 0x5c, 0x3d, 0x50, 0x61, 0x72, 0x69, 0x73, 0x2c, 0x20, 0x46, 0x72, 0x61, 0x6e,
+ 0x63, 0x65, 0x5c, 0x5c, 0x6e, 0x5c, 0x6e, 0x38, 0x61, 0x63, 0x66, 0x30, 0x35, 0x39, 0x66, 0x65,
+ 0x33, 0x5c, 0x3d, 0x69, 0x64, 0x5c, 0x5c, 0x5c, 0x3d, 0x38, 0x61, 0x63, 0x66, 0x30, 0x35, 0x39,
+ 0x66, 0x65, 0x33, 0x3a, 0x30, 0x3a, 0x34, 0x38, 0x32, 0x66, 0x36, 0x65, 0x65, 0x35, 0x64, 0x66,
+ 0x65, 0x39, 0x30, 0x32, 0x33, 0x31, 0x39, 0x62, 0x34, 0x31, 0x39, 0x64, 0x65, 0x35, 0x62, 0x64,
+ 0x63, 0x37, 0x36, 0x35, 0x32, 0x30, 0x39, 0x63, 0x30, 0x65, 0x63, 0x64, 0x61, 0x33, 0x38, 0x63,
+ 0x34, 0x64, 0x36, 0x65, 0x34, 0x66, 0x63, 0x66, 0x30, 0x64, 0x33, 0x33, 0x36, 0x35, 0x38, 0x33,
+ 0x39, 0x38, 0x62, 0x34, 0x35, 0x32, 0x37, 0x64, 0x63, 0x64, 0x32, 0x32, 0x66, 0x39, 0x33, 0x31,
+ 0x31, 0x32, 0x66, 0x62, 0x39, 0x62, 0x65, 0x66, 0x64, 0x30, 0x32, 0x66, 0x64, 0x37, 0x38, 0x62,
+ 0x66, 0x37, 0x32, 0x36, 0x31, 0x62, 0x33, 0x33, 0x33, 0x66, 0x63, 0x31, 0x30, 0x35, 0x64, 0x31,
+ 0x39, 0x32, 0x61, 0x36, 0x32, 0x33, 0x63, 0x61, 0x39, 0x65, 0x35, 0x30, 0x66, 0x63, 0x36, 0x30,
+ 0x62, 0x33, 0x37, 0x34, 0x61, 0x35, 0x5c, 0x5c, 0x6e, 0x75, 0x64, 0x70, 0x5c, 0x5c, 0x5c, 0x3d,
+ 0x31, 0x36, 0x32, 0x2e, 0x32, 0x34, 0x33, 0x2e, 0x37, 0x37, 0x2e, 0x31, 0x31, 0x31, 0x2f, 0x39,
+ 0x39, 0x39, 0x33, 0x5c, 0x5c, 0x6e, 0x74, 0x63, 0x70, 0x5c, 0x5c, 0x5c, 0x3d, 0x31, 0x36, 0x32,
+ 0x2e, 0x32, 0x34, 0x33, 0x2e, 0x37, 0x37, 0x2e, 0x31, 0x31, 0x31, 0x2f, 0x34, 0x34, 0x33, 0x5c,
+ 0x5c, 0x6e, 0x64, 0x65, 0x73, 0x63, 0x5c, 0x5c, 0x5c, 0x3d, 0x4e, 0x65, 0x77, 0x20, 0x59, 0x6f,
+ 0x72, 0x6b, 0x2c, 0x20, 0x4e, 0x65, 0x77, 0x20, 0x59, 0x6f, 0x72, 0x6b, 0x2c, 0x20, 0x55, 0x53,
+ 0x41, 0x5c, 0x5c, 0x6e, 0x5c, 0x6e, 0x39, 0x64, 0x32, 0x31, 0x39, 0x30, 0x33, 0x39, 0x66, 0x33,
+ 0x5c, 0x3d, 0x69, 0x64, 0x5c, 0x5c, 0x5c, 0x3d, 0x39, 0x64, 0x32, 0x31, 0x39, 0x30, 0x33, 0x39,
+ 0x66, 0x33, 0x3a, 0x30, 0x3a, 0x30, 0x31, 0x66, 0x30, 0x39, 0x32, 0x32, 0x61, 0x39, 0x38, 0x65,
+ 0x33, 0x62, 0x33, 0x34, 0x65, 0x62, 0x63, 0x62, 0x66, 0x66, 0x33, 0x33, 0x33, 0x32, 0x36, 0x39,
+ 0x64, 0x63, 0x32, 0x36, 0x35, 0x64, 0x37, 0x61, 0x30, 0x32, 0x30, 0x61, 0x61, 0x62, 0x36, 0x39,
+ 0x64, 0x37, 0x32, 0x62, 0x65, 0x34, 0x64, 0x34, 0x61, 0x63, 0x63, 0x39, 0x63, 0x38, 0x63, 0x39,
+ 0x32, 0x39, 0x34, 0x37, 0x38, 0x35, 0x37, 0x37, 0x31, 0x32, 0x35, 0x36, 0x63, 0x64, 0x31, 0x64,
+ 0x39, 0x34, 0x32, 0x61, 0x39, 0x30, 0x64, 0x31, 0x62, 0x64, 0x31, 0x64, 0x32, 0x64, 0x63, 0x61,
+ 0x33, 0x65, 0x61, 0x38, 0x34, 0x65, 0x66, 0x37, 0x64, 0x38, 0x35, 0x61, 0x66, 0x65, 0x36, 0x36,
+ 0x31, 0x31, 0x66, 0x62, 0x34, 0x33, 0x66, 0x66, 0x30, 0x62, 0x37, 0x34, 0x31, 0x32, 0x36, 0x64,
+ 0x39, 0x30, 0x61, 0x36, 0x65, 0x5c, 0x5c, 0x6e, 0x75, 0x64, 0x70, 0x5c, 0x5c, 0x5c, 0x3d, 0x31,
+ 0x32, 0x38, 0x2e, 0x31, 0x39, 0x39, 0x2e, 0x31, 0x39, 0x37, 0x2e, 0x32, 0x31, 0x37, 0x2f, 0x39,
+ 0x39, 0x39, 0x33, 0x5c, 0x5c, 0x6e, 0x74, 0x63, 0x70, 0x5c, 0x5c, 0x5c, 0x3d, 0x31, 0x32, 0x38,
+ 0x2e, 0x31, 0x39, 0x39, 0x2e, 0x31, 0x39, 0x37, 0x2e, 0x32, 0x31, 0x37, 0x2f, 0x34, 0x34, 0x33,
+ 0x5c, 0x5c, 0x6e, 0x64, 0x65, 0x73, 0x63, 0x5c, 0x5c, 0x5c, 0x3d, 0x53, 0x69, 0x6e, 0x67, 0x61,
+ 0x70, 0x6f, 0x72, 0x65, 0x5c, 0x5c, 0x6e, 0x5c, 0x6e, 0x0a, 0x7e, 0x21, 0x65, 0x64, 0x32, 0x35,
+ 0x35, 0x31, 0x39, 0x3d, 0x38, 0x33, 0x32, 0x62, 0x33, 0x35, 0x64, 0x61, 0x64, 0x64, 0x37, 0x66,
+ 0x35, 0x36, 0x66, 0x66, 0x33, 0x38, 0x31, 0x66, 0x61, 0x37, 0x32, 0x31, 0x64, 0x65, 0x37, 0x64,
+ 0x35, 0x62, 0x65, 0x34, 0x63, 0x65, 0x62, 0x66, 0x63, 0x63, 0x63, 0x32, 0x30, 0x30, 0x32, 0x30,
+ 0x38, 0x33, 0x38, 0x30, 0x64, 0x33, 0x30, 0x38, 0x34, 0x66, 0x36, 0x34, 0x38, 0x65, 0x32, 0x63,
+ 0x31, 0x61, 0x35, 0x63, 0x66, 0x34, 0x33, 0x65, 0x35, 0x39, 0x66, 0x39, 0x32, 0x61, 0x36, 0x36,
+ 0x35, 0x64, 0x66, 0x34, 0x64, 0x62, 0x63, 0x62, 0x38, 0x33, 0x37, 0x38, 0x38, 0x66, 0x36, 0x62,
+ 0x64, 0x36, 0x37, 0x37, 0x66, 0x30, 0x32, 0x62, 0x32, 0x31, 0x30, 0x65, 0x35, 0x30, 0x63, 0x61,
+ 0x66, 0x65, 0x66, 0x64, 0x32, 0x65, 0x66, 0x31, 0x38, 0x39, 0x62, 0x62, 0x66, 0x34, 0x38, 0x31,
+ 0x62, 0x64, 0x30, 0x32, 0x63, 0x64, 0x63, 0x39, 0x38, 0x34, 0x35, 0x33, 0x38, 0x37, 0x64, 0x38,
+ 0x34, 0x39, 0x62, 0x63, 0x35, 0x36, 0x66, 0x39, 0x63, 0x37, 0x32, 0x35, 0x31, 0x65, 0x35, 0x64,
+ 0x30, 0x65, 0x61, 0x34, 0x34, 0x34, 0x66, 0x66, 0x63, 0x66, 0x38, 0x66, 0x37, 0x32, 0x32, 0x63,
+ 0x32, 0x66, 0x65, 0x62, 0x38, 0x39, 0x36, 0x30, 0x33, 0x61, 0x30, 0x65, 0x35, 0x62, 0x61, 0x32,
+ 0x39, 0x35, 0x66, 0x63, 0x0a, 0x7e, 0x21, 0x73, 0x69, 0x67, 0x69, 0x64, 0x3d, 0x37, 0x37, 0x37,
+ 0x39, 0x32, 0x62, 0x31, 0x63, 0x30, 0x32, 0x3a, 0x30, 0x3a, 0x62, 0x35, 0x63, 0x33, 0x36, 0x31,
+ 0x65, 0x38, 0x65, 0x39, 0x63, 0x32, 0x31, 0x35, 0x34, 0x65, 0x38, 0x32, 0x63, 0x33, 0x65, 0x39,
+ 0x30, 0x32, 0x66, 0x64, 0x66, 0x63, 0x33, 0x33, 0x37, 0x34, 0x36, 0x38, 0x62, 0x30, 0x39, 0x32,
+ 0x61, 0x37, 0x63, 0x34, 0x64, 0x38, 0x64, 0x63, 0x36, 0x38, 0x35, 0x63, 0x33, 0x37, 0x65, 0x62,
+ 0x31, 0x30, 0x65, 0x65, 0x34, 0x66, 0x33, 0x63, 0x31, 0x37, 0x63, 0x63, 0x30, 0x62, 0x62, 0x31,
+ 0x64, 0x30, 0x32, 0x34, 0x31, 0x36, 0x37, 0x65, 0x38, 0x63, 0x62, 0x30, 0x38, 0x32, 0x34, 0x64,
+ 0x31, 0x32, 0x32, 0x36, 0x33, 0x34, 0x32, 0x38, 0x33, 0x37, 0x33, 0x35, 0x38, 0x32, 0x64, 0x61,
+ 0x33, 0x64, 0x30, 0x61, 0x39, 0x61, 0x31, 0x34, 0x62, 0x33, 0x36, 0x65, 0x34, 0x35, 0x34, 0x36,
+ 0x63, 0x33, 0x31, 0x37, 0x65, 0x38, 0x31, 0x31, 0x65, 0x36, 0x0a, 0x7e, 0x21, 0x73, 0x69, 0x67,
+ 0x74, 0x73, 0x3d, 0x31, 0x34, 0x65, 0x30, 0x63, 0x62, 0x62, 0x39, 0x38, 0x64, 0x36, 0x0a
};
-#define ZT_DEFAULT_ROOT_TOPOLOGY_LEN 1514
+#define ZT_DEFAULT_ROOT_TOPOLOGY_LEN 1391
diff --git a/root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.dict b/root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.dict
index 8aa828f0a..58144758e 100644
--- a/root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.dict
+++ b/root-topology/ZT_DEFAULT_ROOT_TOPOLOGY.dict
@@ -1,4 +1,4 @@
-supernodes=7e19876aba\=id\\\=7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa\\nudp\\\=198.199.97.220/9993\\ntcp\\\=198.199.97.220/443\\ndesc\\\=San Francisco, California, USA\\ndns\\\=nyarlathotep.zerotier.com\\n\n8841408a2e\=id\\\=8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02dffe555d462ccf6a85b5631c12350c8d5dc409ba10b9025d0f445cf449d92b1c\\nudp\\\=107.191.46.210/9993\\ntcp\\\=107.191.46.210/443\\ndesc\\\=Paris, France\\ndns\\\=shoggoth.zerotier.com\\n\n8acf059fe3\=id\\\=8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5\\nudp\\\=162.243.77.111/9993\\ntcp\\\=162.243.77.111/443\\ndesc\\\=New York, New York, USA\\ndns\\\=cthulhu.zerotier.com\\n\n9d219039f3\=id\\\=9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c9294785771256cd1d942a90d1bd1d2dca3ea84ef7d85afe6611fb43ff0b74126d90a6e\\nudp\\\=128.199.197.217/9993\\ntcp\\\=128.199.197.217/443\\ndesc\\\=Singapore\\ndns\\\=mi-go.zerotier.com\\n\n
-~!ed25519=b7493f5a4b79a1dcc423fd25d2d8aa8d6293c490a12ceb6395417dd5868c17bfbcee685de58019d21f92576a78a45235d342efa2a00a544ded34766dd32d6f0e11809197f9baeedf4c6a0e8d2d657d280a579f2f2478b2f7c7a08089a5016b55
+rootservers=7e19876aba\=id\\\=7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e41181f216fb2e6fa8d95c1ee9667156411905c3dccfea78d8c6dfafba688170b3fa\\nudp\\\=198.199.97.220/9993\\ntcp\\\=198.199.97.220/443\\ndesc\\\=San Francisco, California, USA\\n\n8841408a2e\=id\\\=8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02dffe555d462ccf6a85b5631c12350c8d5dc409ba10b9025d0f445cf449d92b1c\\nudp\\\=107.191.46.210/9993\\ntcp\\\=107.191.46.210/443\\ndesc\\\=Paris, France\\n\n8acf059fe3\=id\\\=8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b4527dcd22f93112fb9befd02fd78bf7261b333fc105d192a623ca9e50fc60b374a5\\nudp\\\=162.243.77.111/9993\\ntcp\\\=162.243.77.111/443\\ndesc\\\=New York, New York, USA\\n\n9d219039f3\=id\\\=9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c9294785771256cd1d942a90d1bd1d2dca3ea84ef7d85afe6611fb43ff0b74126d90a6e\\nudp\\\=128.199.197.217/9993\\ntcp\\\=128.199.197.217/443\\ndesc\\\=Singapore\\n\n
+~!ed25519=832b35dadd7f56ff381fa721de7d5be4cebfccc200208380d3084f648e2c1a5cf43e59f92a665df4dbcb83788f6bd677f02b210e50cafefd2ef189bbf481bd02cdc9845387d849bc56f9c7251e5d0ea444ffcf8f722c2feb89603a0e5ba295fc
~!sigid=77792b1c02:0:b5c361e8e9c2154e82c3e902fdfc337468b092a7c4d8dc685c37eb10ee4f3c17cc0bb1d024167e8cb0824d12263428373582da3d0a9a14b36e4546c317e811e6
-~!sigts=14ae42d0314
+~!sigts=14e0cbb98d6
diff --git a/root-topology/mktopology.cpp b/root-topology/mktopology.cpp
index 00ada7b76..f0ad5b556 100644
--- a/root-topology/mktopology.cpp
+++ b/root-topology/mktopology.cpp
@@ -30,21 +30,21 @@ int main(int argc,char **argv)
if (OSUtils::readFile("template.dict",buf))
topology.fromString(buf);
- // Read all entries in supernodes/ that correspond to supernode entry dictionaries
- // and add them to topology under supernodes/ subkey.
- Dictionary supernodes;
- std::vector supernodeDictionaries(OSUtils::listDirectory("supernodes"));
- for(std::vector::const_iterator sn(supernodeDictionaries.begin());sn!=supernodeDictionaries.end();++sn) {
+ // Read all entries in rootservers/ that correspond to rootserver entry dictionaries
+ // and add them to topology under rootservers/ subkey.
+ Dictionary rootservers;
+ std::vector rootserverDictionaries(OSUtils::listDirectory("rootservers"));
+ for(std::vector::const_iterator sn(rootserverDictionaries.begin());sn!=rootserverDictionaries.end();++sn) {
if (sn->length() == 10) {
buf.clear();
- if (!OSUtils::readFile((std::string("supernodes/")+(*sn)).c_str(),buf)) {
- std::cerr << "Cannot read supernodes/" << *sn << std::endl;
+ if (!OSUtils::readFile((std::string("rootservers/")+(*sn)).c_str(),buf)) {
+ std::cerr << "Cannot read rootservers/" << *sn << std::endl;
return 1;
}
- supernodes[*sn] = buf;
+ rootservers[*sn] = buf;
}
}
- topology["supernodes"] = supernodes.toString();
+ topology["rootservers"] = rootservers.toString();
if ((topologyAuthority)&&(topologyAuthority.hasPrivate())) {
// Sign topology with root-topology-authority.secret
diff --git a/root-topology/supernodes/7e19876aba b/root-topology/rootservers/7e19876aba
similarity index 88%
rename from root-topology/supernodes/7e19876aba
rename to root-topology/rootservers/7e19876aba
index 23c2ad247..6bd8dc429 100644
--- a/root-topology/supernodes/7e19876aba
+++ b/root-topology/rootservers/7e19876aba
@@ -2,4 +2,3 @@ id=7e19876aba:0:2a6e2b2318930f60eb097f70d0f4b028b2cd6d3d0c63c014b9039ff35390e411
udp=198.199.97.220/9993
tcp=198.199.97.220/443
desc=San Francisco, California, USA
-dns=nyarlathotep.zerotier.com
diff --git a/root-topology/supernodes/8841408a2e b/root-topology/rootservers/8841408a2e
similarity index 89%
rename from root-topology/supernodes/8841408a2e
rename to root-topology/rootservers/8841408a2e
index 09258f4e0..3be3333e4 100644
--- a/root-topology/supernodes/8841408a2e
+++ b/root-topology/rootservers/8841408a2e
@@ -2,4 +2,3 @@ id=8841408a2e:0:bb1d31f2c323e264e9e64172c1a74f77899555ed10751cd56e86405cde118d02
udp=107.191.46.210/9993
tcp=107.191.46.210/443
desc=Paris, France
-dns=shoggoth.zerotier.com
diff --git a/root-topology/supernodes/8acf059fe3 b/root-topology/rootservers/8acf059fe3
similarity index 89%
rename from root-topology/supernodes/8acf059fe3
rename to root-topology/rootservers/8acf059fe3
index 438e67a32..4a569d95b 100644
--- a/root-topology/supernodes/8acf059fe3
+++ b/root-topology/rootservers/8acf059fe3
@@ -2,4 +2,3 @@ id=8acf059fe3:0:482f6ee5dfe902319b419de5bdc765209c0ecda38c4d6e4fcf0d33658398b452
udp=162.243.77.111/9993
tcp=162.243.77.111/443
desc=New York, New York, USA
-dns=cthulhu.zerotier.com
diff --git a/root-topology/supernodes/9d219039f3 b/root-topology/rootservers/9d219039f3
similarity index 90%
rename from root-topology/supernodes/9d219039f3
rename to root-topology/rootservers/9d219039f3
index 1602f35e4..ec9224336 100644
--- a/root-topology/supernodes/9d219039f3
+++ b/root-topology/rootservers/9d219039f3
@@ -2,4 +2,3 @@ id=9d219039f3:0:01f0922a98e3b34ebcbff333269dc265d7a020aab69d72be4d4acc9c8c929478
udp=128.199.197.217/9993
tcp=128.199.197.217/443
desc=Singapore
-dns=mi-go.zerotier.com
diff --git a/root-topology/test/README.md b/root-topology/test/README.md
index 332f8297f..ae7022437 100644
--- a/root-topology/test/README.md
+++ b/root-topology/test/README.md
@@ -1,6 +1,6 @@
Test Root Topology Script
======
-This builds a test-root-topology from any number of running test-supernode-# Docker containers. This can then be used with the (undocumented) -T (override root topology) option to run test networks under Docker.
+This builds a test-root-topology from any number of running test-rootserver-# Docker containers. This can then be used with the (undocumented) -T (override root topology) option to run test networks under Docker.
Once you have a local Docker test network running you can use iptables rules to simulate a variety of network pathologies, or you can just use it to test any new changes to the protocol or node behavior at some limited scale.
diff --git a/root-topology/test/create-test-root-topology.sh b/root-topology/test/create-test-root-topology.sh
index 86c0577cf..cb6287295 100755
--- a/root-topology/test/create-test-root-topology.sh
+++ b/root-topology/test/create-test-root-topology.sh
@@ -5,18 +5,18 @@ if [ ! -e ../mktopology ]; then
exit 1
fi
-echo 'Populating supernodes/* with all Docker test-supernode-* container IPs and identities...'
+echo 'Populating rootservers/* with all Docker test-rootserver-* container IPs and identities...'
-rm -rf supernodes
-mkdir supernodes
+rm -rf rootservers
+mkdir rootservers
-for cid in `docker ps -f 'name=test-supernode-*' -q`; do
+for cid in `docker ps -f 'name=test-rootserver-*' -q`; do
id=`docker exec $cid cat /var/lib/zerotier-one/identity.secret | cut -d : -f 1-3`
ztaddr=`echo $id | cut -d : -f 1`
ip=`docker exec $cid ifconfig | sed -En 's/127.0.0.1//;s/.*inet (addr:)?(([0-9]*\.){3}[0-9]*).*/\2/p'`
echo $cid $ztaddr $id $ip
- echo "id=$id" >supernodes/$ztaddr
- echo "udp=$ip/9993" >>supernodes/$ztaddr
+ echo "id=$id" >rootservers/$ztaddr
+ echo "udp=$ip/9993" >>rootservers/$ztaddr
done
echo 'Creating test-root-topology...'
diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp
index 71b3fd3fb..015825867 100644
--- a/service/ControlPlane.cpp
+++ b/service/ControlPlane.cpp
@@ -211,9 +211,9 @@ static void _jsonAppend(unsigned int depth,std::string &buf,const ZT1_Peer *peer
const char *prole = "";
switch(peer->role) {
- case ZT1_PEER_ROLE_LEAF: prole = "LEAF"; break;
- case ZT1_PEER_ROLE_HUB: prole = "HUB"; break;
- case ZT1_PEER_ROLE_SUPERNODE: prole = "SUPERNODE"; break;
+ case ZT1_PEER_ROLE_LEAF: prole = "LEAF"; break;
+ case ZT1_PEER_ROLE_RELAY: prole = "RELAY"; break;
+ case ZT1_PEER_ROLE_ROOT: prole = "ROOT"; break;
}
Utils::snprintf(json,sizeof(json),
@@ -454,7 +454,7 @@ unsigned int ControlPlane::handleRequest(
} else {
#ifdef ZT_ENABLE_NETWORK_CONTROLLER
if (_controller)
- _controller->handleControlPlaneHttpGET(std::vector(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
+ scode = _controller->handleControlPlaneHttpGET(std::vector(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
else scode = 404;
#else
scode = 404;
@@ -490,7 +490,7 @@ unsigned int ControlPlane::handleRequest(
} else {
#ifdef ZT_ENABLE_NETWORK_CONTROLLER
if (_controller)
- _controller->handleControlPlaneHttpPOST(std::vector(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
+ scode = _controller->handleControlPlaneHttpPOST(std::vector(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
else scode = 404;
#else
scode = 404;
@@ -525,7 +525,7 @@ unsigned int ControlPlane::handleRequest(
} else {
#ifdef ZT_ENABLE_NETWORK_CONTROLLER
if (_controller)
- _controller->handleControlPlaneHttpDELETE(std::vector(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
+ scode = _controller->handleControlPlaneHttpDELETE(std::vector(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
else scode = 404;
#else
scode = 404;
diff --git a/service/README.md b/service/README.md
index acad97a14..df62ff274 100644
--- a/service/README.md
+++ b/service/README.md
@@ -106,7 +106,7 @@ Getting /peer returns an array of peer objects for all current peers. See below
versionRev | integer | Revision of remote if known | no |
version | string | Version in major.minor.rev format | no |
latency | integer | Latency in milliseconds if known | no |
-role | string | LEAF, HUB, or SUPERNODE | no |
+role | string | LEAF, HUB, or ROOTSERVER | no |
paths | [object] | Array of path objects (see below) | no |
@@ -184,7 +184,7 @@ Relays, IP assignment pools, and rules are edited via direct POSTs to the networ
**Relay object format:**
-Relay objects define network-specific preferred relay nodes. Traffic to peers on this network will preferentially use these relays if they are available, and otherwise will fall back to the global supernode infrastructure.
+Relay objects define network-specific preferred relay nodes. Traffic to peers on this network will preferentially use these relays if they are available, and otherwise will fall back to the global rootserver infrastructure.
Field | Type | Description |
@@ -204,7 +204,7 @@ Relay objects define network-specific preferred relay nodes. Traffic to peers on
* **Note**: at the moment, only rules specifying allowed Ethernet types are used. The database supports a richer rule set, but this is not implemented yet in the client. Other types of rules will have no effect (yet).
-Rules are matched in order of ruleId. If no rules match, the default action is 'drop'. To allow all traffic, create a single rule with all *null* fields and an action of 'accept'.
+Rules are matched in order of ruleNo. If no rules match, the default action is 'drop'. To allow all traffic, create a single rule with all *null* fields and an action of 'accept'.
Rule object fields can be *null*, in which case they are omitted from the object. A null field indicates "no match on this criteria."
@@ -212,7 +212,7 @@ IP related fields apply only to Ethernet frames of type IPv4 or IPV6. Otherwise
Field | Type | Description |
-ruleId | integer | User-defined rule ID and sort order |
+ruleNo | integer | User-defined rule ID and sort order |
nodeId | string | 10-digit hex ZeroTier address of node (a.k.a. "port on switch") |
vlanId | integer | Ethernet VLAN ID |
vlanPcp | integer | Ethernet VLAN priority code point (PCP) ID |
diff --git a/tcp-proxy/tcp-proxy.cpp b/tcp-proxy/tcp-proxy.cpp
index f7ba2c2f6..6acf7b423 100644
--- a/tcp-proxy/tcp-proxy.cpp
+++ b/tcp-proxy/tcp-proxy.cpp
@@ -85,7 +85,7 @@ using namespace ZeroTier;
* in which every encapsulated ZT packet is prepended by an IP address where
* it should be forwarded (or where it came from for replies). This causes
* this proxy to act as a remote UDP socket similar to a socks proxy, which
- * will allow us to move this function off the supernodes and onto dedicated
+ * will allow us to move this function off the rootservers and onto dedicated
* proxy nodes.
*
* Older ZT clients that do not send this message get their packets relayed