This commit is contained in:
keesbos 2015-06-26 20:14:27 +00:00
commit 6de91ba3fe
52 changed files with 967 additions and 1173 deletions

41
AUTHORS.md Normal file
View file

@ -0,0 +1,41 @@
## Authors
* ZeroTier protocol design and core network virtualization engine, ZeroTier One service, React web UI, packaging for most platforms, kitchen sink...<br>
Adam Ierymenko / adam.ierymenko@zerotier.com
* Java JNI Interface to enable Android application development, and Android app itself (code for that is elsewhere)<br>
Grant Limberg / glimberg@gmail.com
## Contributors
* A number of fixes and improvements to the new controller, other stuff.<br>
Kees Bos / https://github.com/keesbos
* Debugging and testing, OpenWRT support fixes.<br>
Moritz Warning / moritzwarning@web.de
* Several others made smaller contributions, which GitHub tracks here:<br>
https://github.com/zerotier/ZeroTierOne/graphs/contributors
## Third Party Code
* LZ4 compression algorithm by Yann Collet (BSD license)<br>
http://code.google.com/p/lz4/
* http-parser by many authors (MIT license)<br>
https://github.com/joyent/http-parser
* json-parser by James McLaughlin (BSD license)<br>
https://github.com/udp/json-parser
* TunTapOSX by Mattias Nissler (BSD license)<br>
http://tuntaposx.sourceforge.net
* tap-windows and tap-windows6 by the OpenVPN project (GPL)<br>
https://github.com/OpenVPN/tap-windows<br>
https://github.com/OpenVPN/tap-windows6
* Salsa20 stream cipher, Curve25519 elliptic curve cipher, Ed25519
digital signature algorithm, and Poly1305 MAC algorithm, all by
Daniel J. Bernstein (public domain)<br>
http://cr.yp.to/

View file

@ -1,27 +0,0 @@
ZeroTier One is designed and written by Adam Ierymenko, with a few bug
fixes and other contributions from other users. Information about all
contributors can be found on the GitHub home page at:
https://github.com/zerotier/ZeroTierOne
ZeroTier One includes the following third party code:
* LZ4 compression algorithm by Yann Collet (BSD license)
http://code.google.com/p/lz4/
* http-parser by many authors (MIT license)
https://github.com/joyent/http-parser
* json-parser by James McLaughlin (BSD license)
https://github.com/udp/json-parser
* TunTapOSX by Mattias Nissler (forked for ZT1) (BSD license)
http://tuntaposx.sourceforge.net
* tap-windows by the OpenVPN project (forked for ZT1) (GPL)
https://github.com/OpenVPN/tap-windows
* Salsa20 stream cipher, Curve25519 elliptic curve cipher, Ed25519
digital signature algorithm, and Poly1305 MAC algorithm, all by
Daniel J. Bernstein (public domain)
http://cr.yp.to/

View file

