mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-16 12:06:55 +02:00
Merge branch 'adamierymenko-dev' into android-jni
This commit is contained in:
commit
9a00366b18
13 changed files with 544 additions and 418 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -52,3 +52,4 @@ java/build_win32/
|
|||
/ui/.module-cache
|
||||
/windows/WebUIWrapper/bin
|
||||
/windows/WebUIWrapper/obj
|
||||
node_modules
|
||||
|
|
|
@ -169,20 +169,19 @@ SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
|
|||
||(sqlite3_prepare_v2(_db,"SELECT ipNetwork,ipNetmaskBits,ipVersion FROM IpAssignmentPool WHERE networkId = ? ORDER BY ipNetwork ASC",-1,&_sGetIpAssignmentPools2,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT ruleId,nodeId,vlanId,vlanPcp,etherType,macSource,macDest,ipSource,ipDest,ipTos,ipProtocol,ipSourcePort,ipDestPort,\"action\" FROM Rule WHERE networkId = ? ORDER BY ruleId ASC",-1,&_sListRules,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"INSERT INTO Rule (networkId,ruleId,nodeId,vlanId,vlanPcP,etherType,macSource,macDest,ipSource,ipDest,ipTos,ipProtocol,ipSourcePort,ipDestPort,\"action\") VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)",-1,&_sCreateRule,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"INSERT INTO Network (networkId,name,creationTime,revision) VALUES (?,?,?,1)",-1,&_sCreateNetwork,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"UPDATE Network SET ? = ? WHERE networkId = ?",-1,&_sUpdateNetworkField,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"INSERT INTO Network (id,name,creationTime,revision) VALUES (?,?,?,1)",-1,&_sCreateNetwork,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT revision FROM Network WHERE id = ?",-1,&_sGetNetworkRevision,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"UPDATE Network SET revision = ? WHERE id = ?",-1,&_sSetNetworkRevision,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT ip,ipNetmaskBits,ipVersion FROM IpAssignment WHERE networkId = ? AND nodeId = ?",-1,&_sGetIpAssignmentsForNode2,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"SELECT ip,ipNetmaskBits,ipVersion FROM IpAssignment WHERE networkId = ? AND nodeId = ? ORDER BY ip ASC",-1,&_sGetIpAssignmentsForNode2,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"DELETE FROM Relay WHERE networkId = ?",-1,&_sDeleteRelaysForNetwork,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"INSERT INTO Relay (networkId,nodeId,phyAddress) VALUES (?,?,?)",-1,&_sCreateRelay,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"DELETE FROM IpAssignmentPool WHERE networkId = ?",-1,&_sDeleteIpAssignmentPoolsForNetwork,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"DELETE FROM Rule WHERE networkId = ?",-1,&_sDeleteRulesForNetwork,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"INSERT INTO IpAssignmentPool (networkId,ipNetwork,ipNetmaskBits,ipVersion) VALUES (?,?,?,?)",-1,&_sCreateIpAssignmentPool,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"UPDATE Member SET ? = ? WHERE rowid = ?",-1,&_sUpdateMemberField,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"DELETE FROM Member WHERE networkId = ? AND nodeId = ?",-1,&_sDeleteMember,(const char **)0) != SQLITE_OK)
|
||||
||(sqlite3_prepare_v2(_db,"DELETE FROM IpAssignment WHERE networkId = ?; DELETE FROM IpAssignmentPool WHERE networkId = ?; DELETE FROM Member WHERE networkId = ?; DELETE FROM MulticastRate WHERE networkId = ?; DELETE FROM Relay WHERE networkId = ?; DELETE FROM Rule WHERE networkId = ?; DELETE FROM Network WHERE id = ?;",-1,&_sDeleteNetworkAndRelated,(const char **)0) != SQLITE_OK)
|
||||
) {
|
||||
//printf("!!! %s\n",sqlite3_errmsg(_db));
|
||||
sqlite3_close(_db);
|
||||
throw std::runtime_error("SqliteNetworkController unable to initialize one or more prepared statements");
|
||||
}
|
||||
|
@ -215,7 +214,6 @@ SqliteNetworkController::~SqliteNetworkController()
|
|||
sqlite3_finalize(_sListRules);
|
||||
sqlite3_finalize(_sCreateRule);
|
||||
sqlite3_finalize(_sCreateNetwork);
|
||||
sqlite3_finalize(_sUpdateNetworkField);
|
||||
sqlite3_finalize(_sGetNetworkRevision);
|
||||
sqlite3_finalize(_sSetNetworkRevision);
|
||||
sqlite3_finalize(_sGetIpAssignmentsForNode2);
|
||||
|
@ -224,7 +222,6 @@ SqliteNetworkController::~SqliteNetworkController()
|
|||
sqlite3_finalize(_sDeleteIpAssignmentPoolsForNetwork);
|
||||
sqlite3_finalize(_sDeleteRulesForNetwork);
|
||||
sqlite3_finalize(_sCreateIpAssignmentPool);
|
||||
sqlite3_finalize(_sUpdateMemberField);
|
||||
sqlite3_finalize(_sDeleteNetworkAndRelated);
|
||||
sqlite3_close(_db);
|
||||
}
|
||||
|
@ -562,282 +559,8 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpGET(
|
|||
std::string &responseBody,
|
||||
std::string &responseContentType)
|
||||
{
|
||||
char json[16384];
|
||||
|
||||
if (path.empty())
|
||||
return 404;
|
||||
Mutex::Lock _l(_lock);
|
||||
|
||||
if (path[0] == "network") {
|
||||
|
||||
if ((path.size() >= 2)&&(path[1].length() == 16)) {
|
||||
uint64_t nwid = Utils::hexStrToU64(path[1].c_str());
|
||||
char nwids[24];
|
||||
Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid);
|
||||
|
||||
if (path.size() >= 3) {
|
||||
if ((path.size() == 4)&&(path[2] == "member")&&(path[3].length() == 10)) {
|
||||
uint64_t address = Utils::hexStrToU64(path[3].c_str());
|
||||
char addrs[24];
|
||||
Utils::snprintf(addrs,sizeof(addrs),"%.10llx",address);
|
||||
|
||||
sqlite3_reset(_sGetMember2);
|
||||
sqlite3_bind_text(_sGetMember2,1,nwids,16,SQLITE_STATIC);
|
||||
sqlite3_bind_text(_sGetMember2,2,addrs,10,SQLITE_STATIC);
|
||||
if (sqlite3_step(_sGetMember2) == SQLITE_ROW) {
|
||||
Utils::snprintf(json,sizeof(json),
|
||||
"{\n"
|
||||
"\tnwid: \"%s\",\n"
|
||||
"\taddress: \"%s\",\n"
|
||||
"\tauthorized: %s,\n"
|
||||
"\tactiveBridge: %s,\n"
|
||||
"\tlastAt: \"%s\",\n"
|
||||
"\tlastSeen: %llu,\n"
|
||||
"\tfirstSeen: %llu,\n"
|
||||
"\tidentity: \"%s\",\n"
|
||||
"\tipAssignments: [",
|
||||
nwids,
|
||||
addrs,
|
||||
(sqlite3_column_int(_sGetMember2,0) > 0) ? "true" : "false",
|
||||
(sqlite3_column_int(_sGetMember2,1) > 0) ? "true" : "false",
|
||||
_jsonEscape((const char *)sqlite3_column_text(_sGetMember2,3)).c_str(),
|
||||
(unsigned long long)sqlite3_column_int64(_sGetMember2,4),
|
||||
(unsigned long long)sqlite3_column_int64(_sGetMember2,5),
|
||||
_jsonEscape((const char *)sqlite3_column_text(_sGetMember2,2)).c_str());
|
||||
responseBody = json;
|
||||
|
||||
sqlite3_reset(_sGetIpAssignmentsForNode2);
|
||||
sqlite3_bind_text(_sGetIpAssignmentsForNode2,1,nwids,16,SQLITE_STATIC);
|
||||
sqlite3_bind_text(_sGetIpAssignmentsForNode2,2,addrs,10,SQLITE_STATIC);
|
||||
bool firstIp = true;
|
||||
while (sqlite3_step(_sGetIpAssignmentPools2) == SQLITE_ROW) {
|
||||
InetAddress ip((const void *)sqlite3_column_blob(_sGetIpAssignmentsForNode2,0),(sqlite3_column_int(_sGetIpAssignmentsForNode2,2) == 6) ? 16 : 4,(unsigned int)sqlite3_column_int(_sGetIpAssignmentPools2,1));
|
||||
responseBody.append(firstIp ? "\"" : ",\"");
|
||||
firstIp = false;
|
||||
responseBody.append(_jsonEscape(ip.toString()));
|
||||
responseBody.push_back('"');
|
||||
}
|
||||
|
||||
responseBody.append("]");
|
||||
|
||||
/* It's possible to get the actual netconf dictionary by including these
|
||||
* three URL arguments. The member identity must be the string
|
||||
* serialized identity of this member, and the signing identity must be
|
||||
* the full secret identity of this network controller. The have revision
|
||||
* is optional but would designate the revision our hypothetical client
|
||||
* already has.
|
||||
*
|
||||
* This is primarily for testing and is not used in production. It makes
|
||||
* it easy to test the entire network controller via its JSON API.
|
||||
*
|
||||
* If these arguments are included, three more object fields are returned:
|
||||
* 'netconf', 'netconfResult', and 'netconfResultMessage'. These are all
|
||||
* string fields and contain the actual netconf dictionary, the query
|
||||
* result code, and any verbose message e.g. an error description. */
|
||||
std::map<std::string,std::string>::const_iterator memids(urlArgs.find("memberIdentity"));
|
||||
std::map<std::string,std::string>::const_iterator sigids(urlArgs.find("signingIdentity"));
|
||||
std::map<std::string,std::string>::const_iterator hrs(urlArgs.find("haveRevision"));
|
||||
if ((memids != urlArgs.end())&&(sigids != urlArgs.end())) {
|
||||
Dictionary netconf;
|
||||
Identity memid,sigid;
|
||||
try {
|
||||
if (memid.fromString(memids->second)&&sigid.fromString(sigids->second)&&sigid.hasPrivate()) {
|
||||
uint64_t hr = 0;
|
||||
if (hrs != urlArgs.end())
|
||||
hr = Utils::strToU64(hrs->second.c_str());
|
||||
const char *result = "";
|
||||
switch(this->doNetworkConfigRequest(InetAddress(),sigid,memid,nwid,Dictionary(),hr,netconf)) {
|
||||
case NetworkController::NETCONF_QUERY_OK: result = "OK"; break;
|
||||
case NetworkController::NETCONF_QUERY_OK_BUT_NOT_NEWER: result = "OK_BUT_NOT_NEWER"; break;
|
||||
case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: result = "OBJECT_NOT_FOUND"; break;
|
||||
case NetworkController::NETCONF_QUERY_ACCESS_DENIED: result = "ACCESS_DENIED"; break;
|
||||
case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR: result = "INTERNAL_SERVER_ERROR"; break;
|
||||
default: result = "(unrecognized result code)"; break;
|
||||
}
|
||||
responseBody.append(",\n\tnetconf: \"");
|
||||
responseBody.append(_jsonEscape(netconf.toString().c_str()));
|
||||
responseBody.append("\",\n\tnetconfResult: \"");
|
||||
responseBody.append(result);
|
||||
responseBody.append("\",\n\tnetconfResultMessage: \"");
|
||||
responseBody.append(_jsonEscape(netconf["error"].c_str()));
|
||||
responseBody.append("\"");
|
||||
} else {
|
||||
responseBody.append(",\n\tnetconf: \"\",\n\tnetconfResult: \"INTERNAL_SERVER_ERROR\",\n\tnetconfResultMessage: \"invalid member or signing identity\"");
|
||||
}
|
||||
} catch ( ... ) {
|
||||
responseBody.append(",\n\tnetconf: \"\",\n\tnetconfResult: \"INTERNAL_SERVER_ERROR\",\n\tnetconfResultMessage: \"unexpected exception\"");
|
||||
}
|
||||
}
|
||||
|
||||
responseBody.append("\n}\n");
|
||||
|
||||
responseContentType = "application/json";
|
||||
return 200;
|
||||
} // else 404
|
||||
} // else 404
|
||||
} else {
|
||||
// get network info
|
||||
sqlite3_reset(_sGetNetworkById);
|
||||
sqlite3_bind_text(_sGetNetworkById,1,nwids,16,SQLITE_STATIC);
|
||||
if (sqlite3_step(_sGetNetworkById) == SQLITE_ROW) {
|
||||
Utils::snprintf(json,sizeof(json),
|
||||
"{\n"
|
||||
"\tnwid: \"%s\",\n"
|
||||
"\tname: \"%s\",\n"
|
||||
"\tprivate: %s,\n"
|
||||
"\tenableBroadcast: %s,\n"
|
||||
"\tallowPassiveBridging: %s,\n"
|
||||
"\tv4AssignMode: \"%s\",\n"
|
||||
"\tv6AssignMode: \"%s\",\n"
|
||||
"\tmulticastLimit: %d,\n"
|
||||
"\tcreationTime: %llu,\n",
|
||||
"\trevision: %llu,\n"
|
||||
"\amembers: [",
|
||||
nwids,
|
||||
_jsonEscape((const char *)sqlite3_column_text(_sGetNetworkById,0)).c_str(),
|
||||
(sqlite3_column_int(_sGetNetworkById,1) > 0) ? "true" : "false",
|
||||
(sqlite3_column_int(_sGetNetworkById,2) > 0) ? "true" : "false",
|
||||
(sqlite3_column_int(_sGetNetworkById,3) > 0) ? "true" : "false",
|
||||
_jsonEscape((const char *)sqlite3_column_text(_sGetNetworkById,4)).c_str(),
|
||||
_jsonEscape((const char *)sqlite3_column_text(_sGetNetworkById,5)).c_str(),
|
||||
sqlite3_column_int(_sGetNetworkById,6),
|
||||
(unsigned long long)sqlite3_column_int64(_sGetNetworkById,7),
|
||||
(unsigned long long)sqlite3_column_int64(_sGetNetworkById,8));
|
||||
responseBody = json;
|
||||
|
||||
sqlite3_reset(_sListNetworkMembers);
|
||||
sqlite3_bind_text(_sListNetworkMembers,1,nwids,16,SQLITE_STATIC);
|
||||
bool firstMember = true;
|
||||
while (sqlite3_step(_sListNetworkMembers) == SQLITE_ROW) {
|
||||
if (!firstMember)
|
||||
responseBody.push_back(',');
|
||||
responseBody.push_back('"');
|
||||
responseBody.append((const char *)sqlite3_column_text(_sListNetworkMembers,0));
|
||||
responseBody.push_back('"');
|
||||
firstMember = false;
|
||||
}
|
||||
responseBody.append("],\n\trelays: [");
|
||||
|
||||
sqlite3_reset(_sGetRelays);
|
||||
sqlite3_bind_text(_sGetRelays,1,nwids,16,SQLITE_STATIC);
|
||||
bool firstRelay = true;
|
||||
while (sqlite3_step(_sGetRelays) == SQLITE_ROW) {
|
||||
responseBody.append(firstRelay ? "\n\t\t" : ",\n\t\t");
|
||||
firstRelay = false;
|
||||
responseBody.append("{address:\"");
|
||||
responseBody.append((const char *)sqlite3_column_text(_sGetRelays,0));
|
||||
responseBody.append("\",phyAddress:\"");
|
||||
responseBody.append(_jsonEscape((const char *)sqlite3_column_text(_sGetRelays,1)));
|
||||
responseBody.append("\"}");
|
||||
}
|
||||
responseBody.append("],\n\tipAssignmentPools: [");
|
||||
|
||||
sqlite3_reset(_sGetIpAssignmentPools2);
|
||||
sqlite3_bind_text(_sGetIpAssignmentPools2,1,nwids,16,SQLITE_STATIC);
|
||||
bool firstIpAssignmentPool = true;
|
||||
while (sqlite3_step(_sGetIpAssignmentPools2) == SQLITE_ROW) {
|
||||
responseBody.append(firstIpAssignmentPool ? "\n\t\t" : ",\n\t\t");
|
||||
firstIpAssignmentPool = false;
|
||||
InetAddress ipp((const void *)sqlite3_column_blob(_sGetIpAssignmentPools2,0),(sqlite3_column_int(_sGetIpAssignmentPools2,2) == 6) ? 16 : 4,(unsigned int)sqlite3_column_int(_sGetIpAssignmentPools2,1));
|
||||
Utils::snprintf(json,sizeof(json),"{network:\"%s\",netmaskBits:%u}",
|
||||
_jsonEscape(ipp.toIpString()).c_str(),
|
||||
ipp.netmaskBits());
|
||||
responseBody.append(json);
|
||||
}
|
||||
responseBody.append("],\n\trules: [");
|
||||
|
||||
sqlite3_reset(_sListRules);
|
||||
sqlite3_bind_text(_sListRules,1,nwids,16,SQLITE_STATIC);
|
||||
bool firstRule = true;
|
||||
while (sqlite3_step(_sListRules) == SQLITE_ROW) {
|
||||
responseBody.append(firstRule ? "\n\t{\n" : ",{\n");
|
||||
Utils::snprintf(json,sizeof(json),"\t\truleId: %lld,\n",sqlite3_column_int64(_sListRules,0));
|
||||
responseBody.append(json);
|
||||
if (sqlite3_column_type(_sListRules,1) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\tnodeId: \"%s\",\n",(const char *)sqlite3_column_text(_sListRules,1));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,2) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\tvlanId: %d,\n",sqlite3_column_int(_sListRules,2));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,3) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\tvlanPcp: %d,\n",sqlite3_column_int(_sListRules,3));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,4) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\tetherType: %d,\n",sqlite3_column_int(_sListRules,4));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,5) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\tmacSource: \"%s\",\n",MAC((const char *)sqlite3_column_text(_sListRules,5)).toString().c_str());
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,6) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\tmacDest: \"%s\",\n",MAC((const char *)sqlite3_column_text(_sListRules,6)).toString().c_str());
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,7) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\tipSource: \"%s\",\n",_jsonEscape((const char *)sqlite3_column_text(_sListRules,7)).c_str());
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,8) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\tipDest: \"%s\",\n",_jsonEscape((const char *)sqlite3_column_text(_sListRules,8)).c_str());
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,9) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\tipTos: %d,\n",sqlite3_column_int(_sListRules,9));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,10) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\tipProtocol: %d,\n",sqlite3_column_int(_sListRules,10));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,11) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\tipSourcePort: %d,\n",sqlite3_column_int(_sListRules,11));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,12) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\tipDestPort: %d,\n",sqlite3_column_int(_sListRules,12));
|
||||
responseBody.append(json);
|
||||
}
|
||||
responseBody.append("\t\taction: \"");
|
||||
responseBody.append(_jsonEscape((const char *)sqlite3_column_text(_sListRules,13)));
|
||||
responseBody.append("\"\n\t}");
|
||||
}
|
||||
|
||||
responseBody.append("]\n}\n");
|
||||
responseContentType = "application/json";
|
||||
return 200;
|
||||
} // else 404
|
||||
}
|
||||
} else if (path.size() == 1) {
|
||||
// list networks
|
||||
sqlite3_reset(_sListNetworks);
|
||||
responseContentType = "application/json";
|
||||
responseBody = "[";
|
||||
bool first = true;
|
||||
while (sqlite3_step(_sListNetworks) == SQLITE_ROW) {
|
||||
if (first) {
|
||||
first = false;
|
||||
responseBody.push_back('"');
|
||||
} else responseBody.append(",\"");
|
||||
responseBody.append((const char *)sqlite3_column_text(_sListNetworks,0));
|
||||
responseBody.push_back('"');
|
||||
}
|
||||
responseBody.push_back(']');
|
||||
return 200;
|
||||
} // else 404
|
||||
|
||||
} else {
|
||||
// GET /controller returns status and API version if controller is supported
|
||||
Utils::snprintf(json,sizeof(json),"{\n\tcontroller: true,\n\tapiVersion: %d\n\tclock: %llu\n}",ZT_NETCONF_CONTROLLER_API_VERSION,(unsigned long long)OSUtils::now());
|
||||
responseBody = json;
|
||||
responseContentType = "applicaiton/json";
|
||||
return 200;
|
||||
}
|
||||
|
||||
return 404;
|
||||
return _doCPGet(path,urlArgs,headers,body,responseBody,responseContentType);
|
||||
}
|
||||
|
||||
unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
|
||||
|
@ -902,20 +625,25 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
|
|||
if (j) {
|
||||
if (j->type == json_object) {
|
||||
for(unsigned int k=0;k<j->u.object.length;++k) {
|
||||
sqlite3_reset(_sUpdateMemberField);
|
||||
sqlite3_bind_int64(_sUpdateMemberField,3,memberRowId);
|
||||
|
||||
if (!strcmp(j->u.object.values[k].name,"authorized")) {
|
||||
if (j->u.object.values[k].value->type == json_boolean) {
|
||||
sqlite3_bind_text(_sUpdateMemberField,1,"authorized",-1,SQLITE_STATIC);
|
||||
sqlite3_bind_int(_sUpdateMemberField,2,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1);
|
||||
sqlite3_step(_sUpdateMemberField);
|
||||
sqlite3_stmt *stmt = (sqlite3_stmt *)0;
|
||||
if (sqlite3_prepare_v2(_db,"UPDATE Member SET authorized = ? WHERE rowid = ?",-1,&stmt,(const char **)0) == SQLITE_OK)
|
||||
sqlite3_bind_int(stmt,1,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1);
|
||||
sqlite3_bind_int64(stmt,2,memberRowId);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
} else if (!strcmp(j->u.object.values[k].name,"activeBridge")) {
|
||||
if (j->u.object.values[k].value->type == json_boolean) {
|
||||
sqlite3_bind_text(_sUpdateMemberField,1,"activeBridge",-1,SQLITE_STATIC);
|
||||
sqlite3_bind_int(_sUpdateMemberField,2,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1);
|
||||
sqlite3_step(_sUpdateMemberField);
|
||||
sqlite3_stmt *stmt = (sqlite3_stmt *)0;
|
||||
if (sqlite3_prepare_v2(_db,"UPDATE Member SET activeBridge = ? WHERE rowid = ?",-1,&stmt,(const char **)0) == SQLITE_OK) {
|
||||
sqlite3_bind_int(stmt,1,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1);
|
||||
sqlite3_bind_int64(stmt,2,memberRowId);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
}
|
||||
} else if (!strcmp(j->u.object.values[k].name,"ipAssignments")) {
|
||||
if (j->u.object.values[k].value->type == json_array) {
|
||||
|
@ -957,12 +685,13 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
json_value_free(j);
|
||||
}
|
||||
|
||||
return handleControlPlaneHttpGET(path,urlArgs,headers,body,responseBody,responseContentType);
|
||||
return _doCPGet(path,urlArgs,headers,body,responseBody,responseContentType);
|
||||
} // else 404
|
||||
|
||||
} else {
|
||||
|
@ -980,50 +709,42 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
|
|||
if (j) {
|
||||
if (j->type == json_object) {
|
||||
for(unsigned int k=0;k<j->u.object.length;++k) {
|
||||
sqlite3_reset(_sUpdateNetworkField);
|
||||
sqlite3_bind_text(_sUpdateNetworkField,3,nwids,16,SQLITE_STATIC);
|
||||
sqlite3_stmt *stmt = (sqlite3_stmt *)0;
|
||||
|
||||
if (!strcmp(j->u.object.values[k].name,"name")) {
|
||||
if ((j->u.object.values[k].value->type == json_string)&&(j->u.object.values[k].value->u.string.ptr[0])) {
|
||||
sqlite3_bind_text(_sUpdateNetworkField,1,"name",-1,SQLITE_STATIC);
|
||||
sqlite3_bind_text(_sUpdateNetworkField,2,j->u.object.values[k].value->u.string.ptr,-1,SQLITE_STATIC);
|
||||
sqlite3_step(_sUpdateNetworkField);
|
||||
if (sqlite3_prepare_v2(_db,"UPDATE Network SET name = ? WHERE id = ?",-1,&stmt,(const char **)0) == SQLITE_OK)
|
||||
sqlite3_bind_text(stmt,1,j->u.object.values[k].value->u.string.ptr,-1,SQLITE_STATIC);
|
||||
}
|
||||
} else if (!strcmp(j->u.object.values[k].name,"private")) {
|
||||
if (j->u.object.values[k].value->type == json_boolean) {
|
||||
sqlite3_bind_text(_sUpdateNetworkField,1,"private",-1,SQLITE_STATIC);
|
||||
sqlite3_bind_int(_sUpdateNetworkField,2,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1);
|
||||
sqlite3_step(_sUpdateNetworkField);
|
||||
if (sqlite3_prepare_v2(_db,"UPDATE Network SET private = ? WHERE id = ?",-1,&stmt,(const char **)0) == SQLITE_OK)
|
||||
sqlite3_bind_int(stmt,1,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1);
|
||||
}
|
||||
} else if (!strcmp(j->u.object.values[k].name,"enableBroadcast")) {
|
||||
if (j->u.object.values[k].value->type == json_boolean) {
|
||||
sqlite3_bind_text(_sUpdateNetworkField,1,"enableBroadcast",-1,SQLITE_STATIC);
|
||||
sqlite3_bind_int(_sUpdateNetworkField,2,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1);
|
||||
sqlite3_step(_sUpdateNetworkField);
|
||||
if (sqlite3_prepare_v2(_db,"UPDATE Network SET enableBroadcast = ? WHERE id = ?",-1,&stmt,(const char **)0) == SQLITE_OK)
|
||||
sqlite3_bind_int(stmt,1,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1);
|
||||
}
|
||||
} else if (!strcmp(j->u.object.values[k].name,"allowPassiveBridging")) {
|
||||
if (j->u.object.values[k].value->type == json_boolean) {
|
||||
sqlite3_bind_text(_sUpdateNetworkField,1,"allowPassiveBridging",-1,SQLITE_STATIC);
|
||||
sqlite3_bind_int(_sUpdateNetworkField,2,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1);
|
||||
sqlite3_step(_sUpdateNetworkField);
|
||||
if (sqlite3_prepare_v2(_db,"UPDATE Network SET allowPassiveBridging = ? WHERE id = ?",-1,&stmt,(const char **)0) == SQLITE_OK)
|
||||
sqlite3_bind_int(stmt,1,(j->u.object.values[k].value->u.boolean == 0) ? 0 : 1);
|
||||
}
|
||||
} else if (!strcmp(j->u.object.values[k].name,"v4AssignMode")) {
|
||||
if (j->u.object.values[k].value->type == json_string) {
|
||||
sqlite3_bind_text(_sUpdateNetworkField,1,"v4AssignMode",-1,SQLITE_STATIC);
|
||||
sqlite3_bind_text(_sUpdateNetworkField,2,j->u.object.values[k].value->u.string.ptr,-1,SQLITE_STATIC);
|
||||
sqlite3_step(_sUpdateNetworkField);
|
||||
if (sqlite3_prepare_v2(_db,"UPDATE Network SET v4AssignMode = ? WHERE id = ?",-1,&stmt,(const char **)0) == SQLITE_OK)
|
||||
sqlite3_bind_text(stmt,1,j->u.object.values[k].value->u.string.ptr,-1,SQLITE_STATIC);
|
||||
}
|
||||
} else if (!strcmp(j->u.object.values[k].name,"v6AssignMode")) {
|
||||
if (j->u.object.values[k].value->type == json_string) {
|
||||
sqlite3_bind_text(_sUpdateNetworkField,1,"v6AssignMode",-1,SQLITE_STATIC);
|
||||
sqlite3_bind_text(_sUpdateNetworkField,2,j->u.object.values[k].value->u.string.ptr,-1,SQLITE_STATIC);
|
||||
sqlite3_step(_sUpdateNetworkField);
|
||||
if (sqlite3_prepare_v2(_db,"UPDATE Network SET v6AssignMode = ? WHERE id = ?",-1,&stmt,(const char **)0) == SQLITE_OK)
|
||||
sqlite3_bind_text(stmt,1,j->u.object.values[k].value->u.string.ptr,-1,SQLITE_STATIC);
|
||||
}
|
||||
} else if (!strcmp(j->u.object.values[k].name,"multicastLimit")) {
|
||||
if (j->u.object.values[k].value->type == json_integer) {
|
||||
sqlite3_bind_text(_sUpdateNetworkField,1,"multicastLimit",-1,SQLITE_STATIC);
|
||||
sqlite3_bind_int(_sUpdateNetworkField,2,(int)j->u.object.values[k].value->u.integer);
|
||||
sqlite3_step(_sUpdateNetworkField);
|
||||
if (sqlite3_prepare_v2(_db,"UPDATE Network SET multicastLimit = ? WHERE id = ?",-1,&stmt,(const char **)0) == SQLITE_OK)
|
||||
sqlite3_bind_int(stmt,1,(int)j->u.object.values[k].value->u.integer);
|
||||
}
|
||||
} else if (!strcmp(j->u.object.values[k].name,"relays")) {
|
||||
if (j->u.object.values[k].value->type == json_array) {
|
||||
|
@ -1185,6 +906,12 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (stmt) {
|
||||
sqlite3_bind_text(stmt,2,nwids,16,SQLITE_STATIC);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
}
|
||||
}
|
||||
}
|
||||
json_value_free(j);
|
||||
|
@ -1195,7 +922,7 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpPOST(
|
|||
sqlite3_bind_text(_sSetNetworkRevision,2,nwids,16,SQLITE_STATIC);
|
||||
sqlite3_step(_sSetNetworkRevision);
|
||||
|
||||
return handleControlPlaneHttpGET(path,urlArgs,headers,body,responseBody,responseContentType);
|
||||
return _doCPGet(path,urlArgs,headers,body,responseBody,responseContentType);
|
||||
}
|
||||
|
||||
} // else 404
|
||||
|
@ -1260,4 +987,287 @@ unsigned int SqliteNetworkController::handleControlPlaneHttpDELETE(
|
|||
return 404;
|
||||
}
|
||||
|
||||
unsigned int SqliteNetworkController::_doCPGet(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType)
|
||||
{
|
||||
// Assumes _lock is locked
|
||||
char json[16384];
|
||||
|
||||
if ((path.size() > 0)&&(path[0] == "network")) {
|
||||
|
||||
if ((path.size() >= 2)&&(path[1].length() == 16)) {
|
||||
uint64_t nwid = Utils::hexStrToU64(path[1].c_str());
|
||||
char nwids[24];
|
||||
Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid);
|
||||
|
||||
if (path.size() >= 3) {
|
||||
if ((path.size() == 4)&&(path[2] == "member")&&(path[3].length() == 10)) {
|
||||
uint64_t address = Utils::hexStrToU64(path[3].c_str());
|
||||
char addrs[24];
|
||||
Utils::snprintf(addrs,sizeof(addrs),"%.10llx",address);
|
||||
|
||||
sqlite3_reset(_sGetMember2);
|
||||
sqlite3_bind_text(_sGetMember2,1,nwids,16,SQLITE_STATIC);
|
||||
sqlite3_bind_text(_sGetMember2,2,addrs,10,SQLITE_STATIC);
|
||||
if (sqlite3_step(_sGetMember2) == SQLITE_ROW) {
|
||||
Utils::snprintf(json,sizeof(json),
|
||||
"{\n"
|
||||
"\t\"nwid\": \"%s\",\n"
|
||||
"\t\"address\": \"%s\",\n"
|
||||
"\t\"authorized\": %s,\n"
|
||||
"\t\"activeBridge\": %s,\n"
|
||||
"\t\"lastAt\": \"%s\",\n"
|
||||
"\t\"lastSeen\": %llu,\n"
|
||||
"\t\"firstSeen\": %llu,\n"
|
||||
"\t\"identity\": \"%s\",\n"
|
||||
"\t\"ipAssignments\": [",
|
||||
nwids,
|
||||
addrs,
|
||||
(sqlite3_column_int(_sGetMember2,0) > 0) ? "true" : "false",
|
||||
(sqlite3_column_int(_sGetMember2,1) > 0) ? "true" : "false",
|
||||
_jsonEscape((const char *)sqlite3_column_text(_sGetMember2,3)).c_str(),
|
||||
(unsigned long long)sqlite3_column_int64(_sGetMember2,4),
|
||||
(unsigned long long)sqlite3_column_int64(_sGetMember2,5),
|
||||
_jsonEscape((const char *)sqlite3_column_text(_sGetMember2,2)).c_str());
|
||||
responseBody = json;
|
||||
|
||||
sqlite3_reset(_sGetIpAssignmentsForNode2);
|
||||
sqlite3_bind_text(_sGetIpAssignmentsForNode2,1,nwids,16,SQLITE_STATIC);
|
||||
sqlite3_bind_text(_sGetIpAssignmentsForNode2,2,addrs,10,SQLITE_STATIC);
|
||||
bool firstIp = true;
|
||||
while (sqlite3_step(_sGetIpAssignmentPools2) == SQLITE_ROW) {
|
||||
InetAddress ip((const void *)sqlite3_column_blob(_sGetIpAssignmentsForNode2,0),(sqlite3_column_int(_sGetIpAssignmentsForNode2,2) == 6) ? 16 : 4,(unsigned int)sqlite3_column_int(_sGetIpAssignmentPools2,1));
|
||||
responseBody.append(firstIp ? "\"" : ",\"");
|
||||
firstIp = false;
|
||||
responseBody.append(_jsonEscape(ip.toString()));
|
||||
responseBody.push_back('"');
|
||||
}
|
||||
|
||||
responseBody.append("]");
|
||||
|
||||
/* It's possible to get the actual netconf dictionary by including these
|
||||
* three URL arguments. The member identity must be the string
|
||||
* serialized identity of this member, and the signing identity must be
|
||||
* the full secret identity of this network controller. The have revision
|
||||
* is optional but would designate the revision our hypothetical client
|
||||
* already has.
|
||||
*
|
||||
* This is primarily for testing and is not used in production. It makes
|
||||
* it easy to test the entire network controller via its JSON API.
|
||||
*
|
||||
* If these arguments are included, three more object fields are returned:
|
||||
* 'netconf', 'netconfResult', and 'netconfResultMessage'. These are all
|
||||
* string fields and contain the actual netconf dictionary, the query
|
||||
* result code, and any verbose message e.g. an error description. */
|
||||
std::map<std::string,std::string>::const_iterator memids(urlArgs.find("memberIdentity"));
|
||||
std::map<std::string,std::string>::const_iterator sigids(urlArgs.find("signingIdentity"));
|
||||
std::map<std::string,std::string>::const_iterator hrs(urlArgs.find("haveRevision"));
|
||||
if ((memids != urlArgs.end())&&(sigids != urlArgs.end())) {
|
||||
Dictionary netconf;
|
||||
Identity memid,sigid;
|
||||
try {
|
||||
if (memid.fromString(memids->second)&&sigid.fromString(sigids->second)&&sigid.hasPrivate()) {
|
||||
uint64_t hr = 0;
|
||||
if (hrs != urlArgs.end())
|
||||
hr = Utils::strToU64(hrs->second.c_str());
|
||||
const char *result = "";
|
||||
switch(this->doNetworkConfigRequest(InetAddress(),sigid,memid,nwid,Dictionary(),hr,netconf)) {
|
||||
case NetworkController::NETCONF_QUERY_OK: result = "OK"; break;
|
||||
case NetworkController::NETCONF_QUERY_OK_BUT_NOT_NEWER: result = "OK_BUT_NOT_NEWER"; break;
|
||||
case NetworkController::NETCONF_QUERY_OBJECT_NOT_FOUND: result = "OBJECT_NOT_FOUND"; break;
|
||||
case NetworkController::NETCONF_QUERY_ACCESS_DENIED: result = "ACCESS_DENIED"; break;
|
||||
case NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR: result = "INTERNAL_SERVER_ERROR"; break;
|
||||
default: result = "(unrecognized result code)"; break;
|
||||
}
|
||||
responseBody.append(",\n\t\"netconf\": \"");
|
||||
responseBody.append(_jsonEscape(netconf.toString().c_str()));
|
||||
responseBody.append("\",\n\t\"netconfResult\": \"");
|
||||
responseBody.append(result);
|
||||
responseBody.append("\",\n\t\"netconfResultMessage\": \"");
|
||||
responseBody.append(_jsonEscape(netconf["error"].c_str()));
|
||||
responseBody.append("\"");
|
||||
} else {
|
||||
responseBody.append(",\n\t\"netconf\": \"\",\n\t\"netconfResult\": \"INTERNAL_SERVER_ERROR\",\n\t\"netconfResultMessage\": \"invalid member or signing identity\"");
|
||||
}
|
||||
} catch ( ... ) {
|
||||
responseBody.append(",\n\t\"netconf\": \"\",\n\t\"netconfResult\": \"INTERNAL_SERVER_ERROR\",\n\t\"netconfResultMessage\": \"unexpected exception\"");
|
||||
}
|
||||
}
|
||||
|
||||
responseBody.append("\n}\n");
|
||||
|
||||
responseContentType = "application/json";
|
||||
return 200;
|
||||
} // else 404
|
||||
} // else 404
|
||||
} else {
|
||||
// get network info
|
||||
sqlite3_reset(_sGetNetworkById);
|
||||
sqlite3_bind_text(_sGetNetworkById,1,nwids,16,SQLITE_STATIC);
|
||||
if (sqlite3_step(_sGetNetworkById) == SQLITE_ROW) {
|
||||
Utils::snprintf(json,sizeof(json),
|
||||
"{\n"
|
||||
"\t\"nwid\": \"%s\",\n"
|
||||
"\t\"name\": \"%s\",\n"
|
||||
"\t\"private\": %s,\n"
|
||||
"\t\"enableBroadcast\": %s,\n"
|
||||
"\t\"allowPassiveBridging\": %s,\n"
|
||||
"\t\"v4AssignMode\": \"%s\",\n"
|
||||
"\t\"v6AssignMode\": \"%s\",\n"
|
||||
"\t\"multicastLimit\": %d,\n"
|
||||
"\t\"creationTime\": %llu,\n"
|
||||
"\t\"revision\": %llu,\n"
|
||||
"\t\"members\": [",
|
||||
nwids,
|
||||
_jsonEscape((const char *)sqlite3_column_text(_sGetNetworkById,0)).c_str(),
|
||||
(sqlite3_column_int(_sGetNetworkById,1) > 0) ? "true" : "false",
|
||||
(sqlite3_column_int(_sGetNetworkById,2) > 0) ? "true" : "false",
|
||||
(sqlite3_column_int(_sGetNetworkById,3) > 0) ? "true" : "false",
|
||||
_jsonEscape((const char *)sqlite3_column_text(_sGetNetworkById,4)).c_str(),
|
||||
_jsonEscape((const char *)sqlite3_column_text(_sGetNetworkById,5)).c_str(),
|
||||
sqlite3_column_int(_sGetNetworkById,6),
|
||||
(unsigned long long)sqlite3_column_int64(_sGetNetworkById,7),
|
||||
(unsigned long long)sqlite3_column_int64(_sGetNetworkById,8));
|
||||
responseBody = json;
|
||||
|
||||
sqlite3_reset(_sListNetworkMembers);
|
||||
sqlite3_bind_text(_sListNetworkMembers,1,nwids,16,SQLITE_STATIC);
|
||||
bool firstMember = true;
|
||||
while (sqlite3_step(_sListNetworkMembers) == SQLITE_ROW) {
|
||||
if (!firstMember)
|
||||
responseBody.push_back(',');
|
||||
responseBody.push_back('"');
|
||||
responseBody.append((const char *)sqlite3_column_text(_sListNetworkMembers,0));
|
||||
responseBody.push_back('"');
|
||||
firstMember = false;
|
||||
}
|
||||
responseBody.append("],\n\t\"relays\": [");
|
||||
|
||||
sqlite3_reset(_sGetRelays);
|
||||
sqlite3_bind_text(_sGetRelays,1,nwids,16,SQLITE_STATIC);
|
||||
bool firstRelay = true;
|
||||
while (sqlite3_step(_sGetRelays) == SQLITE_ROW) {
|
||||
responseBody.append(firstRelay ? "\n\t\t" : ",\n\t\t");
|
||||
firstRelay = false;
|
||||
responseBody.append("{\"address\":\"");
|
||||
responseBody.append((const char *)sqlite3_column_text(_sGetRelays,0));
|
||||
responseBody.append("\",\"phyAddress\":\"");
|
||||
responseBody.append(_jsonEscape((const char *)sqlite3_column_text(_sGetRelays,1)));
|
||||
responseBody.append("\"}");
|
||||
}
|
||||
responseBody.append("],\n\t\"ipAssignmentPools\": [");
|
||||
|
||||
sqlite3_reset(_sGetIpAssignmentPools2);
|
||||
sqlite3_bind_text(_sGetIpAssignmentPools2,1,nwids,16,SQLITE_STATIC);
|
||||
bool firstIpAssignmentPool = true;
|
||||
while (sqlite3_step(_sGetIpAssignmentPools2) == SQLITE_ROW) {
|
||||
responseBody.append(firstIpAssignmentPool ? "\n\t\t" : ",\n\t\t");
|
||||
firstIpAssignmentPool = false;
|
||||
InetAddress ipp((const void *)sqlite3_column_blob(_sGetIpAssignmentPools2,0),(sqlite3_column_int(_sGetIpAssignmentPools2,2) == 6) ? 16 : 4,(unsigned int)sqlite3_column_int(_sGetIpAssignmentPools2,1));
|
||||
Utils::snprintf(json,sizeof(json),"{\"network\":\"%s\",\"netmaskBits\":%u}",
|
||||
_jsonEscape(ipp.toIpString()).c_str(),
|
||||
ipp.netmaskBits());
|
||||
responseBody.append(json);
|
||||
}
|
||||
responseBody.append("],\n\t\"rules\": [");
|
||||
|
||||
sqlite3_reset(_sListRules);
|
||||
sqlite3_bind_text(_sListRules,1,nwids,16,SQLITE_STATIC);
|
||||
bool firstRule = true;
|
||||
while (sqlite3_step(_sListRules) == SQLITE_ROW) {
|
||||
responseBody.append(firstRule ? "\n\t{\n" : ",{\n");
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"ruleId\": %lld,\n",sqlite3_column_int64(_sListRules,0));
|
||||
responseBody.append(json);
|
||||
if (sqlite3_column_type(_sListRules,1) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"nodeId\": \"%s\",\n",(const char *)sqlite3_column_text(_sListRules,1));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,2) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"vlanId\": %d,\n",sqlite3_column_int(_sListRules,2));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,3) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"vlanPcp\": %d,\n",sqlite3_column_int(_sListRules,3));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,4) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"etherType\": %d,\n",sqlite3_column_int(_sListRules,4));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,5) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"macSource\": \"%s\",\n",MAC((const char *)sqlite3_column_text(_sListRules,5)).toString().c_str());
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,6) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"macDest\": \"%s\",\n",MAC((const char *)sqlite3_column_text(_sListRules,6)).toString().c_str());
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,7) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"ipSource\": \"%s\",\n",_jsonEscape((const char *)sqlite3_column_text(_sListRules,7)).c_str());
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,8) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"ipDest\": \"%s\",\n",_jsonEscape((const char *)sqlite3_column_text(_sListRules,8)).c_str());
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,9) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"ipTos\": %d,\n",sqlite3_column_int(_sListRules,9));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,10) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"ipProtocol\": %d,\n",sqlite3_column_int(_sListRules,10));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,11) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"ipSourcePort\": %d,\n",sqlite3_column_int(_sListRules,11));
|
||||
responseBody.append(json);
|
||||
}
|
||||
if (sqlite3_column_type(_sListRules,12) != SQLITE_NULL) {
|
||||
Utils::snprintf(json,sizeof(json),"\t\t\"ipDestPort\": %d,\n",sqlite3_column_int(_sListRules,12));
|
||||
responseBody.append(json);
|
||||
}
|
||||
responseBody.append("\t\t\"action\": \"");
|
||||
responseBody.append(_jsonEscape((const char *)sqlite3_column_text(_sListRules,13)));
|
||||
responseBody.append("\"\n\t}");
|
||||
}
|
||||
|
||||
responseBody.append("]\n}\n");
|
||||
responseContentType = "application/json";
|
||||
return 200;
|
||||
} // else 404
|
||||
}
|
||||
} else if (path.size() == 1) {
|
||||
// list networks
|
||||
sqlite3_reset(_sListNetworks);
|
||||
responseContentType = "application/json";
|
||||
responseBody = "[";
|
||||
bool first = true;
|
||||
while (sqlite3_step(_sListNetworks) == SQLITE_ROW) {
|
||||
if (first) {
|
||||
first = false;
|
||||
responseBody.push_back('"');
|
||||
} else responseBody.append(",\"");
|
||||
responseBody.append((const char *)sqlite3_column_text(_sListNetworks,0));
|
||||
responseBody.push_back('"');
|
||||
}
|
||||
responseBody.push_back(']');
|
||||
return 200;
|
||||
} // else 404
|
||||
|
||||
} else {
|
||||
// GET /controller returns status and API version if controller is supported
|
||||
Utils::snprintf(json,sizeof(json),"{\n\t\"controller\": true,\n\t\"apiVersion\": %d,\n\t\"clock\": %llu\n}",ZT_NETCONF_CONTROLLER_API_VERSION,(unsigned long long)OSUtils::now());
|
||||
responseBody = json;
|
||||
responseContentType = "applicaiton/json";
|
||||
return 200;
|
||||
}
|
||||
|
||||
return 404;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
|
|
@ -40,17 +40,14 @@
|
|||
#include "../node/NetworkController.hpp"
|
||||
#include "../node/Mutex.hpp"
|
||||
|
||||
#include "../service/ControlPlaneSubsystem.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class SqliteNetworkController : public NetworkController,public ControlPlaneSubsystem
|
||||
class SqliteNetworkController : public NetworkController
|
||||
{
|
||||
public:
|
||||
SqliteNetworkController(const char *dbPath);
|
||||
virtual ~SqliteNetworkController();
|
||||
|
||||
// NetworkController
|
||||
virtual NetworkController::ResultCode doNetworkConfigRequest(
|
||||
const InetAddress &fromAddr,
|
||||
const Identity &signingId,
|
||||
|
@ -60,22 +57,21 @@ public:
|
|||
uint64_t haveRevision,
|
||||
Dictionary &netconf);
|
||||
|
||||
// ControlPlaneSubsystem
|
||||
virtual unsigned int handleControlPlaneHttpGET(
|
||||
unsigned int handleControlPlaneHttpGET(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType);
|
||||
virtual unsigned int handleControlPlaneHttpPOST(
|
||||
unsigned int handleControlPlaneHttpPOST(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType);
|
||||
virtual unsigned int handleControlPlaneHttpDELETE(
|
||||
unsigned int handleControlPlaneHttpDELETE(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
|
@ -84,6 +80,14 @@ public:
|
|||
std::string &responseContentType);
|
||||
|
||||
private:
|
||||
unsigned int _doCPGet(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType);
|
||||
|
||||
std::string _dbPath;
|
||||
sqlite3 *_db;
|
||||
|
||||
|
@ -110,7 +114,6 @@ private:
|
|||
sqlite3_stmt *_sListRules;
|
||||
sqlite3_stmt *_sCreateRule;
|
||||
sqlite3_stmt *_sCreateNetwork;
|
||||
sqlite3_stmt *_sUpdateNetworkField;
|
||||
sqlite3_stmt *_sGetNetworkRevision;
|
||||
sqlite3_stmt *_sSetNetworkRevision;
|
||||
sqlite3_stmt *_sGetIpAssignmentsForNode2;
|
||||
|
@ -119,7 +122,6 @@ private:
|
|||
sqlite3_stmt *_sDeleteIpAssignmentPoolsForNetwork;
|
||||
sqlite3_stmt *_sDeleteRulesForNetwork;
|
||||
sqlite3_stmt *_sCreateIpAssignmentPool;
|
||||
sqlite3_stmt *_sUpdateMemberField;
|
||||
sqlite3_stmt *_sDeleteMember;
|
||||
sqlite3_stmt *_sDeleteNetworkAndRelated;
|
||||
|
||||
|
|
|
@ -30,10 +30,6 @@
|
|||
"CREATE TABLE Member (\n"\
|
||||
" networkId char(16) NOT NULL,\n"\
|
||||
" nodeId char(10) NOT NULL,\n"\
|
||||
" cachedNetconf blob(4096),\n"\
|
||||
" cachedNetconfRevision integer NOT NULL DEFAULT(0),\n"\
|
||||
" cachedNetconfTimestamp integer NOT NULL DEFAULT(0),\n"\
|
||||
" clientReportedRevision integer NOT NULL DEFAULT(0),\n"\
|
||||
" authorized integer NOT NULL DEFAULT(0),\n"\
|
||||
" activeBridge integer NOT NULL DEFAULT(0)\n"\
|
||||
");\n"\
|
||||
|
|
137
nodejs-zt1-client/index.js
Normal file
137
nodejs-zt1-client/index.js
Normal file
|
@ -0,0 +1,137 @@
|
|||
'use strict'
|
||||
|
||||
var request = require('request');
|
||||
|
||||
function ZT1Client(url,authToken)
|
||||
{
|
||||
this.url = url;
|
||||
this.authToken = authToken;
|
||||
}
|
||||
|
||||
ZT1Client.prototype._jsonGet = function(getPath,callback)
|
||||
{
|
||||
request({
|
||||
url: this.url + getPath,
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-ZT1-Auth': this.authToken
|
||||
}
|
||||
},function(error,response,body) {
|
||||
if (error)
|
||||
return callback(error,null);
|
||||
if (response.statusCode !== 200)
|
||||
return callback(new Error('server responded with error: '+response.statusCode),null);
|
||||
return callback(null,(typeof body === 'string') ? JSON.parse(body) : null);
|
||||
});
|
||||
};
|
||||
|
||||
ZT1Client.prototype.status = function(callback)
|
||||
{
|
||||
request({
|
||||
url: this.url + 'controller',
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-ZT1-Auth': this.authToken
|
||||
}
|
||||
},function(error,response,body) {
|
||||
if (error)
|
||||
return callback(error,{});
|
||||
var controllerStatus = {};
|
||||
if (typeof body === 'string')
|
||||
controllerStatus = JSON.parse(body);
|
||||
request({
|
||||
url: this.url + 'status',
|
||||
method: 'GET',
|
||||
headers: {
|
||||
'X-ZT1-Auth': this.authToken
|
||||
}
|
||||
},function(error,response,body) {
|
||||
if (error)
|
||||
return callback(error,{});
|
||||
if (response.statusCode !== 200)
|
||||
return callback(new Error('server responded with '+response.statusCode),{});
|
||||
var nodeStatus = JSON.parse(body);
|
||||
for(var k in controllerStatus)
|
||||
nodeStatus[k] = controllerStatus[k];
|
||||
return callback(null,nodeStatus);
|
||||
}.bind(this));
|
||||
}.bind(this));
|
||||
};
|
||||
|
||||
ZT1Client.prototype.getNetworks = function(callback)
|
||||
{
|
||||
this._jsonGet('network',callback);
|
||||
};
|
||||
|
||||
ZT1Client.prototype.getPeers = function(callback)
|
||||
{
|
||||
this._jsonGet('peer',callback);
|
||||
};
|
||||
|
||||
ZT1Client.prototype.listControllerNetworks = function(callback)
|
||||
{
|
||||
this._jsonGet('controller/network',callback);
|
||||
};
|
||||
|
||||
ZT1Client.prototype.getControllerNetwork = function(nwid,callback)
|
||||
{
|
||||
this._jsonGet('controller/network/' + nwid,callback);
|
||||
};
|
||||
|
||||
ZT1Client.prototype.saveControllerNetwork = function(network,callback)
|
||||
{
|
||||
if ((typeof network.nwid !== 'string')||(network.nwid.length !== 16))
|
||||
return callback(new Error('Missing required field: nwid'),null);
|
||||
|
||||
// The ZT1 service is type variation intolerant, so recreate our submission with the correct types
|
||||
var n = {
|
||||
nwid: network.nwid
|
||||
};
|
||||
if (network.name)
|
||||
n.name = network.name.toString();
|
||||
if ('private' in network)
|
||||
n.private = (network.private) ? true : false;
|
||||
if ('enableBroadcast' in network)
|
||||
n.enableBroadcast = (network.enableBroadcast) ? true : false;
|
||||
if ('allowPassiveBridging' in network)
|
||||
n.allowPassiveBridging = (network.allowPassiveBridging) ? true : false;
|
||||
if ('v4AssignMode' in network) {
|
||||
if (network.v4AssignMode)
|
||||
n.v4AssignMode = network.v4AssignMode.toString();
|
||||
else n.v4AssignMode = 'none';
|
||||
}
|
||||
if ('v6AssignMode' in network) {
|
||||
if (network.v6AssignMode)
|
||||
n.v6AssignMode = network.v6AssignMode.toString();
|
||||
else n.v4AssignMode = 'none';
|
||||
}
|
||||
if ('multicastLimit' in network) {
|
||||
if (typeof network.multicastLimit === 'number')
|
||||
n.multicastLimit = network.multicastLimit;
|
||||
else n.multicastLimit = parseInt(network.multicastLimit.toString());
|
||||
}
|
||||
if (Array.isArray(network.relays))
|
||||
n.relays = network.relays;
|
||||
if (Array.isArray(network.ipAssignmentPools))
|
||||
n.ipAssignmentPools = network.ipAssignmentPools;
|
||||
if (Array.isArray(network.rules))
|
||||
n.rules = network.rules;
|
||||
|
||||
request({
|
||||
url: this.url + 'controller/network/' + n.nwid,
|
||||
method: 'POST',
|
||||
json: true,
|
||||
body: n,
|
||||
headers: {
|
||||
'X-ZT1-Auth': this.authToken
|
||||
}
|
||||
},function(err,response,body) {
|
||||
if (err)
|
||||
return callback(err,null);
|
||||
if (response.statusCode !== 200)
|
||||
return callback(new Error('server responded with error: '+response.statusCode),null);
|
||||
return callback(null,(typeof body === 'string') ? JSON.parse(body) : body);
|
||||
});
|
||||
};
|
||||
|
||||
exports.ZT1Client = ZT1Client;
|
14
nodejs-zt1-client/package.json
Normal file
14
nodejs-zt1-client/package.json
Normal file
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "nodejs-zt1-client",
|
||||
"version": "1.0.0",
|
||||
"description": "ZeroTier One Network Virtualization Service JSON API Client",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "ZeroTier, Inc.",
|
||||
"license": "BSD",
|
||||
"dependencies": {
|
||||
"request": "^2.55.0"
|
||||
}
|
||||
}
|
33
nodejs-zt1-client/test.js
Normal file
33
nodejs-zt1-client/test.js
Normal file
|
@ -0,0 +1,33 @@
|
|||
var ZT1Client = require('./index.js').ZT1Client;
|
||||
|
||||
var zt1c = new ZT1Client('http://127.0.0.1:9993/','5d6181b71fae2684f9cc64ed');
|
||||
|
||||
zt1c.status(function(err,status) {
|
||||
if (err)
|
||||
console.log(err);
|
||||
else console.log(status);
|
||||
|
||||
zt1c.getNetworks(function(err,networks) {
|
||||
if (err)
|
||||
console.log(err);
|
||||
else console.log(networks);
|
||||
|
||||
zt1c.getPeers(function(err,peers) {
|
||||
if (err)
|
||||
console.log(err);
|
||||
else console.log(peers);
|
||||
|
||||
if (status.controller) {
|
||||
zt1c.saveControllerNetwork({
|
||||
nwid: status.address + 'dead01',
|
||||
name: 'test network',
|
||||
private: true
|
||||
},function(err,network) {
|
||||
if (err)
|
||||
console.log(err);
|
||||
else console.log(network);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
18
one.cpp
18
one.cpp
|
@ -881,6 +881,7 @@ static void printHelp(const char *cn,FILE *out)
|
|||
fprintf(out,"Available switches:"ZT_EOL_S);
|
||||
fprintf(out," -h - Display this help"ZT_EOL_S);
|
||||
fprintf(out," -v - Show version"ZT_EOL_S);
|
||||
fprintf(out," -U - Run as unprivileged user (skip privilege check)"ZT_EOL_S);
|
||||
fprintf(out," -p<port> - Port for UDP and TCP/HTTP (default: 9993)"ZT_EOL_S);
|
||||
//fprintf(out," -T<path> - Override root topology, do not authenticate or update"ZT_EOL_S);
|
||||
#ifdef __UNIX_LIKE__
|
||||
|
@ -945,6 +946,7 @@ int main(int argc,char **argv)
|
|||
std::string overrideRootTopology;
|
||||
std::string homeDir;
|
||||
unsigned int port = ZT1_DEFAULT_PORT;
|
||||
bool skipRootCheck = false;
|
||||
|
||||
for(int i=1;i<argc;++i) {
|
||||
if (argv[i][0] == '-') {
|
||||
|
@ -964,6 +966,10 @@ int main(int argc,char **argv)
|
|||
break;
|
||||
#endif // __UNIX_LIKE__
|
||||
|
||||
case 'U':
|
||||
skipRootCheck = true;
|
||||
break;
|
||||
|
||||
case 'T': // Override root topology
|
||||
if (argv[i][2]) {
|
||||
if (!OSUtils::readFile(argv[i] + 2,overrideRootTopology)) {
|
||||
|
@ -1082,11 +1088,10 @@ int main(int argc,char **argv)
|
|||
}
|
||||
|
||||
#ifdef __UNIX_LIKE__
|
||||
if (getuid() != 0) {
|
||||
if ((!skipRootCheck)&&(getuid() != 0)) {
|
||||
fprintf(stderr,"%s: must be run as root (uid 0)"ZT_EOL_S,argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (runAsDaemon) {
|
||||
long p = (long)fork();
|
||||
if (p < 0) {
|
||||
|
@ -1102,10 +1107,13 @@ int main(int argc,char **argv)
|
|||
if (winRunFromCommandLine) {
|
||||
// Running in "interactive" mode (mostly for debugging)
|
||||
if (IsCurrentUserLocalAdministrator() != TRUE) {
|
||||
fprintf(stderr,"%s: must be run as a local administrator."ZT_EOL_S,argv[0]);
|
||||
return 1;
|
||||
if (!skipRootCheck) {
|
||||
fprintf(stderr,"%s: must be run as a local administrator."ZT_EOL_S,argv[0]);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
_winPokeAHole();
|
||||
}
|
||||
_winPokeAHole();
|
||||
SetConsoleCtrlHandler(&_winConsoleCtrlHandler,TRUE);
|
||||
// continues on to ordinary command line execution code below...
|
||||
} else {
|
||||
|
|
|
@ -26,7 +26,6 @@
|
|||
*/
|
||||
|
||||
#include "ControlPlane.hpp"
|
||||
#include "ControlPlaneSubsystem.hpp"
|
||||
#include "OneService.hpp"
|
||||
|
||||
#include "../version.h"
|
||||
|
@ -34,6 +33,8 @@
|
|||
|
||||
#include "../ext/http-parser/http_parser.h"
|
||||
|
||||
#include "../controller/SqliteNetworkController.hpp"
|
||||
|
||||
#include "../node/InetAddress.hpp"
|
||||
#include "../node/Node.hpp"
|
||||
#include "../node/Utils.hpp"
|
||||
|
@ -444,7 +445,7 @@ unsigned int ControlPlane::handleRequest(
|
|||
responseContentType = "text/plain";
|
||||
scode = 200;
|
||||
} else {
|
||||
std::map<std::string,ControlPlaneSubsystem *>::const_iterator ss(_subsystems.find(ps[0]));
|
||||
std::map<std::string,SqliteNetworkController *>::const_iterator ss(_subsystems.find(ps[0]));
|
||||
if (ss != _subsystems.end())
|
||||
scode = ss->second->handleControlPlaneHttpGET(std::vector<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
|
||||
else scode = 404;
|
||||
|
@ -477,7 +478,7 @@ unsigned int ControlPlane::handleRequest(
|
|||
} else scode = 500;
|
||||
}
|
||||
} else {
|
||||
std::map<std::string,ControlPlaneSubsystem *>::const_iterator ss(_subsystems.find(ps[0]));
|
||||
std::map<std::string,SqliteNetworkController *>::const_iterator ss(_subsystems.find(ps[0]));
|
||||
if (ss != _subsystems.end())
|
||||
scode = ss->second->handleControlPlaneHttpPOST(std::vector<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
|
||||
else scode = 404;
|
||||
|
@ -509,7 +510,7 @@ unsigned int ControlPlane::handleRequest(
|
|||
_node->freeQueryResult((void *)nws);
|
||||
} else scode = 500;
|
||||
} else {
|
||||
std::map<std::string,ControlPlaneSubsystem *>::const_iterator ss(_subsystems.find(ps[0]));
|
||||
std::map<std::string,SqliteNetworkController *>::const_iterator ss(_subsystems.find(ps[0]));
|
||||
if (ss != _subsystems.end())
|
||||
scode = ss->second->handleControlPlaneHttpDELETE(std::vector<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
|
||||
else scode = 404;
|
||||
|
|
|
@ -40,7 +40,7 @@ namespace ZeroTier {
|
|||
|
||||
class OneService;
|
||||
class Node;
|
||||
class ControlPlaneSubsystem;
|
||||
class SqliteNetworkController;
|
||||
struct InetAddress;
|
||||
|
||||
/**
|
||||
|
@ -72,7 +72,7 @@ public:
|
|||
* @param prefix First element in URI path
|
||||
* @param subsys Object to call for results of GET and POST/PUT operations
|
||||
*/
|
||||
inline void mount(const char *prefix,ControlPlaneSubsystem *subsys)
|
||||
inline void mount(const char *prefix,SqliteNetworkController *subsys)
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
_subsystems[std::string(prefix)] = subsys;
|
||||
|
@ -104,7 +104,7 @@ private:
|
|||
Node *const _node;
|
||||
std::string _uiStaticPath;
|
||||
std::set<std::string> _authTokens;
|
||||
std::map<std::string,ControlPlaneSubsystem *> _subsystems;
|
||||
std::map<std::string,SqliteNetworkController *> _subsystems;
|
||||
Mutex _lock;
|
||||
};
|
||||
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* ZeroTier may be used and distributed under the terms of the GPLv3, which
|
||||
* are available at: http://www.gnu.org/licenses/gpl-3.0.html
|
||||
*
|
||||
* If you would like to embed ZeroTier into a commercial application or
|
||||
* redistribute it in a modified binary form, please contact ZeroTier Networks
|
||||
* LLC. Start here: http://www.zerotier.com/
|
||||
*/
|
||||
|
||||
#ifndef ZT_CONTROLPLANESUBSYSTEM_HPP
|
||||
#define ZT_CONTROLPLANESUBSYSTEM_HPP
|
||||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* Base class for subsystems that can be mounted under the HTTP control plane
|
||||
*
|
||||
* Handlers should fill in responseBody and responseContentType and return
|
||||
* a HTTP status code or 0 on other errors.
|
||||
*/
|
||||
class ControlPlaneSubsystem
|
||||
{
|
||||
public:
|
||||
ControlPlaneSubsystem() {}
|
||||
virtual ~ControlPlaneSubsystem() {}
|
||||
|
||||
virtual unsigned int handleControlPlaneHttpGET(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType) = 0;
|
||||
|
||||
virtual unsigned int handleControlPlaneHttpPOST(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType) = 0;
|
||||
|
||||
virtual unsigned int handleControlPlaneHttpDELETE(
|
||||
const std::vector<std::string> &path,
|
||||
const std::map<std::string,std::string> &urlArgs,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType) = 0;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
|
@ -233,7 +233,7 @@ public:
|
|||
_controlPlane = new ControlPlane(this,_node,(_homePath + ZT_PATH_SEPARATOR_S + "ui").c_str());
|
||||
_controlPlane->addAuthToken(authToken.c_str());
|
||||
if (_master)
|
||||
_controlPlane->mount("controller",reinterpret_cast<ControlPlaneSubsystem *>(_master));
|
||||
_controlPlane->mount("controller",reinterpret_cast<SqliteNetworkController *>(_master));
|
||||
|
||||
{ // Remember networks from previous session
|
||||
std::vector<std::string> networksDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S + "networks.d").c_str()));
|
||||
|
|
|
@ -11,7 +11,7 @@ The JSON API supports GET, POST/PUT, and DELETE. PUT is treated as a synonym for
|
|||
|
||||
Values POSTed to the JSON API are *extremely* type sensitive. Things *must* be of the indicated type, otherwise they will be ignored or will generate an error. Anything quoted is a string so booleans and integers must lack quotes. Booleans must be *true* or *false* and nothing else. Integers cannot contain decimal points or they are floats (and vice versa). If something seems to be getting ignored or set to a strange value, or if you receive errors, check the type of all JSON fields you are submitting against the types listed below. Unrecognized fields in JSON objects are also ignored.
|
||||
|
||||
API requests must be authenticated via an authentication token. ZeroTier One saves this token in the *authtoken.secret* file in its working directory. This token may be supplied via the *authToken* URL parameter (e.g. '?authToken=...') or via the *X-ZT1-Auth* HTTP request header. Static UI pages are the only thing the server will allow without authentication.
|
||||
API requests must be authenticated via an authentication token. ZeroTier One saves this token in the *authtoken.secret* file in its working directory. This token may be supplied via the *auth* URL parameter (e.g. '?auth=...') or via the *X-ZT1-Auth* HTTP request header. Static UI pages are the only thing the server will allow without authentication.
|
||||
|
||||
A *jsonp* URL argument may be supplied to request JSONP encapsulation. A JSONP response is sent as a script with its JSON response payload wrapped in a call to the function name supplied as the argument to *jsonp*.
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue