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

@ -73,7 +73,7 @@ extern "C" {
* *
* If this does change, also change it in tap.h in the tuntaposx code under * If this does change, also change it in tap.h in the tuntaposx code under
* mac-tap. * mac-tap.
* *
* Overhead for a normal frame split into two packets: * Overhead for a normal frame split into two packets:
* *
* 1414 = 1444 (typical UDP MTU) - 28 (packet header) - 2 (ethertype) * 1414 = 1444 (typical UDP MTU) - 28 (packet header) - 2 (ethertype)
@ -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

@ -33,7 +33,7 @@
#include <string> #include <string>
#include <map> #include <map>
#include <stdexcept> #include <stdexcept>
#include "Constants.hpp" #include "Constants.hpp"
#include "Utils.hpp" #include "Utils.hpp"
@ -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

@ -70,7 +70,7 @@
/** /**
* Maximum hop count allowed by packet structure (3 bits, 0-7) * Maximum hop count allowed by packet structure (3 bits, 0-7)
* *
* This is a protocol constant. It's the maximum allowed by the length * This is a protocol constant. It's the maximum allowed by the length
* of the hop counter -- three bits. See node/Constants.hpp for the * of the hop counter -- three bits. See node/Constants.hpp for the
* pragmatic forwarding limit, which is typically lower. * pragmatic forwarding limit, which is typically lower.
@ -352,7 +352,7 @@ namespace ZeroTier {
/** /**
* ZeroTier packet * ZeroTier packet
* *
* Packet format: * Packet format:
* <[8] random initialization vector (doubles as 64-bit packet ID)> * <[8] random initialization vector (doubles as 64-bit packet ID)>
* <[5] destination ZT address> * <[5] destination ZT address>
@ -362,7 +362,7 @@ namespace ZeroTier {
* [... -- begin encryption envelope -- ...] * [... -- begin encryption envelope -- ...]
* <[1] encrypted flags (top 3 bits) and verb (last 5 bits)> * <[1] encrypted flags (top 3 bits) and verb (last 5 bits)>
* [... verb-specific payload ...] * [... verb-specific payload ...]
* *
* Packets smaller than 28 bytes are invalid and silently discarded. * Packets smaller than 28 bytes are invalid and silently discarded.
* *
* The flags/cipher/hops bit field is: FFCCCHHH where C is a 3-bit cipher * The flags/cipher/hops bit field is: FFCCCHHH where C is a 3-bit cipher
@ -384,15 +384,15 @@ class Packet : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH>
public: public:
/** /**
* A packet fragment * A packet fragment
* *
* Fragments are sent if a packet is larger than UDP MTU. The first fragment * Fragments are sent if a packet is larger than UDP MTU. The first fragment
* is sent with its normal header with the fragmented flag set. Remaining * is sent with its normal header with the fragmented flag set. Remaining
* fragments are sent this way. * fragments are sent this way.
* *
* The fragmented bit indicates that there is at least one fragment. Fragments * The fragmented bit indicates that there is at least one fragment. Fragments
* themselves contain the total, so the receiver must "learn" this from the * themselves contain the total, so the receiver must "learn" this from the
* first fragment it receives. * first fragment it receives.
* *
* Fragments are sent with the following format: * Fragments are sent with the following format:
* <[8] packet ID of packet whose fragment this belongs to> * <[8] packet ID of packet whose fragment this belongs to>
* <[5] destination ZT address> * <[5] destination ZT address>
@ -430,7 +430,7 @@ public:
/** /**
* Initialize from a packet * Initialize from a packet
* *
* @param p Original assembled packet * @param p Original assembled packet
* @param fragStart Start of fragment (raw index in packet data) * @param fragStart Start of fragment (raw index in packet data)
* @param fragLen Length of fragment in bytes * @param fragLen Length of fragment in bytes
@ -446,7 +446,7 @@ public:
/** /**
* Initialize from a packet * Initialize from a packet
* *
* @param p Original assembled packet * @param p Original assembled packet
* @param fragStart Start of fragment (raw index in packet data) * @param fragStart Start of fragment (raw index in packet data)
* @param fragLen Length of fragment in bytes * @param fragLen Length of fragment in bytes
@ -473,7 +473,7 @@ public:
/** /**
* Get this fragment's destination * Get this fragment's destination
* *
* @return Destination ZT address * @return Destination ZT address
*/ */
inline Address destination() const { return Address(field(ZT_PACKET_FRAGMENT_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } inline Address destination() const { return Address(field(ZT_PACKET_FRAGMENT_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
@ -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
}; };
@ -974,7 +967,7 @@ public:
/** /**
* Construct a new empty packet with a unique random packet ID * Construct a new empty packet with a unique random packet ID
* *
* Flags and hops will be zero. Other fields and data region are undefined. * Flags and hops will be zero. Other fields and data region are undefined.
* Use the header access methods (setDestination() and friends) to fill out * Use the header access methods (setDestination() and friends) to fill out
* the header. Payload should be appended; initial size is header size. * the header. Payload should be appended; initial size is header size.
@ -1004,7 +997,7 @@ public:
/** /**
* Construct a new empty packet with a unique random packet ID * Construct a new empty packet with a unique random packet ID
* *
* @param dest Destination ZT address * @param dest Destination ZT address
* @param source Source ZT address * @param source Source ZT address
* @param v Verb * @param v Verb
@ -1021,7 +1014,7 @@ public:
/** /**
* Reset this packet structure for reuse in place * Reset this packet structure for reuse in place
* *
* @param dest Destination ZT address * @param dest Destination ZT address
* @param source Source ZT address * @param source Source ZT address
* @param v Verb * @param v Verb
@ -1047,28 +1040,28 @@ public:
/** /**
* Set this packet's destination * Set this packet's destination
* *
* @param dest ZeroTier address of destination * @param dest ZeroTier address of destination
*/ */
inline void setDestination(const Address &dest) { dest.copyTo(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } inline void setDestination(const Address &dest) { dest.copyTo(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
/** /**
* Set this packet's source * Set this packet's source
* *
* @param source ZeroTier address of source * @param source ZeroTier address of source
*/ */
inline void setSource(const Address &source) { source.copyTo(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } inline void setSource(const Address &source) { source.copyTo(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
/** /**
* Get this packet's destination * Get this packet's destination
* *
* @return Destination ZT address * @return Destination ZT address
*/ */
inline Address destination() const { return Address(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } inline Address destination() const { return Address(field(ZT_PACKET_IDX_DEST,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
/** /**
* Get this packet's source * Get this packet's source
* *
* @return Source ZT address * @return Source ZT address
*/ */
inline Address source() const { return Address(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); } inline Address source() const { return Address(field(ZT_PACKET_IDX_SOURCE,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); }
@ -1138,17 +1131,17 @@ public:
/** /**
* Get this packet's unique ID (the IV field interpreted as uint64_t) * Get this packet's unique ID (the IV field interpreted as uint64_t)
* *
* @return Packet ID * @return Packet ID
*/ */
inline uint64_t packetId() const { return at<uint64_t>(ZT_PACKET_IDX_IV); } inline uint64_t packetId() const { return at<uint64_t>(ZT_PACKET_IDX_IV); }
/** /**
* Set packet verb * Set packet verb
* *
* This also has the side-effect of clearing any verb flags, such as * This also has the side-effect of clearing any verb flags, such as
* compressed, and so must only be done during packet composition. * compressed, and so must only be done during packet composition.
* *
* @param v New packet verb * @param v New packet verb
*/ */
inline void setVerb(Verb v) { (*this)[ZT_PACKET_IDX_VERB] = (char)v; } inline void setVerb(Verb v) { (*this)[ZT_PACKET_IDX_VERB] = (char)v; }
@ -1186,22 +1179,22 @@ public:
/** /**
* Attempt to compress payload if not already (must be unencrypted) * Attempt to compress payload if not already (must be unencrypted)
* *
* This requires that the payload at least contain the verb byte already * This requires that the payload at least contain the verb byte already
* set. The compressed flag in the verb is set if compression successfully * set. The compressed flag in the verb is set if compression successfully
* results in a size reduction. If no size reduction occurs, compression * results in a size reduction. If no size reduction occurs, compression
* is not done and the flag is left cleared. * is not done and the flag is left cleared.
* *
* @return True if compression occurred * @return True if compression occurred
*/ */
bool compress(); bool compress();
/** /**
* Attempt to decompress payload if it is compressed (must be unencrypted) * Attempt to decompress payload if it is compressed (must be unencrypted)
* *
* If payload is compressed, it is decompressed and the compressed verb * If payload is compressed, it is decompressed and the compressed verb
* flag is cleared. Otherwise nothing is done and true is returned. * flag is cleared. Otherwise nothing is done and true is returned.
* *
* @return True if data is now decompressed and valid, false on error * @return True if data is now decompressed and valid, false on error
*/ */
bool uncompress(); bool uncompress();

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) switch(p->trust()) {
flags |= (0x01 | 0x02); // forget and blacklist default:
else { break;
if (p->reliable()) case Path::TRUST_PRIVACY:
flags |= 0x04; // no NAT keepalives and such flags |= 0x04; // no encryption
switch(p->trust()) { break;
default: case Path::TRUST_ULTIMATE:
break; flags |= (0x04 | 0x08); // no encryption, no authentication (redundant but go ahead and set both)
case Path::TRUST_PRIVACY: break;
flags |= 0x08; // no encryption
break;
case Path::TRUST_ULTIMATE:
flags |= (0x08 | 0x10); // no encryption, no authentication (redundant but go ahead and set both)
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

@ -102,7 +102,7 @@ public:
* *
* This is called by the decode pipe when a packet is proven to be authentic * This is called by the decode pipe when a packet is proven to be authentic
* and appears to be valid. * and appears to be valid.
* *
* @param RR Runtime environment * @param RR Runtime environment
* @param remoteAddr Internet address of sender * @param remoteAddr Internet address of sender
* @param hops ZeroTier (not IP) hops * @param hops ZeroTier (not IP) hops
@ -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

@ -99,20 +99,20 @@ public:
/** /**
* Send a packet to a ZeroTier address (destination in packet) * Send a packet to a ZeroTier address (destination in packet)
* *
* The packet must be fully composed with source and destination but not * The packet must be fully composed with source and destination but not
* yet encrypted. If the destination peer is known the packet * yet encrypted. If the destination peer is known the packet
* is sent immediately. Otherwise it is queued and a WHOIS is dispatched. * is sent immediately. Otherwise it is queued and a WHOIS is dispatched.
* *
* The packet may be compressed. Compression isn't done here. * The packet may be compressed. Compression isn't done here.
* *
* Needless to say, the packet's source must be this node. Otherwise it * Needless to say, the packet's source must be this node. Otherwise it
* won't be encrypted right. (This is not used for relaying.) * won't be encrypted right. (This is not used for relaying.)
* *
* The network ID should only be specified for frames and other actual * The network ID should only be specified for frames and other actual
* network traffic. Other traffic such as controller requests and regular * network traffic. Other traffic such as controller requests and regular
* protocol messages should specify zero. * protocol messages should specify zero.
* *
* @param packet Packet to send * @param packet Packet to send
* @param encrypt Encrypt packet payload? (always true except for HELLO) * @param encrypt Encrypt packet payload? (always true except for HELLO)
* @param nwid Related network ID or 0 if message is not in-network traffic * @param nwid Related network ID or 0 if message is not in-network traffic
@ -168,7 +168,7 @@ public:
/** /**
* Perform retries and other periodic timer tasks * Perform retries and other periodic timer tasks
* *
* This can return a very long delay if there are no pending timer * This can return a very long delay if there are no pending timer
* tasks. The caller should cap this comparatively vs. other values. * tasks. The caller should cap this comparatively vs. other values.
* *
@ -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>