@ -164,7 +164,7 @@ Users behind certain types of firewalls and "symmetric" NAT devices may not able
If you're interested, there's a [technical deep dive about NAT traversal on our blog](https://www.zerotier.com/blog/?p=226). A troubleshooting tool to help you diagnose NAT issues is planned for the future as are uPnP/IGD/NAT-PMP and IPv6 transport.
If a firewall between you and the Internet blocks ZeroTier's UDP traffic, you will fall back to last-resort TCP tunneling to supernodes over port 443 (https impersonation). This will work almost anywhere but is *very slow* compared to UDP or direct peer to peer connectivity.
If a firewall between you and the Internet blocks ZeroTier's UDP traffic, you will fall back to last-resort TCP tunneling to rootservers over port 443 (https impersonation). This will work almost anywhere but is *very slow* compared to UDP or direct peer to peer connectivity.
### License

View file

@ -50,6 +50,7 @@
#include "../node/InetAddress.hpp"
#include "../node/MAC.hpp"
#include "../node/Address.hpp"
#include "../node/Switch.hpp"
#include "../osdep/OSUtils.hpp"
// Include ZT_NETCONF_SCHEMA_SQL constant to init database
@ -155,7 +156,6 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
||(sqlite3_prepare_v2(_db,"UPDATE Node SET lastAt = ?,lastSeen = ? WHERE id = ?",-1,&_sUpdateNode,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"UPDATE Node SET lastSeen = ? WHERE id = ?",-1,&_sUpdateNode2,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT etherType FROM Rule WHERE networkId = ? AND \"action\" = 'accept'",-1,&_sGetEtherTypesFromRuleTable,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT mgMac,mgAdi,preload,maxBalance,accrual FROM MulticastRate WHERE networkId = ?",-1,&_sGetMulticastRates,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT nodeId FROM Member WHERE networkId = ? AND activeBridge > 0 AND authorized > 0",-1,&_sGetActiveBridges,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT ip,ipNetmaskBits FROM IpAssignment WHERE networkId = ? AND nodeId = ? AND ipVersion = ?",-1,&_sGetIpAssignmentsForNode,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT ipNetwork,ipNetmaskBits FROM IpAssignmentPool WHERE networkId = ? AND ipVersion = ?",-1,&_sGetIpAssignmentPools,(const char **)0) != SQLITE_OK)
@ -164,11 +164,11 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
||(sqlite3_prepare_v2(_db,"DELETE FROM IpAssignment WHERE networkId = ? AND nodeId = ?",-1,&_sDeleteIpAllocations,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT nodeId,phyAddress FROM Relay WHERE networkId = ? ORDER BY nodeId ASC",-1,&_sGetRelays,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT id FROM Network ORDER BY id ASC",-1,&_sListNetworks,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT n.id FROM Member AS m,Node AS n WHERE m.networkId = ? AND n.id = m.nodeId ORDER BY n.id ASC",-1,&_sListNetworkMembers,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT m.authorized,m.activeBridge,n.identity,n.lastAt,n.lastSeen,n.firstSeen FROM Member AS m,Node AS n WHERE m.networkId = ? AND m.nodeId = ?",-1,&_sGetMember2,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT m.nodeId FROM Member AS m WHERE m.networkId = ? ORDER BY m.nodeId ASC",-1,&_sListNetworkMembers,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT m.authorized,m.activeBridge,n.identity,n.lastAt,n.lastSeen,n.firstSeen FROM Member AS m JOIN Node AS n ON n.id = m.nodeId WHERE m.networkId = ? AND m.nodeId = ?",-1,&_sGetMember2,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT ipNetwork,ipNetmaskBits,ipVersion FROM IpAssignmentPool WHERE networkId = ? ORDER BY ipNetwork ASC",-1,&_sGetIpAssignmentPools2,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT ruleId,nodeId,vlanId,vlanPcp,etherType,macSource,macDest,ipSource,ipDest,ipTos,ipProtocol,ipSourcePort,ipDestPort,\"flags\",invFlags,\"action\" FROM Rule WHERE networkId = ? ORDER BY ruleId ASC",-1,&_sListRules,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"INSERT INTO Rule (networkId,ruleId,nodeId,vlanId,vlanPcP,etherType,macSource,macDest,ipSource,ipDest,ipTos,ipProtocol,ipSourcePort,ipDestPort,\"action\") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",-1,&_sCreateRule,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT ruleNo,nodeId,vlanId,vlanPcp,etherType,macSource,macDest,ipSource,ipDest,ipTos,ipProtocol,ipSourcePort,ipDestPort,\"flags\",invFlags,\"action\" FROM Rule WHERE networkId = ? ORDER BY ruleNo ASC",-1,&_sListRules,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"INSERT INTO Rule (networkId,ruleNo,nodeId,vlanId,vlanPcP,etherType,macSource,macDest,ipSource,ipDest,ipTos,ipProtocol,ipSourcePort,ipDestPort,\"action\") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",-1,&_sCreateRule,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"INSERT INTO Network (id,name,creationTime,revision) VALUES (?,?,?,1)",-1,&_sCreateNetwork,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT revision FROM Network WHERE id = ?",-1,&_sGetNetworkRevision,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"UPDATE Network SET revision = ? WHERE id = ?",-1,&_sSetNetworkRevision,(const char **)0) != SQLITE_OK)
@ -178,8 +178,13 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
||(sqlite3_prepare_v2(_db,"DELETE FROM IpAssignmentPool WHERE networkId = ?",-1,&_sDeleteIpAssignmentPoolsForNetwork,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"DELETE FROM Rule WHERE networkId = ?",-1,&_sDeleteRulesForNetwork,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"INSERT INTO IpAssignmentPool (networkId,ipNetwork,ipNetmaskBits,ipVersion) VALUES (?,?,?,?)",-1,&_sCreateIpAssignmentPool,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"UPDATE Member SET authorized = ? WHERE rowid = ?",-1,&_sUpdateMemberAuthorized,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"UPDATE Member SET activeBridge = ? WHERE rowid = ?",-1,&_sUpdateMemberActiveBridge,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"DELETE FROM Member WHERE networkId = ? AND nodeId = ?",-1,&_sDeleteMember,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"DELETE FROM IpAssignment WHERE networkId = ?; DELETE FROM IpAssignmentPool WHERE networkId = ?; DELETE FROM Member WHERE networkId = ?; DELETE FROM MulticastRate WHERE networkId = ?; DELETE FROM Relay WHERE networkId = ?; DELETE FROM Rule WHERE networkId = ?; DELETE FROM Network WHERE id = ?;",-1,&_sDeleteNetworkAndRelated,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"DELETE FROM Network WHERE id = ?",-1,&_sDeleteNetwork,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT ip,ipVersion,metric FROM Gateway WHERE networkId = ? ORDER BY metric ASC",-1,&_sGetGateways,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"DELETE FROM Gateway WHERE networkId = ?",-1,&_sDeleteGateways,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"INSERT INTO Gateway (networkId,ip,ipVersion,metric) VALUES (?,?,?,?)",-1,&_sCreateGateway,(const char **)0) != SQLITE_OK)
) {
//printf("!!! %s\n",sqlite3_errmsg(_db));
sqlite3_close(_db);
@ -199,7 +204,6 @@ SqliteNetworkController::~SqliteNetworkController()
sqlite3_finalize(_sUpdateNode);
sqlite3_finalize(_sUpdateNode2);
sqlite3_finalize(_sGetEtherTypesFromRuleTable);
sqlite3_finalize(_sGetMulticastRates);
sqlite3_finalize(_sGetActiveBridges);
sqlite3_finalize(_sGetIpAssignmentsForNode);
sqlite3_finalize(_sGetIpAssignmentPools);
@ -222,7 +226,13 @@ SqliteNetworkController::~SqliteNetworkController()
sqlite3_finalize(_sDeleteIpAssignmentPoolsForNetwork);
sqlite3_finalize(_sDeleteRulesForNetwork);
sqlite3_finalize(_sCreateIpAssignmentPool);
sqlite3_finalize(_sDeleteNetworkAndRelated);
sqlite3_finalize(_sUpdateMemberAuthorized);
sqlite3_finalize(_sUpdateMemberActiveBridge);
sqlite3_finalize(_sDeleteMember);
sqlite3_finalize(_sDeleteNetwork);
sqlite3_finalize(_sGetGateways);
sqlite3_finalize(_sDeleteGateways);
sqlite3_finalize(_sCreateGateway);
sqlite3_close(_db);
}
}
@ -336,7 +346,7 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
sqlite3_reset(_sCreateMember);
sqlite3_bind_text(_sCreateMember,1,network.id,16,SQLITE_STATIC);
sqlite3_bind_text(_sCreateMember,2,member.nodeId,10,SQLITE_STATIC);
sqlite3_bind_int(_sCreateMember,3,(member.authorized ? 0 : 1));
sqlite3_bind_int(_sCreateMember,3,(member.authorized ? 1 : 0));
if (sqlite3_step(_sCreateMember) != SQLITE_DONE) {
netconf["error"] = "unable to create new member record";
return NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR;
@ -379,6 +389,14 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
if ((et >= 0)&&(et <= 0xffff))
allowedEtherTypes.push_back(et);
}
if (!allowedEtherTypes.size()) {
// Nothing permitted is not usefull
// Just supply a default config allowing ARP, IPv4, IPv6
// allowedEtherTypes.push_back(0); this would allow anything
allowedEtherTypes.push_back(ZT_ETHERTYPE_IPV4);
allowedEtherTypes.push_back(ZT_ETHERTYPE_ARP);
allowedEtherTypes.push_back(ZT_ETHERTYPE_IPV6);
}
std::sort(allowedEtherTypes.begin(),allowedEtherTypes.end());
std::unique(allowedEtherTypes.begin(),allowedEtherTypes.end());
std::string allowedEtherTypesCsv;
@ -392,26 +410,10 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
netconf[ZT_NETWORKCONFIG_DICT_KEY_ALLOWED_ETHERNET_TYPES] = allowedEtherTypesCsv;
}
{
std::string multicastRates;
sqlite3_reset(_sGetMulticastRates);
sqlite3_bind_text(_sGetMulticastRates,1,network.id,16,SQLITE_STATIC);
while (sqlite3_step(_sGetMulticastRates) == SQLITE_ROW) {
const char *mac = (const char *)sqlite3_column_text(_sGetMulticastRates,0);
if ((mac)&&(strlen(mac) == 12)) {
unsigned long adi = ((unsigned long)sqlite3_column_int64(_sGetMulticastRates,1)) & 0xffffffff;
char tmp[256];
Utils::snprintf(tmp,sizeof(tmp),"%s/%.4lx=%x,%x,%x\n",mac,adi,sqlite3_column_int(_sGetMulticastRates,2),sqlite3_column_int(_sGetMulticastRates,3),sqlite3_column_int(_sGetMulticastRates,4));
multicastRates.append(tmp);
}
}
if (multicastRates.length() > 0)
netconf[ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_RATES] = multicastRates;
if (network.multicastLimit > 0) {
char ml[16];
Utils::snprintf(ml,sizeof(ml),"%lx",(unsigned long)network.multicastLimit);
netconf[ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT] = ml;
}
if (network.multicastLimit > 0) {
char ml[16];
Utils::snprintf(ml,sizeof(ml),"%lx",(unsigned long)network.multicastLimit);
netconf[ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT] = ml;
}
{
@ -455,6 +457,52 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
netconf[ZT_NETWORKCONFIG_DICT_KEY_RELAYS] = relays;
}
{
char tmp[128];
std::string gateways;
sqlite3_reset(_sGetGateways);
sqlite3_bind_text(_sGetGateways,1,network.id,16,SQLITE_STATIC);
while (sqlite3_step(_sGetGateways) == SQLITE_ROW) {
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",
(gateways.length() > 0) ? "," : "",
(int)ip[0],
(int)ip[1],
(int)ip[2],
(int)ip[3],
(int)sqlite3_column_int(_sGetGateways,2)); // metric
gateways.append(tmp);
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",
(gateways.length() > 0) ? "," : "",
(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
gateways.append(tmp);
break;
}
}
if (gateways.length())
netconf[ZT_NETWORKCONFIG_DICT_KEY_GATEWAYS] = gateways;
}
if ((network.v4AssignMode)&&(!strcmp(network.v4AssignMode,"zt"))) {
std::string v4s;
@ -467,7 +515,7 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
int ipNetmaskBits = sqlite3_column_int(_sGetIpAssignmentsForNode,1);
if ((ip)&&(sqlite3_column_bytes(_sGetIpAssignmentsForNode,0) >= 4)&&(ipNetmaskBits > 0)&&(ipNetmaskBits <= 32)) {
char tmp[32];
Utils::snprintf(tmp,sizeof(tmp),"%d.%d.%d.%d/%d",(int)ip[0],(int)ip[1],(int)ip[2],(int)ip[3],ipNetmaskBits);
Utils::snprintf(tmp,sizeof(tmp),"%d.%d.%d.%d/%d",(int)ip[12+0],(int)ip[12+1],(int)ip[12+2],(int)ip[12+3],ipNetmaskBits);
if (v4s.length())
v4s.push_back(',');
v4s.append(tmp);
@ -628,29 +676,27 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
if (!strcmp(j->u.object.values[k].name,"authorized")) {
if (j->u.object.values[k].value->type == json_boolean) {
sqlite3_stmt *stmt = (sqlite3_stmt *)0;
if (sqlite3_prepare_v2(_db,"UPDATE Member SET authorized = ? WHERE rowid = ?",-1,&stmt,(const char **)0) == SQLITE_OK)
sqlite3_bind_int(stmt,1,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1);
sqlite3_bind_int64(stmt,2,memberRowId);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
sqlite3_reset(_sUpdateMemberAuthorized);
sqlite3_bind_int(_sUpdateMemberAuthorized,1,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1);
sqlite3_bind_int64(_sUpdateMemberAuthorized,2,memberRowId);
if (sqlite3_step(_sUpdateMemberAuthorized) != SQLITE_DONE)
return 500;
}
} else if (!strcmp(j->u.object.values[k].name,"activeBridge")) {
if (j->u.object.values[k].value->type == json_boolean) {
sqlite3_stmt *stmt = (sqlite3_stmt *)0;
if (sqlite3_prepare_v2(_db,"UPDATE Member SET activeBridge = ? WHERE rowid = ?",-1,&stmt,(const char **)0) == SQLITE_OK) {
sqlite3_bind_int(stmt,1,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1);
sqlite3_bind_int64(stmt,2,memberRowId);
sqlite3_step(stmt);
sqlite3_finalize(stmt);
}
sqlite3_reset(_sUpdateMemberActiveBridge);
sqlite3_bind_int(_sUpdateMemberActiveBridge,1,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1);
sqlite3_bind_int64(_sUpdateMemberActiveBridge,2,memberRowId);
if (sqlite3_step(_sUpdateMemberActiveBridge) != SQLITE_DONE)
return 500;
}
} else if (!strcmp(j->u.object.values[k].name,"ipAssignments")) {
if (j->u.object.values[k].value->type == json_array) {
sqlite3_reset(_sDeleteIpAllocations);
sqlite3_bind_text(_sDeleteIpAllocations,1,nwids,16,SQLITE_STATIC);
sqlite3_bind_text(_sDeleteIpAllocations,2,addrs,10,SQLITE_STATIC);
sqlite3_step(_sDeleteIpAllocations);
if (sqlite3_step(_sDeleteIpAllocations) != SQLITE_DONE)
return 500;
for(unsigned int kk=0;kk<j->u.object.values[k].value->u.array.length;++kk) {
json_value *ipalloc = j->u.object.values[k].value->u.array.values[kk];
if (ipalloc->type == json_string) {
@ -679,7 +725,8 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
sqlite3_bind_blob(_sAllocateIp,3,(const void *)ipBlob,16,SQLITE_STATIC);
sqlite3_bind_int(_sAllocateIp,4,(int)a.netmaskBits());
sqlite3_bind_int(_sAllocateIp,5,ipVersion);
sqlite3_step(_sAllocateIp);
if (sqlite3_step(_sAllocateIp) != SQLITE_DONE)
return 500;
}
}
}
@ -695,6 +742,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
} // else 404
} else {
std::vector<std::string> path_copy(path);
if (!networkExists) {
if (path[1].substr(10) == "______") {
@ -734,6 +782,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
sqlite3_bind_int64(_sCreateNetwork,3,(long long)OSUtils::now());
if (sqlite3_step(_sCreateNetwork) != SQLITE_DONE)
return 500;
path_copy[1].assign(nwids);
}
json_value *j = json_parse(body.c_str(),body.length());
@ -808,6 +857,31 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
sqlite3_step(_sCreateRelay);
}
}
} else if (!strcmp(j->u.object.values[k].name,"gateways")) {
sqlite3_reset(_sDeleteGateways);
sqlite3_bind_text(_sDeleteGateways,1,nwids,16,SQLITE_STATIC);
sqlite3_step(_sDeleteGateways);
if (j->u.object.values[k].value->type == json_array) {
for(unsigned int kk=0;kk<j->u.object.values[k].value->u.array.length;++kk) {
json_value *gateway = j->u.object.values[k].value->u.array.values[kk];
if ((gateway)&&(gateway->type == json_string)) {
InetAddress gwip(gateway->u.string.ptr);
int ipVersion = 0;
if (gwip.ss_family == AF_INET)
ipVersion = 4;
else if (gwip.ss_family == AF_INET6)
ipVersion = 6;
if (ipVersion) {
sqlite3_reset(_sCreateGateway);
sqlite3_bind_text(_sCreateGateway,1,nwids,16,SQLITE_STATIC);
sqlite3_bind_blob(_sCreateGateway,2,gwip.rawIpData(),(gwip.ss_family == AF_INET6) ? 16 : 4,SQLITE_STATIC);
sqlite3_bind_int(_sCreateGateway,3,ipVersion);
sqlite3_bind_int(_sCreateGateway,4,(int)gwip.metric());
sqlite3_step(_sCreateGateway);
}
}
}
}
} else if (!strcmp(j->u.object.values[k].name,"ipAssignmentPools")) {
if (j->u.object.values[k].value->type == json_array) {
std::set<InetAddress> pools;
@ -855,7 +929,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
json_value *rj = j->u.object.values[k].value->u.array.values[kk];
if ((rj)&&(rj->type == json_object)) {
struct { // NULL pointers indicate missing or NULL -- wildcards
const json_int_t *ruleId;
const json_int_t *ruleNo;
const char *nodeId;
const json_int_t *vlanId;
const json_int_t *vlanPcp;
@ -875,8 +949,8 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
memset(&rule,0,sizeof(rule));
for(unsigned int rk=0;rk<rj->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));

View file

@ -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;
};

View file

@ -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);
CREATE UNIQUE INDEX Rule_networkId_ruleNo ON Rule (networkId, ruleNo);

View file

@ -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"\
""

View file

@ -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'

View file

@ -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
};
/**

View file

@ -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;
}

View file

@ -90,7 +90,7 @@ public enum Event {
/**
* A more recent version was observed on the network
*
* <p>Right now this is only triggered if a hub or supernode reports a
* <p>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.</p>
*

View file

@ -39,7 +39,7 @@ public enum PeerRole {
PEER_ROLE_HUB,
/**
* planetary supernode
* planetary rootserver
*/
PEER_ROLE_SUPERNODE
PEER_ROLE_ROOTSERVER
}

View file

@ -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<v.length;++i)
r.push(convertType(v[i],t[0]));
} else r = [ convertType(v,t[0]) ];
} else r = [ v ];
return r;
} else if (t === 'string') {
if (typeof v === 'string')
return v;
else if ((typeof v === 'boolean')||(typeof v === 'number'))
return v.toString();
else if (Array.isArray(v)||(typeof v === 'object'))
return JSON.stringify(v);
else return '';
} else if (t === 'integer') {
if (typeof v === 'number')
return Math.round(v);
else if (typeof v === 'string')
return parseInt(v);
else if (typeof v === 'boolean')
return ((v) ? 1 : 0);
else return 0;
} else if (t === 'number') {
if (typeof v === 'number')
return v;
else if (typeof v === 'string')
return parseFloat(v);
else if (typeof v === 'boolean')
return ((v) ? 1 : 0);
else return 0;
} else if (t === 'boolean') {
return ((v) ? true : false);
} else if (typeof t === 'object') {
if ((v !== null)&&(typeof v === 'object'))
return constrainTypes(v,t);
else return {};
} else return v;
}
function constrainTypes(obj,typeMap)
{
var r = {};
for(var k in obj) {
var t = typeMap[k];
r[k] = convertType(v,t);
}
return r;
}
exports = constrainTypes;

