Merge branch 'adamierymenko-dev' into android-jni

This commit is contained in:
Grant Limberg 2015-06-13 14:39:45 -07:00
commit c59c74ddda
14 changed files with 548 additions and 323 deletions

View File

@ -167,8 +167,8 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
||(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 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)
@ -179,7 +179,10 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
||(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,"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);
@ -222,7 +225,10 @@ SqliteNetworkController::~SqliteNetworkController()
sqlite3_finalize(_sDeleteIpAssignmentPoolsForNetwork);
sqlite3_finalize(_sDeleteRulesForNetwork);
sqlite3_finalize(_sCreateIpAssignmentPool);
sqlite3_finalize(_sDeleteNetworkAndRelated);
sqlite3_finalize(_sDeleteNetwork);
sqlite3_finalize(_sGetGateways);
sqlite3_finalize(_sDeleteGateways);
sqlite3_finalize(_sCreateGateway);
sqlite3_close(_db);
}
}
@ -455,6 +461,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;
@ -808,6 +860,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 +932,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 +952,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 +986,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)
@ -993,6 +1070,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 +1082,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 +1104,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
@ -1202,6 +1289,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 +1353,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

@ -123,7 +123,10 @@ private:
sqlite3_stmt *_sDeleteRulesForNetwork;
sqlite3_stmt *_sCreateIpAssignmentPool;
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,70 @@ 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 MulticastRate (
networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
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 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 +104,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,70 @@
" 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 MulticastRate (\n"\
" networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\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 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 +105,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

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

@ -163,6 +163,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
@ -211,7 +218,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 (_relays != nc._relays) 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.

View File

@ -49,24 +49,61 @@ 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"
// dictionary of one or more of: MAC/ADI=preload,maxbalance,accrual
#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
*
@ -146,6 +183,7 @@ public:
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; }
@ -188,6 +226,7 @@ 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;

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

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

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

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