Merge branch 'adamierymenko-dev' into android-jni

This commit is contained in:
Grant Limberg 2015-07-16 18:09:57 -07:00
commit 1e8ead441c
20 changed files with 237 additions and 133 deletions

View file

@ -108,6 +108,7 @@ struct NetworkRecord {
int multicastLimit; int multicastLimit;
uint64_t creationTime; uint64_t creationTime;
uint64_t revision; uint64_t revision;
uint64_t memberRevisionCounter;
}; };
} // anonymous namespace } // anonymous namespace
@ -149,12 +150,13 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
if ( if (
/* Network */ /* Network */
(sqlite3_prepare_v2(_db,"SELECT name,private,enableBroadcast,allowPassiveBridging,v4AssignMode,v6AssignMode,multicastLimit,creationTime,revision FROM Network WHERE id = ?",-1,&_sGetNetworkById,(const char **)0) != SQLITE_OK) (sqlite3_prepare_v2(_db,"SELECT name,private,enableBroadcast,allowPassiveBridging,v4AssignMode,v6AssignMode,multicastLimit,creationTime,revision,memberRevisionCounter FROM Network WHERE id = ?",-1,&_sGetNetworkById,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT revision FROM Network WHERE id = ?",-1,&_sGetNetworkRevision,(const char **)0) != SQLITE_OK) ||(sqlite3_prepare_v2(_db,"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) ||(sqlite3_prepare_v2(_db,"UPDATE Network SET revision = ? WHERE id = ?",-1,&_sSetNetworkRevision,(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,"INSERT INTO Network (id,name,creationTime,revision) VALUES (?,?,?,1)",-1,&_sCreateNetwork,(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,"DELETE FROM Network WHERE id = ?",-1,&_sDeleteNetwork,(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 id FROM Network ORDER BY id ASC",-1,&_sListNetworks,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"UPDATE Network SET memberRevisionCounter = (memberRevisionCounter + 1) WHERE id = ?",-1,&_sIncrementMemberRevisionCounter,(const char **)0) != SQLITE_OK)
/* Node */ /* Node */
||(sqlite3_prepare_v2(_db,"SELECT identity FROM Node WHERE id = ?",-1,&_sGetNodeIdentity,(const char **)0) != SQLITE_OK) ||(sqlite3_prepare_v2(_db,"SELECT identity FROM Node WHERE id = ?",-1,&_sGetNodeIdentity,(const char **)0) != SQLITE_OK)
@ -188,12 +190,12 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
/* Member */ /* Member */
||(sqlite3_prepare_v2(_db,"SELECT rowid,authorized,activeBridge FROM Member WHERE networkId = ? AND nodeId = ?",-1,&_sGetMember,(const char **)0) != SQLITE_OK) ||(sqlite3_prepare_v2(_db,"SELECT rowid,authorized,activeBridge FROM Member WHERE networkId = ? AND nodeId = ?",-1,&_sGetMember,(const char **)0) != SQLITE_OK)
||(sqlite3_prepare_v2(_db,"SELECT m.authorized,m.activeBridge,n.identity 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 m.authorized,m.activeBridge,m.memberRevision,n.identity 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,"INSERT INTO Member (networkId,nodeId,authorized,activeBridge) VALUES (?,?,?,0)",-1,&_sCreateMember,(const char **)0) != SQLITE_OK) ||(sqlite3_prepare_v2(_db,"INSERT INTO Member (networkId,nodeId,authorized,activeBridge,memberRevision) VALUES (?,?,?,0,(SELECT memberRevisionCounter FROM Network WHERE id = ?))",-1,&_sCreateMember,(const char **)0) != SQLITE_OK)
||(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 nodeId FROM Member WHERE networkId = ? AND activeBridge > 0 AND authorized > 0",-1,&_sGetActiveBridges,(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.nodeId FROM Member AS m WHERE m.networkId = ? ORDER BY m.nodeId ASC",-1,&_sListNetworkMembers,(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 authorized = ?,memberRevision = (SELECT memberRevisionCounter FROM Network WHERE id = ?) 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,"UPDATE Member SET activeBridge = ?,memberRevision = (SELECT memberRevisionCounter FROM Network WHERE id = ?) 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 Member WHERE networkId = ? AND nodeId = ?",-1,&_sDeleteMember,(const char **)0) != SQLITE_OK)
/* Gateway */ /* Gateway */
@ -251,6 +253,7 @@ SqliteNetworkController::~SqliteNetworkController()
sqlite3_finalize(_sGetGateways); sqlite3_finalize(_sGetGateways);
sqlite3_finalize(_sDeleteGateways); sqlite3_finalize(_sDeleteGateways);
sqlite3_finalize(_sCreateGateway); sqlite3_finalize(_sCreateGateway);
sqlite3_finalize(_sIncrementMemberRevisionCounter);
sqlite3_close(_db); sqlite3_close(_db);
} }
} }
@ -316,6 +319,7 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
network.multicastLimit = sqlite3_column_int(_sGetNetworkById,6); network.multicastLimit = sqlite3_column_int(_sGetNetworkById,6);
network.creationTime = (uint64_t)sqlite3_column_int64(_sGetNetworkById,7); network.creationTime = (uint64_t)sqlite3_column_int64(_sGetNetworkById,7);
network.revision = (uint64_t)sqlite3_column_int64(_sGetNetworkById,8); network.revision = (uint64_t)sqlite3_column_int64(_sGetNetworkById,8);
network.memberRevisionCounter = (uint64_t)sqlite3_column_int64(_sGetNetworkById,9);
} else return NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND; } else return NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND;
// Fetch Member record // Fetch Member record
@ -340,11 +344,16 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
sqlite3_bind_text(_sCreateMember,1,network.id,16,SQLITE_STATIC); sqlite3_bind_text(_sCreateMember,1,network.id,16,SQLITE_STATIC);
sqlite3_bind_text(_sCreateMember,2,member.nodeId,10,SQLITE_STATIC); sqlite3_bind_text(_sCreateMember,2,member.nodeId,10,SQLITE_STATIC);
sqlite3_bind_int(_sCreateMember,3,(member.authorized ? 1 : 0)); sqlite3_bind_int(_sCreateMember,3,(member.authorized ? 1 : 0));
sqlite3_bind_text(_sCreateMember,4,network.id,16,SQLITE_STATIC);
if (sqlite3_step(_sCreateMember) != SQLITE_DONE) { if (sqlite3_step(_sCreateMember) != SQLITE_DONE) {
netconf["error"] = "unable to create new member record"; netconf["error"] = "unable to create new member record";
return NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR; return NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR;
} }
member.rowid = (int64_t)sqlite3_last_insert_rowid(_db); member.rowid = (int64_t)sqlite3_last_insert_rowid(_db);
sqlite3_reset(_sIncrementMemberRevisionCounter);
sqlite3_bind_text(_sIncrementMemberRevisionCounter,1,network.id,16,SQLITE_STATIC);
sqlite3_step(_sIncrementMemberRevisionCounter);
} }
// Check member authorization // Check member authorization
@ -683,9 +692,14 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
sqlite3_bind_text(_sCreateMember,1,nwids,16,SQLITE_STATIC); sqlite3_bind_text(_sCreateMember,1,nwids,16,SQLITE_STATIC);
sqlite3_bind_text(_sCreateMember,2,addrs,10,SQLITE_STATIC); sqlite3_bind_text(_sCreateMember,2,addrs,10,SQLITE_STATIC);
sqlite3_bind_int(_sCreateMember,3,0); sqlite3_bind_int(_sCreateMember,3,0);
sqlite3_bind_text(_sCreateMember,4,nwids,16,SQLITE_STATIC);
if (sqlite3_step(_sCreateMember) != SQLITE_DONE) if (sqlite3_step(_sCreateMember) != SQLITE_DONE)
return 500; return 500;
memberRowId = (int64_t)sqlite3_last_insert_rowid(_db); memberRowId = (int64_t)sqlite3_last_insert_rowid(_db);
sqlite3_reset(_sIncrementMemberRevisionCounter);
sqlite3_bind_text(_sIncrementMemberRevisionCounter,1,nwids,16,SQLITE_STATIC);
sqlite3_step(_sIncrementMemberRevisionCounter);
} }
json_value *j = json_parse(body.c_str(),body.length()); json_value *j = json_parse(body.c_str(),body.length());
@ -697,17 +711,27 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
if (j->u.object.values[k].value->type == json_boolean) { if (j->u.object.values[k].value->type == json_boolean) {
sqlite3_reset(_sUpdateMemberAuthorized); sqlite3_reset(_sUpdateMemberAuthorized);
sqlite3_bind_int(_sUpdateMemberAuthorized,1,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1); sqlite3_bind_int(_sUpdateMemberAuthorized,1,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1);
sqlite3_bind_int64(_sUpdateMemberAuthorized,2,memberRowId); sqlite3_bind_text(_sUpdateMemberAuthorized,2,nwids,16,SQLITE_STATIC);
sqlite3_bind_int64(_sUpdateMemberAuthorized,3,memberRowId);
if (sqlite3_step(_sUpdateMemberAuthorized) != SQLITE_DONE) if (sqlite3_step(_sUpdateMemberAuthorized) != SQLITE_DONE)
return 500; return 500;
sqlite3_reset(_sIncrementMemberRevisionCounter);
sqlite3_bind_text(_sIncrementMemberRevisionCounter,1,nwids,16,SQLITE_STATIC);
sqlite3_step(_sIncrementMemberRevisionCounter);
} }
} else if (!strcmp(j->u.object.values[k].name,"activeBridge")) { } else if (!strcmp(j->u.object.values[k].name,"activeBridge")) {
if (j->u.object.values[k].value->type == json_boolean) { if (j->u.object.values[k].value->type == json_boolean) {
sqlite3_reset(_sUpdateMemberActiveBridge); sqlite3_reset(_sUpdateMemberActiveBridge);
sqlite3_bind_int(_sUpdateMemberActiveBridge,1,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1); sqlite3_bind_int(_sUpdateMemberActiveBridge,1,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1);
sqlite3_bind_int64(_sUpdateMemberActiveBridge,2,memberRowId); sqlite3_bind_text(_sUpdateMemberActiveBridge,2,nwids,16,SQLITE_STATIC);
sqlite3_bind_int64(_sUpdateMemberActiveBridge,3,memberRowId);
if (sqlite3_step(_sUpdateMemberActiveBridge) != SQLITE_DONE) if (sqlite3_step(_sUpdateMemberActiveBridge) != SQLITE_DONE)
return 500; return 500;
sqlite3_reset(_sIncrementMemberRevisionCounter);
sqlite3_bind_text(_sIncrementMemberRevisionCounter,1,nwids,16,SQLITE_STATIC);
sqlite3_step(_sIncrementMemberRevisionCounter);
} }
} else if (!strcmp(j->u.object.values[k].name,"ipAssignments")) { } else if (!strcmp(j->u.object.values[k].name,"ipAssignments")) {
if (j->u.object.values[k].value->type == json_array) { if (j->u.object.values[k].value->type == json_array) {
@ -778,6 +802,8 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
uint64_t nwidOriginalPostfix = nwidPostfix; uint64_t nwidOriginalPostfix = nwidPostfix;
do { do {
uint64_t tryNwid = nwidPrefix | nwidPostfix; uint64_t tryNwid = nwidPrefix | nwidPostfix;
if (!nwidPostfix)
tryNwid |= 1;
Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)tryNwid); Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)tryNwid);
sqlite3_reset(_sGetNetworkRevision); sqlite3_reset(_sGetNetworkRevision);
@ -799,7 +825,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
sqlite3_reset(_sCreateNetwork); sqlite3_reset(_sCreateNetwork);
sqlite3_bind_text(_sCreateNetwork,1,nwids,16,SQLITE_STATIC); sqlite3_bind_text(_sCreateNetwork,1,nwids,16,SQLITE_STATIC);
sqlite3_bind_text(_sCreateNetwork,2,nwids,16,SQLITE_STATIC); // default name, will be changed below if a name is specified in JSON sqlite3_bind_text(_sCreateNetwork,2,"",0,SQLITE_STATIC);
sqlite3_bind_int64(_sCreateNetwork,3,(long long)OSUtils::now()); sqlite3_bind_int64(_sCreateNetwork,3,(long long)OSUtils::now());
if (sqlite3_step(_sCreateNetwork) != SQLITE_DONE) if (sqlite3_step(_sCreateNetwork) != SQLITE_DONE)
return 500; return 500;
@ -1230,13 +1256,15 @@ unsigned int SqliteNetworkController::_doCPGet(
"\t\"address\": \"%s\",\n" "\t\"address\": \"%s\",\n"
"\t\"authorized\": %s,\n" "\t\"authorized\": %s,\n"
"\t\"activeBridge\": %s,\n" "\t\"activeBridge\": %s,\n"
"\t\"memberRevision\": %llu,\n"
"\t\"identity\": \"%s\",\n" "\t\"identity\": \"%s\",\n"
"\t\"ipAssignments\": [", "\t\"ipAssignments\": [",
nwids, nwids,
addrs, addrs,
(sqlite3_column_int(_sGetMember2,0) > 0) ? "true" : "false", (sqlite3_column_int(_sGetMember2,0) > 0) ? "true" : "false",
(sqlite3_column_int(_sGetMember2,1) > 0) ? "true" : "false", (sqlite3_column_int(_sGetMember2,1) > 0) ? "true" : "false",
_jsonEscape((const char *)sqlite3_column_text(_sGetMember2,2)).c_str()); (unsigned long long)sqlite3_column_int64(_sGetMember2,2),
_jsonEscape((const char *)sqlite3_column_text(_sGetMember2,3)).c_str());
responseBody = json; responseBody = json;
sqlite3_reset(_sGetIpAssignmentsForNode2); sqlite3_reset(_sGetIpAssignmentsForNode2);
@ -1333,6 +1361,7 @@ unsigned int SqliteNetworkController::_doCPGet(
"\t\"multicastLimit\": %d,\n" "\t\"multicastLimit\": %d,\n"
"\t\"creationTime\": %llu,\n" "\t\"creationTime\": %llu,\n"
"\t\"revision\": %llu,\n" "\t\"revision\": %llu,\n"
"\t\"memberRevisionCounter\": %llu,\n"
"\t\"members\": [", "\t\"members\": [",
nwids, nwids,
_jsonEscape((const char *)sqlite3_column_text(_sGetNetworkById,0)).c_str(), _jsonEscape((const char *)sqlite3_column_text(_sGetNetworkById,0)).c_str(),
@ -1343,7 +1372,8 @@ unsigned int SqliteNetworkController::_doCPGet(
_jsonEscape((const char *)sqlite3_column_text(_sGetNetworkById,5)).c_str(), _jsonEscape((const char *)sqlite3_column_text(_sGetNetworkById,5)).c_str(),
sqlite3_column_int(_sGetNetworkById,6), sqlite3_column_int(_sGetNetworkById,6),
(unsigned long long)sqlite3_column_int64(_sGetNetworkById,7), (unsigned long long)sqlite3_column_int64(_sGetNetworkById,7),
(unsigned long long)sqlite3_column_int64(_sGetNetworkById,8)); (unsigned long long)sqlite3_column_int64(_sGetNetworkById,8),
(unsigned long long)sqlite3_column_int64(_sGetNetworkById,9));
responseBody = json; responseBody = json;
sqlite3_reset(_sListNetworkMembers); sqlite3_reset(_sListNetworkMembers);