View file

@ -1,231 +0,0 @@
'use strict'
var request = require('request');
var constrainTypes = require('./constrain-types.js');
// Types that fields must be in submissions -- used with constrainTypes to
// ensure that submitted JSON objects are correctly typed since the JSON
// API is very sensitive to this. This only includes writable fields since
// non-writable and unknown fields are ignored.
var REQUEST_TYPE_MAPS = {
'controller/network/*/relay': {
'address': 'string',
'phyAddress': 'string'
},
'controller/network/*/rule': {
'ruleId': 'integer',
'nodeId': 'string',
'vlanId': 'integer',
'vlanPcp': 'integer',
'etherType': 'integer',
'macSource': 'string',
'macDest': 'string',
'ipSource': 'string',
'ipDest': 'string',
'ipTos': 'integer',
'ipProtocol': 'integer',
'ipSourcePort': 'integer',
'ipDestPort': 'integer',
'flags': 'integer',
'invFlags': 'integer',
'action': 'string'
},
'controller/network/*/ipAssignmentPool': {
'network': 'string',
'netmaskBits': 'integer'
},
'controller/network/*/member': {
'authorized': 'boolean',
'activeBridge': 'boolean',
'ipAssignments': [ 'string' ]
},
'controller/network/*': {
'name': 'string',
'private': 'boolean',
'enableBroadcast': 'boolean',
'allowPassiveBridging': 'boolean',
'v4AssignMode': 'string',
'v6AssignMode': 'string',
'multicastLimit': 'integer',
'relays': [ this['controller/network/*/relay'] ],
'ipAssignmentPools': [ this['controller/network/*/ipAssignmentPool'] ],
'rules': [ this['controller/network/*/rule'] ]
}
};
// URL must end with trailing slash e.g. http://127.0.0.1:9993/
function ZT1ApiClient(url,authToken)
{
this.url = url;
this.authToken = authToken;
}
// Simple JSON URI getter, for internal use.
ZT1ApiClient.prototype._jsonGet = function(getPath,callback)
{
request({
url: this.url + getPath,
method: 'GET',
headers: {
'X-ZT1-Auth': this.authToken
}
},function(error,response,body) {
if (error)
return callback(error,null);
if (response.statusCode !== 200)
return callback(new Error('server responded with error: '+response.statusCode),null);
return callback(null,(typeof body === 'string') ? JSON.parse(body) : null);
});
};
// Generate new ZeroTier identity -- mostly for testing
ZT1ApiClient.prototype.newIdentity = function(callback)
{
request({
url: this.url + 'newIdentity',
method: 'GET',
json: false,
headers: {
'X-ZT1-Auth': this.authToken
}
},function(error,response,body) {
if (error)
return callback(error,null);
if (response.statusCode === 200)
return callback(null,body);
return callback(new Error('server responded with error: '+response.statusCode),'');
});
}
// Get node status -- returns a combination of regular status and (if present) controller info
ZT1ApiClient.prototype.status = function(callback)
{
request({
url: this.url + 'controller',
method: 'GET',
headers: {
'X-ZT1-Auth': this.authToken
}
},function(error,response,body) {
if (error)
return callback(error,null);
var controllerStatus = {};
if ((typeof body === 'string')&&(response.statusCode === 200))
controllerStatus = JSON.parse(body);
request({
url: this.url + 'status',
method: 'GET',
headers: {
'X-ZT1-Auth': this.authToken
}
},function(error,response,body) {
if (error)
return callback(error,{});
if (response.statusCode !== 200)
return callback(new Error('server responded with '+response.statusCode),{});
var nodeStatus = JSON.parse(body);
for(var k in controllerStatus)
nodeStatus[k] = controllerStatus[k];
return callback(null,nodeStatus);
}.bind(this));
}.bind(this));
};
ZT1ApiClient.prototype.getNetworks = function(callback)
{
this._jsonGet('network',callback);
};
ZT1ApiClient.prototype.getPeers = function(callback)
{
this._jsonGet('peer',callback);
};
ZT1ApiClient.prototype.listControllerNetworks = function(callback)
{
this._jsonGet('controller/network',callback);
};
ZT1ApiClient.prototype.getControllerNetwork = function(nwid,callback)
{
this._jsonGet('controller/network/' + nwid,callback);
};
// If NWID is the special ##########______ format, a new NWID will
// be generated server side and filled in in returned object.
ZT1ApiClient.prototype.saveControllerNetwork = function(network,callback)
{
request({
url: this.url + 'controller/network/' + n.nwid,
method: 'POST',
json: true,
body: constrainTypes(network,REQUEST_TYPE_MAPS['controller/network/*']),
headers: {
'X-ZT1-Auth': this.authToken
}
},function(err,response,body) {
if (err)
return callback(err,null);
if (response.statusCode !== 200)
return callback(new Error('server responded with error: '+response.statusCode),null);
return callback(null,(typeof body === 'string') ? JSON.parse(body) : body);
});
};
ZT1ApiClient.prototype.deleteControllerNetwork = function(nwid,callback) {
request({
url: this.url + 'controller/network/'+ nwid,
method: 'DELETE',
headers: {
'X-ZT1-Auth': this.authToken
}
},function(err,response,body) {
if (err)
return callback(err);
else if (response.statusCode === 200)
return callback(null);
else return callback(new Error('server responded with error: '+response.statusCode));
});
};
ZT1ApiClient.prototype.getControllerNetworkMember = function(nwid,address,callback) {
this._jsonGet('controller/network/' + nwid + '/member/' + address,callback);
};
ZT1ApiClient.prototype.saveControllerNetworkMember = function(nwid,member,callback) {
var m = constrainTypes(member,REQUEST_TYPE_MAPS['controller/network/*/member']);
m.nwid = nwid;
request({
url: this.url + 'controller/network' + nwid + '/member/' + member.address,
method: 'POST',
json: true,
body: m,
headers: {
'X-ZT1-Auth': this.authToken
}
},function(err,response,body) {
if (err)
return callback(err,null);
if (response.statusCode !== 200)
return callback(new Error('server responded with error: '+response.statusCode),null);
return callback(null,(typeof body === 'string') ? JSON.parse(body) : body);
});
};
ZT1ApiClient.prototype.deleteControllerNetworkMember = function(nwid,address,callback) {
request({
url: this.url + 'controller/network/' + nwid + '/member/' + address,
method: 'DELETE',
headers: {
'X-ZT1-Auth': this.authToken
}
},function(err,response,body) {
if (err)
return callback(err);
else if (response.statusCode === 200)
return callback(null);
else return callback(new Error('server responded with error: '+response.statusCode));
});
};
exports.ZT1ApiClient = ZT1ApiClient;