View file

@ -137,6 +137,7 @@ private:
sqlite3_stmt *_sGetGateways; sqlite3_stmt *_sGetGateways;
sqlite3_stmt *_sDeleteGateways; sqlite3_stmt *_sDeleteGateways;
sqlite3_stmt *_sCreateGateway; sqlite3_stmt *_sCreateGateway;
sqlite3_stmt *_sIncrementMemberRevisionCounter;
Mutex _lock; Mutex _lock;
}; };

View file

@ -13,7 +13,8 @@ CREATE TABLE Network (
v6AssignMode varchar(8) NOT NULL DEFAULT('none'), v6AssignMode varchar(8) NOT NULL DEFAULT('none'),
multicastLimit integer NOT NULL DEFAULT(32), multicastLimit integer NOT NULL DEFAULT(32),
creationTime integer NOT NULL DEFAULT(0), creationTime integer NOT NULL DEFAULT(0),
revision integer NOT NULL DEFAULT(1) revision integer NOT NULL DEFAULT(1),
memberRevisionCounter integer NOT NULL DEFAULT(1)
); );
CREATE TABLE Node ( CREATE TABLE Node (
@ -57,10 +58,12 @@ CREATE TABLE Member (
nodeId char(10) NOT NULL REFERENCES Node(id) ON DELETE CASCADE, nodeId char(10) NOT NULL REFERENCES Node(id) ON DELETE CASCADE,
authorized integer NOT NULL DEFAULT(0), authorized integer NOT NULL DEFAULT(0),
activeBridge integer NOT NULL DEFAULT(0), activeBridge integer NOT NULL DEFAULT(0),
memberRevision integer NOT NULL DEFAULT(0),
PRIMARY KEY (networkId, nodeId) PRIMARY KEY (networkId, nodeId)
); );
CREATE INDEX Member_networkId_activeBridge ON Member(networkId, activeBridge); CREATE INDEX Member_networkId_activeBridge ON Member(networkId, activeBridge);
CREATE INDEX Member_networkId_memberRevision ON Member(networkId, memberRevision);
CREATE TABLE Relay ( CREATE TABLE Relay (
networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE, networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,

View file

@ -14,7 +14,8 @@
" v6AssignMode varchar(8) NOT NULL DEFAULT('none'),\n"\ " v6AssignMode varchar(8) NOT NULL DEFAULT('none'),\n"\
" multicastLimit integer NOT NULL DEFAULT(32),\n"\ " multicastLimit integer NOT NULL DEFAULT(32),\n"\
" creationTime integer NOT NULL DEFAULT(0),\n"\ " creationTime integer NOT NULL DEFAULT(0),\n"\
" revision integer NOT NULL DEFAULT(1)\n"\ " revision integer NOT NULL DEFAULT(1),\n"\
" memberRevisionCounter integer NOT NULL DEFAULT(1)\n"\
");\n"\ ");\n"\
"\n"\ "\n"\
"CREATE TABLE Node (\n"\ "CREATE TABLE Node (\n"\
@ -58,10 +59,12 @@
" nodeId char(10) NOT NULL REFERENCES Node(id) ON DELETE CASCADE,\n"\ " nodeId char(10) NOT NULL REFERENCES Node(id) ON DELETE CASCADE,\n"\
" authorized integer NOT NULL DEFAULT(0),\n"\ " authorized integer NOT NULL DEFAULT(0),\n"\
" activeBridge integer NOT NULL DEFAULT(0),\n"\ " activeBridge integer NOT NULL DEFAULT(0),\n"\
" memberRevision integer NOT NULL DEFAULT(0),\n"\
" PRIMARY KEY (networkId, nodeId)\n"\ " PRIMARY KEY (networkId, nodeId)\n"\
");\n"\ ");\n"\
"\n"\ "\n"\
"CREATE INDEX Member_networkId_activeBridge ON Member(networkId, activeBridge);\n"\ "CREATE INDEX Member_networkId_activeBridge ON Member(networkId, activeBridge);\n"\
"CREATE INDEX Member_networkId_memberRevision ON Member(networkId, memberRevision);\n"\
"\n"\ "\n"\
"CREATE TABLE Relay (\n"\ "CREATE TABLE Relay (\n"\
" networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"\ " networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,\n"\

View file

@ -987,10 +987,9 @@ void ZT1_Node_freeQueryResult(ZT1_Node *node,void *qr);
* @param addr Local interface address * @param addr Local interface address
* @param metric Local interface metric * @param metric Local interface metric
* @param trust How much do you trust the local network under this interface? * @param trust How much do you trust the local network under this interface?
* @param reliable If nonzero, this interface doesn't link to anything behind a NAT or stateful firewall
* @return Boolean: non-zero if address was accepted and added * @return Boolean: non-zero if address was accepted and added
*/ */
int ZT1_Node_addLocalInterfaceAddress(ZT1_Node *node,const struct sockaddr_storage *addr,int metric,ZT1_LocalInterfaceAddressTrust trust,int reliable); int ZT1_Node_addLocalInterfaceAddress(ZT1_Node *node,const struct sockaddr_storage *addr,int metric,ZT1_LocalInterfaceAddressTrust trust);
/** /**
* Clear local interface addresses * Clear local interface addresses

View file

@ -305,6 +305,21 @@ public:
*/ */
bool verify(const Identity &id) const; bool verify(const Identity &id) const;
inline bool operator==(const Dictionary &d) const
{
// std::map::operator== is broken on uclibc++
if (size() != d.size())
return false;
const_iterator a(begin());
const_iterator b(d.begin());
while (a != end()) {
if (*(a++) != *(b++))
return false;
}
return true;
}
inline bool operator!=(const Dictionary &d) const { return (!(*this == d)); }
private: private:
void _mkSigBuf(std::string &buf) const; void _mkSigBuf(std::string &buf) const;
static void _appendEsc(const char *data,unsigned int len,std::string &to); static void _appendEsc(const char *data,unsigned int len,std::string &to);

View file

@ -185,18 +185,17 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR)
try { try {
const unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION]; const unsigned int protoVersion = (*this)[ZT_PROTO_VERB_HELLO_IDX_PROTOCOL_VERSION];
if (protoVersion < ZT_PROTO_VERSION_MIN) {
TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_remoteAddress.toString().c_str());
return true;
}
const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION]; const unsigned int vMajor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MAJOR_VERSION];
const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION]; const unsigned int vMinor = (*this)[ZT_PROTO_VERB_HELLO_IDX_MINOR_VERSION];
const unsigned int vRevision = at<uint16_t>(ZT_PROTO_VERB_HELLO_IDX_REVISION); const unsigned int vRevision = at<uint16_t>(ZT_PROTO_VERB_HELLO_IDX_REVISION);
const uint64_t timestamp = at<uint64_t>(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); const uint64_t timestamp = at<uint64_t>(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP);
Identity id; Identity id;
unsigned int destAddrPtr = id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY) + ZT_PROTO_VERB_HELLO_IDX_IDENTITY; unsigned int destAddrPtr = id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY) + ZT_PROTO_VERB_HELLO_IDX_IDENTITY;
if (protoVersion < ZT_PROTO_VERSION_MIN) {
TRACE("dropped HELLO from %s(%s): protocol version too old",id.address().toString().c_str(),_remoteAddress.toString().c_str());
return true;
}
if (source() != id.address()) { if (source() != id.address()) {
TRACE("dropped HELLO from %s(%s): identity not for sending address",source().toString().c_str(),_remoteAddress.toString().c_str()); TRACE("dropped HELLO from %s(%s): identity not for sending address",source().toString().c_str(),_remoteAddress.toString().c_str());
return true; return true;
@ -906,26 +905,29 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,const Sha
unsigned int count = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD); unsigned int count = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD);
unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2; unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 2;
while (count) { // if ptr overflows Buffer will throw while (count--) { // if ptr overflows Buffer will throw
// TODO: properly handle blacklisting, support other features... see Packet.hpp. // TODO: properly handle blacklisting, support other features... see Packet.hpp.
unsigned int flags = (*this)[ptr++]; unsigned int flags = (*this)[ptr++];
/*int metric = (*this)[ptr++];*/ ++ptr;
unsigned int extLen = at<uint16_t>(ptr); ptr += 2; unsigned int extLen = at<uint16_t>(ptr); ptr += 2;
ptr += extLen; // unused right now ptr += extLen; // unused right now
unsigned int addrType = (*this)[ptr++]; unsigned int addrType = (*this)[ptr++];
unsigned int addrLen = (*this)[ptr++]; unsigned int addrLen = (*this)[ptr++];
switch(addrType) { switch(addrType) {
case 4: { case 4: {
InetAddress a(field(ptr,4),4,at<uint16_t>(ptr + 4)); InetAddress a(field(ptr,4),4,at<uint16_t>(ptr + 4));
if ( ((flags & (0x01 | 0x02)) == 0) && (Path::isAddressValidForPath(a)) ) if ( ((flags & (0x01 | 0x02)) == 0) && (Path::isAddressValidForPath(a)) ) {
TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
peer->attemptToContactAt(RR,a,RR->node->now()); peer->attemptToContactAt(RR,a,RR->node->now());
}
} break; } break;
case 6: { case 6: {
InetAddress a(field(ptr,16),16,at<uint16_t>(ptr + 16)); InetAddress a(field(ptr,16),16,at<uint16_t>(ptr + 16));
if ( ((flags & (0x01 | 0x02)) == 0) && (Path::isAddressValidForPath(a)) ) if ( ((flags & (0x01 | 0x02)) == 0) && (Path::isAddressValidForPath(a)) ) {
TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
peer->attemptToContactAt(RR,a,RR->node->now()); peer->attemptToContactAt(RR,a,RR->node->now());
}
} break; } break;
} }
ptr += addrLen; ptr += addrLen;

View file

@ -63,17 +63,20 @@ struct InetAddress : public sockaddr_storage
/** /**
* IP address scope * IP address scope
*
* Note that these values are in ascending order of path preference and
* MUST remain that way or Path must be changed to reflect.
*/ */
enum IpScope enum IpScope
{ {
IP_SCOPE_NONE = 0, // not an IP address -- also the number of classes, must be last entry IP_SCOPE_NONE = 0, // NULL or not an IP address
IP_SCOPE_LINK_LOCAL = 1, // 169.254.x.x, IPv6 LL IP_SCOPE_MULTICAST = 1, // 224.0.0.0 and other V4/V6 multicast IPs
IP_SCOPE_PRIVATE = 2, // 10.x.x.x, etc. IP_SCOPE_LOOPBACK = 2, // 127.0.0.1, ::1, etc.
IP_SCOPE_PSEUDOPRIVATE = 3, // 28.x.x.x, etc. -- unofficially unrouted IP blocks often "bogarted" IP_SCOPE_PSEUDOPRIVATE = 3, // 28.x.x.x, etc. -- unofficially unrouted IPv4 blocks often "bogarted"
IP_SCOPE_SHARED = 4, // 100.64.0.0/10, shared space for e.g. carrier-grade NAT IP_SCOPE_GLOBAL = 4, // globally routable IP address (all others)
IP_SCOPE_GLOBAL = 5, // globally routable IP address (all others) IP_SCOPE_LINK_LOCAL = 5, // 169.254.x.x, IPv6 LL
IP_SCOPE_LOOPBACK = 6, // 127.0.0.1 IP_SCOPE_SHARED = 6, // 100.64.0.0/10, shared space for e.g. carrier-grade NAT
IP_SCOPE_MULTICAST = 7 // 224.0.0.0 and other multicast IPs IP_SCOPE_PRIVATE = 7 // 10.x.x.x, 192.168.x.x, etc.
}; };
InetAddress() throw() { memset(this,0,sizeof(InetAddress)); } InetAddress() throw() { memset(this,0,sizeof(InetAddress)); }

View file

@ -432,11 +432,11 @@ void Node::freeQueryResult(void *qr)
::free(qr); ::free(qr);
} }
int Node::addLocalInterfaceAddress(const struct sockaddr_storage *addr,int metric,ZT1_LocalInterfaceAddressTrust trust,int reliable) int Node::addLocalInterfaceAddress(const struct sockaddr_storage *addr,int metric,ZT1_LocalInterfaceAddressTrust trust)
{ {
if (Path::isAddressValidForPath(*(reinterpret_cast<const InetAddress *>(addr)))) { if (Path::isAddressValidForPath(*(reinterpret_cast<const InetAddress *>(addr)))) {
Mutex::Lock _l(_directPaths_m); Mutex::Lock _l(_directPaths_m);
_directPaths.push_back(Path(*(reinterpret_cast<const InetAddress *>(addr)),metric,(Path::Trust)trust,reliable != 0)); _directPaths.push_back(Path(*(reinterpret_cast<const InetAddress *>(addr)),metric,(Path::Trust)trust));
std::sort(_directPaths.begin(),_directPaths.end()); std::sort(_directPaths.begin(),_directPaths.end());
_directPaths.erase(std::unique(_directPaths.begin(),_directPaths.end()),_directPaths.end()); _directPaths.erase(std::unique(_directPaths.begin(),_directPaths.end()),_directPaths.end());
return 1; return 1;
@ -711,10 +711,10 @@ void ZT1_Node_setNetconfMaster(ZT1_Node *node,void *networkControllerInstance)
} catch ( ... ) {} } catch ( ... ) {}
} }
int ZT1_Node_addLocalInterfaceAddress(ZT1_Node *node,const struct sockaddr_storage *addr,int metric,ZT1_LocalInterfaceAddressTrust trust,int reliable) int ZT1_Node_addLocalInterfaceAddress(ZT1_Node *node,const struct sockaddr_storage *addr,int metric,ZT1_LocalInterfaceAddressTrust trust)
{ {
try { try {
return reinterpret_cast<ZeroTier::Node *>(node)->addLocalInterfaceAddress(addr,metric,trust,reliable); return reinterpret_cast<ZeroTier::Node *>(node)->addLocalInterfaceAddress(addr,metric,trust);
} catch ( ... ) { } catch ( ... ) {
return 0; return 0;
} }

View file

@ -105,7 +105,7 @@ public:
ZT1_VirtualNetworkConfig *networkConfig(uint64_t nwid) const; ZT1_VirtualNetworkConfig *networkConfig(uint64_t nwid) const;
ZT1_VirtualNetworkList *networks() const; ZT1_VirtualNetworkList *networks() const;
void freeQueryResult(void *qr); void freeQueryResult(void *qr);
int addLocalInterfaceAddress(const struct sockaddr_storage *addr,int metric,ZT1_LocalInterfaceAddressTrust trust,int reliable); int addLocalInterfaceAddress(const struct sockaddr_storage *addr,int metric,ZT1_LocalInterfaceAddressTrust trust);
void clearLocalInterfaceAddresses(); void clearLocalInterfaceAddresses();
void setNetconfMaster(void *networkControllerInstance); void setNetconfMaster(void *networkControllerInstance);

View file

@ -872,7 +872,6 @@ public:
* *
* Path record format: * Path record format:
* <[1] flags> * <[1] flags>
* <[1] metric from 0 (highest priority) to 255 (lowest priority)>
* <[2] length of extended path characteristics or 0 for none> * <[2] length of extended path characteristics or 0 for none>
* <[...] extended path characteristics> * <[...] extended path characteristics>
* <[1] address type> * <[1] address type>
@ -882,9 +881,8 @@ public:
* Path record flags: * Path record flags:
* 0x01 - Forget this path if it is currently known * 0x01 - Forget this path if it is currently known
* 0x02 - Blacklist this path, do not use * 0x02 - Blacklist this path, do not use
* 0x04 - Reliable path (no NAT keepalives, etc. are necessary) * 0x04 - Disable encryption (trust: privacy)
* 0x08 - Disable encryption (trust: privacy) * 0x08 - Disable encryption and authentication (trust: ultimate)
* 0x10 - Disable encryption and authentication (trust: ultimate)
* *
* Address types and addresses are of the same format as the destination * Address types and addresses are of the same format as the destination
* address type and address in HELLO. * address type and address in HELLO.
@ -901,15 +899,10 @@ public:
* is set. * is set.
* *
* Only a subset of this functionality is currently implemented: basic * Only a subset of this functionality is currently implemented: basic
* path pushing and learning. Metrics, most flags, and OK responses are * path pushing and learning. Blacklisting and trust are not fully
* not yet implemented as of 1.0.4. * implemented yet (encryption is still always used).
* *
* OK response payload: * OK and ERROR are not generated.
* <[2] 16-bit number of active direct paths we already have>
* <[2] 16-bit number of paths in push that we don't already have>
* <[2] 16-bit number of new paths we are trying (or will try)>
*
* ERROR is presently not sent.
*/ */
VERB_PUSH_DIRECT_PATHS = 16 VERB_PUSH_DIRECT_PATHS = 16
}; };