View file

@ -1,15 +0,0 @@
{
"name": "zt1-api-client",
"version": "0.0.1",
"description": "ZeroTier One JSON API Client",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "ZeroTier, Inc.",
"license": "BSD",
"dependencies": {
"async": "^0.9.0",
"request": "^2.55.0"
}
}

View file

@ -254,7 +254,7 @@
/**
* Delay between scans of the topology active peer DB for peers that need ping
*
* This is also how often pings will be retried to upstream peers (supernodes)
* This is also how often pings will be retried to upstream peers (relays, roots)
* constantly until something is heard.
*/
#define ZT_PING_CHECK_INVERVAL 6250
@ -279,9 +279,9 @@
*
* When we send something (including frames), we generally expect a response.
* Switching relays if no response in a short period of time causes more
* rapid failover if a supernode goes down or becomes unreachable. In the
* rapid failover if a root server goes down or becomes unreachable. In the
* mistaken case, little harm is done as it'll pick the next-fastest
* supernode and will switch back eventually.
* root server and will switch back eventually.
*/
#define ZT_PEER_RELAY_CONVERSATION_LATENCY_THRESHOLD 10000

View file

@ -32,9 +32,8 @@
namespace ZeroTier {
void Dictionary::fromString(const char *s,unsigned int maxlen)
void Dictionary::updateFromString(const char *s,unsigned int maxlen)
{
clear();
bool escapeState = false;
std::string keyBuf;
std::string *element = &keyBuf;
@ -75,6 +74,12 @@ void Dictionary::fromString(const char *s,unsigned int maxlen)
(*this)[keyBuf];
}
void Dictionary::fromString(const char *s,unsigned int maxlen)
{
clear();
updateFromString(s,maxlen);
}
bool Dictionary::sign(const Identity &id,uint64_t now)
{
try {

View file

@ -259,6 +259,9 @@ public:
*/
void fromString(const char *s,unsigned int maxlen);
inline void fromString(const std::string &s) { fromString(s.c_str(),(unsigned int)s.length()); }
void updateFromString(const char *s,unsigned int maxlen);
inline void update(const char *s,unsigned int maxlen) { updateFromString(s, maxlen); }
inline void update(const std::string &s) { updateFromString(s.c_str(),(unsigned int)s.length()); }
/**
* @return True if this dictionary is cryptographically signed

View file

@ -110,7 +110,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
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> network(RR->node->network(at<uint64_t>(ZT_PROTO_VERB_ERROR_IDX_PAYLOAD)));
@ -128,7 +128,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,const SharedPtr<Peer>
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<Peer> &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<Peer> &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<Peer>(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 {

View file

@ -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
*/

View file

@ -216,7 +216,7 @@ void Multicaster::send(
if ((now - gs.lastExplicitGather) >= ZT_MULTICAST_EXPLICIT_GATHER_DELAY) {
gs.lastExplicitGather = now;
SharedPtr<Peer> sn(RR->topology->getBestSupernode());
SharedPtr<Peer> 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<Peer> 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<uint64_t,MulticastGroup>,MulticastGroupStatus >::iterator mm(_groups.begin());mm!=_groups.end();) {
for(std::list<OutboundMulticast>::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<OutboundMulticast>::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<OutboundMulticast>::iterator tx(gs.txQueue.begin());tx!=gs.txQueue.end();) {
for(std::vector<OutboundMulticast>::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;
}
}
}

View file

@ -70,7 +70,7 @@ private:
MulticastGroupStatus() : lastExplicitGather(0) {}
uint64_t lastExplicitGather;
std::list<OutboundMulticast> txQueue; // pending outbound multicasts
std::vector<OutboundMulticast> txQueue; // pending outbound multicasts
std::vector<MulticastGroupMember> members; // members of this group
};

View file

@ -286,18 +286,28 @@ void Network::addMembershipCertificate(const CertificateOfMembership &cert,bool
return;
}
SharedPtr<Peer> 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<Peer> 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<Peer> &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<MulticastGroup>::iterator mg(_allMulticastGroups.begin());mg!=_allMulticastGroups.end();++mg) {
@ -551,7 +547,7 @@ private:
const RuntimeEnvironment *RR;
uint64_t _now;
Network *_network;
std::vector<Address> _supernodeAddresses;
std::vector<Address> _rootAddresses;
std::vector<MulticastGroup> _allMulticastGroups;
};

View file

@ -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<MAC,Address> _remoteBridgeRoutes; // remote addresses where given MACs are reachable

View file

@ -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> NetworkConfig::createTestNetworkConfig(const Address &self)
{
SharedPtr<NetworkConfig> nc(new NetworkConfig());
@ -85,18 +81,6 @@ std::vector<unsigned int> NetworkConfig::allowedEtherTypes() const
return ets;
}
const NetworkConfig::MulticastRate &NetworkConfig::multicastRate(const MulticastGroup &mg) const
throw()
{
std::map<MulticastGroup,MulticastRate>::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<std::string> gatewaysSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_GATEWAYS,"").c_str(),",","",""));
for(std::vector<std::string>::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<std::string> activeBridgesSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_ACTIVE_BRIDGES,"").c_str(),",","",""));
for(std::vector<std::string>::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<std::string> 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<std::string> relaysSplit(Utils::split(d.get(ZT_NETWORKCONFIG_DICT_KEY_RELAYS,"").c_str(),",","",""));
for(std::vector<std::string>::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<MulticastGroup,MulticastRate>::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;
}

View file

@ -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<NetworkConfig>;
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<MulticastGroup,MulticastRate> &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<InetAddress> &staticIps() const throw() { return _staticIps; }
inline const std::vector<InetAddress> &gateways() const throw() { return _gateways; }
inline const std::vector<Address> &activeBridges() const throw() { return _activeBridges; }
inline const std::vector< std::pair<Address,InetAddress> > &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<InetAddress> _staticIps;
std::vector<InetAddress> _gateways;
std::vector<Address> _activeBridges;
std::vector< std::pair<Address,InetAddress> > _relays;
std::map<MulticastGroup,MulticastRate> _multicastRates;
CertificateOfMembership _com;
AtomicCounter __refCount;

View file

@ -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<Address,InetAddress> > &_relays;
std::vector<Address> _supernodes;
std::vector<Address> _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<Network> > needConfig;
{
Mutex::Lock _l(_networks_m);
for(std::map< uint64_t,SharedPtr<Network> >::const_iterator n(_networks.begin());n!=_networks.end();++n) {
for(std::vector< std::pair< uint64_t,SharedPtr<Network> > >::const_iterator n(_networks.begin());n!=_networks.end();++n) {
SharedPtr<NetworkConfig> 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<Network> &nwe = _networks[nwid];
if (!nwe)
nwe = SharedPtr<Network>(new Network(RR,nwid));
SharedPtr<Network> nw = _network(nwid);
if(!nw)
_networks.push_back(std::pair< uint64_t,SharedPtr<Network> >(nwid,SharedPtr<Network>(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<Network> > > newn;
Mutex::Lock _l(_networks_m);
std::map< uint64_t,SharedPtr<Network> >::iterator nw(_networks.find(nwid));
if (nw != _networks.end()) {
nw->second->destroy();
_networks.erase(nw);
for(std::vector< std::pair< uint64_t,SharedPtr<Network> > >::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<Path> 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<Network> >::const_iterator nw(_networks.find(nwid));
if (nw != _networks.end()) {
SharedPtr<Network> 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<Network> >::const_iterator n(_networks.begin());n!=_networks.end();++n)
for(std::vector< std::pair< uint64_t,SharedPtr<Network> > >::const_iterator n(_networks.begin());n!=_networks.end();++n)
n->second->externalConfig(&(nl->networks[nl->networkCount++]));
return nl;

View file

@ -155,19 +155,19 @@ public:
len);
}
inline SharedPtr<Network> network(uint64_t nwid)
inline SharedPtr<Network> network(uint64_t nwid) const
{
Mutex::Lock _l(_networks_m);
std::map< uint64_t,SharedPtr<Network> >::iterator nw(_networks.find(nwid));
return ((nw == _networks.end()) ? SharedPtr<Network>() : nw->second);
return _network(nwid);
}
inline std::vector< SharedPtr<Network> > allNetworks() const
{
Mutex::Lock _l(_networks_m);
std::vector< SharedPtr<Network> > nw;
for(std::map< uint64_t,SharedPtr<Network> >::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<Network> > >::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> _network(uint64_t nwid) const
{
// assumes _networks_m is locked
for(std::vector< std::pair< uint64_t, SharedPtr<Network> > >::const_iterator i=_networks.begin();i!=_networks.end();++i) {
if (i->first == nwid)
return i->second;
}
return SharedPtr<Network>();
}
RuntimeEnvironment _RR;
RuntimeEnvironment *RR;
@ -223,7 +233,7 @@ private:
//Dictionary _localConfig; // persisted as local.conf
//Mutex _localConfig_m;
std::map< uint64_t,SharedPtr<Network> > _networks;
std::vector< std::pair< uint64_t, SharedPtr<Network> > > _networks;
Mutex _networks_m;
Mutex _backgroundTasksLock;

View file

@ -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)";
}

View file

@ -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
};
/**

View file

@ -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<Network> > networks(RR->node->allNetworks());
for(std::vector< SharedPtr<Network> >::const_iterator n(networks.begin());n!=networks.end();++n) {
if ( (isSupernode) || ((*n)->isAllowed(_id.address())) ) {
if ( (isRoot) || ((*n)->isAllowed(_id.address())) ) {
const std::vector<MulticastGroup> mgs((*n)->allMulticastGroups());
for(std::vector<MulticastGroup>::const_iterator mg(mgs.begin());mg!=mgs.end();++mg) {
if ((outp.size() + 18) > ZT_UDP_DEFAULT_PAYLOAD_MTU) {

View file

@ -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<Peer> sn(RR->topology->getBestSupernode());
SharedPtr<Peer> sn(RR->topology->getBestRoot());
if (sn) {
Path *snp = sn->getBestPath(now);
if (snp) {

View file

@ -145,12 +145,6 @@ void Switch::onLocalEthernet(const SharedPtr<Network> &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<Peer> 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<ZT_PROTO_BEA
Address Switch::_sendWhoisRequest(const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted)
{
SharedPtr<Peer> supernode(RR->topology->getBestSupernode(peersAlreadyConsulted,numPeersAlreadyConsulted,false));
if (supernode) {
Packet outp(supernode->address(),RR->identity.address(),Packet::VERB_WHOIS);
SharedPtr<Peer> 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;

View file

@ -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<InetAddress> > &sn)
void Topology::setRootServers(const std::map< Identity,std::vector<InetAddress> > &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<InetAddress> >::const_iterator i(sn.begin());i!=sn.end();++i) {
@ -64,17 +64,17 @@ void Topology::setSupernodes(const std::map< Identity,std::vector<InetAddress> >
for(std::vector<InetAddress>::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<InetAddress> > 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<Peer> Topology::addPeer(const SharedPtr<Peer> &peer)
@ -141,28 +141,28 @@ SharedPtr<Peer> Topology::getPeer(const Address &zta)
return SharedPtr<Peer>();
}
SharedPtr<Peer> Topology::getBestSupernode(const Address *avoid,unsigned int avoidCount,bool strictAvoid)
SharedPtr<Peer> Topology::getBestRoot(const Address *avoid,unsigned int avoidCount,bool strictAvoid)
{
SharedPtr<Peer> bestSupernode;
SharedPtr<Peer> 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<Address>::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<Address>::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<Peer> >::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<Peer> 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<Peer> >::const_iterator sn(_supernodePeers.begin());sn!=_supernodePeers.end();) {
for(std::vector< SharedPtr<Peer> >::const_iterator sn(_rootPeers.begin());sn!=_rootPeers.end();) {
// Skip explicitly avoided relays
for(unsigned int i=0;i<avoidCount;++i) {
if (avoid[i] == (*sn)->address())
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<Peer>();
// If we have nothing from above, just pick one without avoidance criteria.
for(std::vector< SharedPtr<Peer> >::const_iterator sn=_supernodePeers.begin();sn!=_supernodePeers.end();++sn) {
for(std::vector< SharedPtr<Peer> >::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<Peer> >::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;
}

View file

@ -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<InetAddress> > &sn);
void setRootServers(const std::map< Identity,std::vector<InetAddress> > &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<Peer> getPeer(const Address &zta);
/**
* @return Vector of peers that are supernodes
* @return Vector of peers that are root servers
*/
inline std::vector< SharedPtr<Peer> > supernodePeers() const
inline std::vector< SharedPtr<Peer> > 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<Peer> getBestSupernode()
inline SharedPtr<Peer> 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<Peer> getBestSupernode(const Address *avoid,unsigned int avoidCount,bool strictAvoid);
SharedPtr<Peer> 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<Address> supernodeAddresses() const
inline std::vector<Address> rootAddresses() const
{
Mutex::Lock _l(_lock);
return _supernodeAddresses;
return _rootAddresses;
}
/**
@ -206,13 +191,13 @@ private:
const RuntimeEnvironment *RR;
std::map< Address,SharedPtr<Peer> > _activePeers;
std::map< Identity,std::vector<InetAddress> > _supernodes;
std::vector< Address > _supernodeAddresses;
std::vector< SharedPtr<Peer> > _supernodePeers;
std::map< Identity,std::vector<InetAddress> > _roots;
std::vector< Address > _rootAddresses;
std::vector< SharedPtr<Peer> > _rootPeers;
Mutex _lock;
bool _amSupernode;
bool _amRoot;
};
} // namespace ZeroTier

View file

@ -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<PhySocketImpl>::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<PhySocketImpl>::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<PhySocketImpl>::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<PhySocketImpl *>(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<PhySocketImpl>::iterator s(_socks.begin());s!=_socks.end();++s) {
if (reinterpret_cast<PhySocket *>(&(*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<PhySocketImpl>::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;

View file

@ -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<MulticastGroup> &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;r<ift->NumEntries;++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)

View file

@ -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<MulticastGroup> _multicastGroups;

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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<std::string> supernodeDictionaries(OSUtils::listDirectory("supernodes"));
for(std::vector<std::string>::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<std::string> rootserverDictionaries(OSUtils::listDirectory("rootservers"));
for(std::vector<std::string>::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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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...'

View file

@ -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<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
scode = _controller->handleControlPlaneHttpGET(std::vector<std::string>(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<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
scode = _controller->handleControlPlaneHttpPOST(std::vector<std::string>(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<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
scode = _controller->handleControlPlaneHttpDELETE(std::vector<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
else scode = 404;
#else
scode = 404;

View file

@ -106,7 +106,7 @@ Getting /peer returns an array of peer objects for all current peers. See below
<tr><td>versionRev</td><td>integer</td><td>Revision of remote if known</td><td>no</td></tr>
<tr><td>version</td><td>string</td><td>Version in major.minor.rev format</td><td>no</td></tr>
<tr><td>latency</td><td>integer</td><td>Latency in milliseconds if known</td><td>no</td></tr>
<tr><td>role</td><td>string</td><td>LEAF, HUB, or SUPERNODE</td><td>no</td></tr>
<tr><td>role</td><td>string</td><td>LEAF, HUB, or ROOTSERVER</td><td>no</td></tr>
<tr><td>paths</td><td>[object]</td><td>Array of path objects (see below)</td><td>no</td></tr>
</table>
@ -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.
<table>
<tr><td><b>Field</b></td><td><b>Type</b></td><td><b>Description</b></td></tr>
@ -204,7 +204,7 @@ Relay objects define network-specific preferred relay nodes. Traffic to peers on
* **Note**: at the moment, <u>only rules specifying allowed Ethernet types are used</u>. The database supports a richer rule set, but this is not implemented yet in the client. <u>Other types of rules will have no effect</u> (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
<table>
<tr><td><b>Field</b></td><td><b>Type</b></td><td><b>Description</b></td></tr>
<tr><td>ruleId</td><td>integer</td><td>User-defined rule ID and sort order</td></tr>
<tr><td>ruleNo</td><td>integer</td><td>User-defined rule ID and sort order</td></tr>
<tr><td>nodeId</td><td>string</td><td>10-digit hex ZeroTier address of node (a.k.a. "port on switch")</td></tr>
<tr><td>vlanId</td><td>integer</td><td>Ethernet VLAN ID</td></tr>
<tr><td>vlanPcp</td><td>integer</td><td>Ethernet VLAN priority code point (PCP) ID</td></tr>

View file

@ -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