View file

@ -34,10 +34,31 @@
namespace ZeroTier { namespace ZeroTier {
/**
* Base class for paths
*
* The base Path class is an immutable value.
*/
class Path class Path
{ {
public: public:
// Must be the same values as ZT1_LocalInterfaceAddressTrust in ZeroTierOne.h /**
* Path trust category
*
* Note that this is NOT peer trust and has nothing to do with root server
* designations or other trust metrics. This indicates how much we trust
* this path to be secure and/or private. A trust level of normal means
* encrypt and authenticate all traffic. Privacy trust means we can send
* traffic in the clear. Ultimate trust means we don't even need
* authentication. Generally a private path would be a hard-wired local
* LAN, while an ultimate trust path would be a physically isolated private
* server backplane.
*
* Nearly all paths will be normal trust. The other levels are for high
* performance local SDN use only.
*
* These values MUST match ZT1_LocalInterfaceAddressTrust in ZeroTierOne.h
*/
enum Trust enum Trust
{ {
TRUST_NORMAL = 0, TRUST_NORMAL = 0,
@ -47,17 +68,15 @@ public:
Path() : Path() :
_addr(), _addr(),
_metric(0), _ipScope(InetAddress::IP_SCOPE_NONE),
_trust(TRUST_NORMAL), _trust(TRUST_NORMAL)
_reliable(false)
{ {
} }
Path(const InetAddress &addr,int metric,Trust trust,bool reliable) : Path(const InetAddress &addr,int metric,Trust trust) :
_addr(addr), _addr(addr),
_metric(metric), _ipScope(addr.ipScope()),
_trust(trust), _trust(trust)
_reliable(reliable)
{ {
} }
@ -67,9 +86,14 @@ public:
inline const InetAddress &address() const throw() { return _addr; } inline const InetAddress &address() const throw() { return _addr; }
/** /**
* @return Metric (higher == worse) or negative if path is blacklisted * @return IP scope -- faster shortcut for address().ipScope()
*/ */
inline int metric() const throw() { return _metric; } inline InetAddress::IpScope ipScope() const throw() { return _ipScope; }
/**
* @return Preference rank, higher == better
*/
inline int preferenceRank() const throw() { return (int)_ipScope; } // IP scopes are in ascending rank order in InetAddress.hpp
/** /**
* @return Path trust level * @return Path trust level
@ -79,7 +103,10 @@ public:
/** /**
* @return True if path is considered reliable (no NAT keepalives etc. are needed) * @return True if path is considered reliable (no NAT keepalives etc. are needed)
*/ */
inline bool reliable() const throw() { return _reliable; } inline bool reliable() const throw()
{
return ((_ipScope != InetAddress::IP_SCOPE_GLOBAL)&&(_ipScope != InetAddress::IP_SCOPE_PSEUDOPRIVATE));
}
/** /**
* @return True if address is non-NULL * @return True if address is non-NULL
@ -127,11 +154,10 @@ public:
return false; return false;
} }
protected: private:
InetAddress _addr; InetAddress _addr;
int _metric; // negative == blacklisted InetAddress::IpScope _ipScope; // memoize this since it's a computed value checked often
Trust _trust; Trust _trust;
bool _reliable;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -161,6 +161,21 @@ void Peer::received(
_lastMulticastFrame = now; _lastMulticastFrame = now;
} }
RemotePath *Peer::getBestPath(uint64_t now)
{
RemotePath *bestPath = (RemotePath *)0;
uint64_t lrMax = 0;
int rank = 0;
for(unsigned int p=0,np=_numPaths;p<np;++p) {
if ( (_paths[p].active(now)) && ((_paths[p].lastReceived() >= lrMax)||(_paths[p].preferenceRank() >= rank)) ) {
lrMax = _paths[p].lastReceived();
rank = _paths[p].preferenceRank();
bestPath = &(_paths[p]);
}
}
return bestPath;
}
void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &atAddress,uint64_t now) void Peer::attemptToContactAt(const RuntimeEnvironment *RR,const InetAddress &atAddress,uint64_t now)
{ {
Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO); Packet outp(_id.address(),RR->identity.address(),Packet::VERB_HELLO);
@ -200,7 +215,7 @@ void Peer::doPingAndKeepalive(const RuntimeEnvironment *RR,uint64_t now)
TRACE("PING %s(%s)",_id.address().toString().c_str(),bestPath->address().toString().c_str()); TRACE("PING %s(%s)",_id.address().toString().c_str(),bestPath->address().toString().c_str());
attemptToContactAt(RR,bestPath->address(),now); attemptToContactAt(RR,bestPath->address(),now);
bestPath->sent(now); bestPath->sent(now);
} else if ((now - bestPath->lastSend()) >= ZT_NAT_KEEPALIVE_DELAY) { } else if (((now - bestPath->lastSend()) >= ZT_NAT_KEEPALIVE_DELAY)&&(!bestPath->reliable())) {
TRACE("NAT keepalive %s(%s)",_id.address().toString().c_str(),bestPath->address().toString().c_str()); TRACE("NAT keepalive %s(%s)",_id.address().toString().c_str(),bestPath->address().toString().c_str());
RR->node->putPacket(bestPath->address(),"",0); RR->node->putPacket(bestPath->address(),"",0);
bestPath->sent(now); bestPath->sent(now);
@ -214,7 +229,17 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_
_lastDirectPathPush = now; _lastDirectPathPush = now;
std::vector<Path> dps(RR->node->directPaths()); std::vector<Path> dps(RR->node->directPaths());
TRACE("pushing %u direct paths (local interface addresses) to %s",(unsigned int)dps.size(),_id.address().toString().c_str()); #ifdef ZT_TRACE
{
std::string ps;
for(std::vector<Path>::const_iterator p(dps.begin());p!=dps.end();++p) {
if (ps.length() > 0)
ps.push_back(',');
ps.append(p->address().toString());
}
TRACE("pushing %u direct paths (local interface addresses) to %s: %s",(unsigned int)dps.size(),_id.address().toString().c_str(),ps.c_str());
}
#endif
std::vector<Path>::const_iterator p(dps.begin()); std::vector<Path>::const_iterator p(dps.begin());
while (p != dps.end()) { while (p != dps.end()) {
@ -230,32 +255,25 @@ void Peer::pushDirectPaths(const RuntimeEnvironment *RR,RemotePath *path,uint64_
case AF_INET6: case AF_INET6:
addressType = 6; addressType = 6;
break; break;
default: default: // we currently only push IP addresses
++p; ++p;
continue; continue;
} }
uint8_t flags = 0; uint8_t flags = 0;
if (p->metric() < 0)
flags |= (0x01 | 0x02); // forget and blacklist
else {
if (p->reliable())
flags |= 0x04; // no NAT keepalives and such
switch(p->trust()) { switch(p->trust()) {
default: default:
break; break;
case Path::TRUST_PRIVACY: case Path::TRUST_PRIVACY:
flags |= 0x08; // no encryption flags |= 0x04; // no encryption
break; break;
case Path::TRUST_ULTIMATE: case Path::TRUST_ULTIMATE:
flags |= (0x08 | 0x10); // no encryption, no authentication (redundant but go ahead and set both) flags |= (0x04 | 0x08); // no encryption, no authentication (redundant but go ahead and set both)
break; break;
} }
}
outp.append(flags); outp.append(flags);
outp.append((uint8_t)((p->metric() >= 0) ? ((p->metric() <= 255) ? p->metric() : 255) : 0)); outp.append((uint16_t)0); // no extensions
outp.append((uint16_t)0);
outp.append(addressType); outp.append(addressType);
outp.append((uint8_t)((addressType == 4) ? 6 : 18)); outp.append((uint8_t)((addressType == 4) ? 6 : 18));
outp.append(p->address().rawIpData(),((addressType == 4) ? 4 : 16)); outp.append(p->address().rawIpData(),((addressType == 4) ? 4 : 16));

View file

@ -126,18 +126,7 @@ public:
* @param now Current time * @param now Current time
* @return Best path or NULL if there are no active (or fixed) direct paths * @return Best path or NULL if there are no active (or fixed) direct paths
*/ */
inline RemotePath *getBestPath(uint64_t now) RemotePath *getBestPath(uint64_t now);
{
RemotePath *bestPath = (RemotePath *)0;
uint64_t lrMax = 0;
for(unsigned int p=0,np=_numPaths;p<np;++p) {
if ((_paths[p].active(now))&&(_paths[p].lastReceived() >= lrMax)) {
lrMax = _paths[p].lastReceived();
bestPath = &(_paths[p]);
}
}
return bestPath;
}
/** /**
* Send via best path * Send via best path

View file

@ -56,7 +56,7 @@ public:
_fixed(false) {} _fixed(false) {}
RemotePath(const InetAddress &addr,bool fixed) : RemotePath(const InetAddress &addr,bool fixed) :
Path(addr,0,TRUST_NORMAL,false), Path(addr,0,TRUST_NORMAL),
_lastSend(0), _lastSend(0),
_lastReceived(0), _lastReceived(0),
_fixed(fixed) {} _fixed(fixed) {}
@ -123,7 +123,7 @@ public:
*/ */
inline bool send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now) inline bool send(const RuntimeEnvironment *RR,const void *data,unsigned int len,uint64_t now)
{ {
if (RR->node->putPacket(_addr,data,len)) { if (RR->node->putPacket(address(),data,len)) {
sent(now); sent(now);
RR->antiRec->logOutgoingZT(data,len); RR->antiRec->logOutgoingZT(data,len);
return true; return true;

View file

@ -65,7 +65,8 @@ static const char *etherTypeName(const unsigned int etherType)
#endif // ZT_TRACE #endif // ZT_TRACE
Switch::Switch(const RuntimeEnvironment *renv) : Switch::Switch(const RuntimeEnvironment *renv) :
RR(renv) RR(renv),
_lastBeaconResponse(0)
{ {
} }
@ -76,7 +77,25 @@ Switch::~Switch()
void Switch::onRemotePacket(const InetAddress &fromAddr,const void *data,unsigned int len) void Switch::onRemotePacket(const InetAddress &fromAddr,const void *data,unsigned int len)
{ {
try { try {
if (len > ZT_PROTO_MIN_FRAGMENT_LENGTH) { if (len == 13) {
/* LEGACY: before VERB_PUSH_DIRECT_PATHS, peers used broadcast
* announcements on the LAN to solve the 'same network problem.' We
* no longer send these, but we'll listen for them for a while to
* locate peers with versions <1.0.4. */
Address beaconAddr(reinterpret_cast<const char *>(data) + 8,5);
if (beaconAddr == RR->identity.address())
return;
SharedPtr<Peer> peer(RR->topology->getPeer(beaconAddr));
if (peer) { // we'll only respond to beacons from known peers
const uint64_t now = RR->node->now();
if ((now - _lastBeaconResponse) >= 2500) { // limit rate of responses
_lastBeaconResponse = now;
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP);
outp.armor(peer->key(),false);
RR->node->putPacket(fromAddr,outp.data(),outp.size());
}
}
} else if (len > ZT_PROTO_MIN_FRAGMENT_LENGTH) {
if (((const unsigned char *)data)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR) { if (((const unsigned char *)data)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR) {
_handleRemotePacketFragment(fromAddr,data,len); _handleRemotePacketFragment(fromAddr,data,len);
} else if (len >= ZT_PROTO_MIN_PACKET_LENGTH) { } else if (len >= ZT_PROTO_MIN_PACKET_LENGTH) {

View file

@ -184,6 +184,7 @@ private:
bool _trySend(const Packet &packet,bool encrypt,uint64_t nwid); bool _trySend(const Packet &packet,bool encrypt,uint64_t nwid);
const RuntimeEnvironment *const RR; const RuntimeEnvironment *const RR;
uint64_t _lastBeaconResponse;
// Outsanding WHOIS requests and how many retries they've undergone // Outsanding WHOIS requests and how many retries they've undergone
struct WhoisRequest struct WhoisRequest

View file

@ -916,7 +916,7 @@ int main(int argc,char **argv)
r |= testCertificate(); r |= testCertificate();
r |= testPhy(); r |= testPhy();
r |= testResolver(); r |= testResolver();
r |= testHttp(); //r |= testHttp();
if (r) if (r)
std::cout << std::endl << "SOMETHING FAILED!" << std::endl; std::cout << std::endl << "SOMETHING FAILED!" << std::endl;

View file

@ -592,7 +592,7 @@ public:
if (!isZT) { if (!isZT) {
InetAddress ip(ifa->ifa_addr); InetAddress ip(ifa->ifa_addr);
ip.setPort(_port); ip.setPort(_port);
_node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&ip),0,ZT1_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL,0); _node->addLocalInterfaceAddress(reinterpret_cast<const struct sockaddr_storage *>(&ip),0,ZT1_LOCAL_INTERFACE_ADDRESS_TRUST_NORMAL);
} }
} }
ifa = ifa->ifa_next; ifa = ifa->ifa_next;

View file

@ -172,6 +172,7 @@ To create a new network with a random last six digits safely and atomically, you
<tr><td>multicastLimit</td><td>integer</td><td>Maximum number of multicast recipients per multicast/broadcast address</td><td>yes</td></tr> <tr><td>multicastLimit</td><td>integer</td><td>Maximum number of multicast recipients per multicast/broadcast address</td><td>yes</td></tr>
<tr><td>creationTime</td><td>integer</td><td>Time network was created in ms since epoch</td><td>no</td></tr> <tr><td>creationTime</td><td>integer</td><td>Time network was created in ms since epoch</td><td>no</td></tr>
<tr><td>revision</td><td>integer</td><td>Network config revision number</td><td>no</td></tr> <tr><td>revision</td><td>integer</td><td>Network config revision number</td><td>no</td></tr>
<tr><td>memberRevisionCounter</td><td>integer</td><td>Current value of network revision counter (incremented after every member add or revision)</td><td>no</td></tr>
<tr><td>members</td><td>[string]</td><td>Array of ZeroTier addresses of network members</td><td>no</td></tr> <tr><td>members</td><td>[string]</td><td>Array of ZeroTier addresses of network members</td><td>no</td></tr>
<tr><td>relays</td><td>[object]</td><td>Array of network-specific relay nodes (see below)</td><td>yes</td></tr> <tr><td>relays</td><td>[object]</td><td>Array of network-specific relay nodes (see below)</td><td>yes</td></tr>
<tr><td>ipLocalRoutes</td><td>[string]</td><td>Array of IP network/netmask entries corresponding to networks routed directly via this interface (e.g. 10.0.0.0/8 to route 10.0.0.0 via this interface)</td></tr> <tr><td>ipLocalRoutes</td><td>[string]</td><td>Array of IP network/netmask entries corresponding to networks routed directly via this interface (e.g. 10.0.0.0/8 to route 10.0.0.0 via this interface)</td></tr>
@ -200,7 +201,7 @@ IP assignment pools are only used if they are within a network specified in ipLo
<table> <table>
<tr><td><b>Field</b></td><td><b>Type</b></td><td><b>Description</b></td></tr> <tr><td><b>Field</b></td><td><b>Type</b></td><td><b>Description</b></td></tr>
<tr><td>ipRangeStart</td><td>string</td><td>Start of IP assignment range</td></tr> <tr><td>ipRangeStart</td><td>string</td><td>Start of IP assignment range</td></tr>
<tr><td>ipRangeEnd</td><td>integer</td><td>End of IP assignment range</td></tr> <tr><td>ipRangeEnd</td><td>string</td><td>End of IP assignment range</td></tr>
</table> </table>
**Rule object format:** **Rule object format:**
@ -247,4 +248,5 @@ IP related fields apply only to Ethernet frames of type IPv4 or IPV6. Otherwise
<tr><td>activeBridge</td><td>boolean</td><td>This member is an active network bridge</td><td>yes</td></tr> <tr><td>activeBridge</td><td>boolean</td><td>This member is an active network bridge</td><td>yes</td></tr>
<tr><td>identity</td><td>string</td><td>Full ZeroTier identity of member</td><td>no</td></tr> <tr><td>identity</td><td>string</td><td>Full ZeroTier identity of member</td><td>no</td></tr>
<tr><td>ipAssignments</td><td>[string]</td><td>Array of IP/bits IP assignments</td><td>yes</td></tr> <tr><td>ipAssignments</td><td>[string]</td><td>Array of IP/bits IP assignments</td><td>yes</td></tr>
<tr><td>memberRevision</td><td>integer</td><td>Member revision counter value from network at time of last revision or member creation</td><td>no</td></tr>
</table> </table>