mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-02-22 10:20:52 +00:00
use cpp-httplib for HTTP control plane (#1979)
refactored the old control plane code to use [cpp-httplib](https://github.com/yhirose/cpp-httplib) instead of a hand rolled HTTP server. Makes the control plane code much more legible. Also no longer randomly stops responding.
This commit is contained in:
parent
411e54023a
commit
e5fc89821f
@ -15,9 +15,12 @@
|
|||||||
|
|
||||||
namespace ZeroTier {
|
namespace ZeroTier {
|
||||||
|
|
||||||
DBMirrorSet::DBMirrorSet(DB::ChangeListener *listener) :
|
DBMirrorSet::DBMirrorSet(DB::ChangeListener *listener)
|
||||||
_listener(listener),
|
: _listener(listener)
|
||||||
_running(true)
|
, _running(true)
|
||||||
|
, _syncCheckerThread()
|
||||||
|
, _dbs()
|
||||||
|
, _dbs_l()
|
||||||
{
|
{
|
||||||
_syncCheckerThread = std::thread([this]() {
|
_syncCheckerThread = std::thread([this]() {
|
||||||
for(;;) {
|
for(;;) {
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
@ -553,274 +554,16 @@ void EmbeddedNetworkController::request(
|
|||||||
_queue.post(qe);
|
_queue.post(qe);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET(
|
std::string EmbeddedNetworkController::networkUpdateFromPostData(uint64_t networkID, const std::string &body)
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
if ((!path.empty())&&(path[0] == "network")) {
|
json b = OSUtils::jsonParse(body);
|
||||||
|
|
||||||
if ((path.size() >= 2)&&(path[1].length() == 16)) {
|
|
||||||
const uint64_t nwid = Utils::hexStrToU64(path[1].c_str());
|
|
||||||
json network;
|
|
||||||
if (!_db.get(nwid,network))
|
|
||||||
return 404;
|
|
||||||
|
|
||||||
if (path.size() >= 3) {
|
|
||||||
|
|
||||||
if (path[2] == "member") {
|
|
||||||
|
|
||||||
if (path.size() >= 4) {
|
|
||||||
// Get member
|
|
||||||
|
|
||||||
const uint64_t address = Utils::hexStrToU64(path[3].c_str());
|
|
||||||
json member;
|
|
||||||
if (!_db.get(nwid,network,address,member))
|
|
||||||
return 404;
|
|
||||||
responseBody = OSUtils::jsonDump(member);
|
|
||||||
responseContentType = "application/json";
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// List members and their revisions
|
|
||||||
|
|
||||||
responseBody = "{";
|
|
||||||
std::vector<json> members;
|
|
||||||
if (_db.get(nwid,network,members)) {
|
|
||||||
responseBody.reserve((members.size() + 2) * 32);
|
|
||||||
std::string mid;
|
|
||||||
for(auto member=members.begin();member!=members.end();++member) {
|
|
||||||
mid = OSUtils::jsonString((*member)["id"], "");
|
|
||||||
char tmp[128];
|
|
||||||
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%s\"%s\":%llu",(responseBody.length() > 1) ? "," : "",mid.c_str(),(unsigned long long)OSUtils::jsonInt((*member)["revision"],0));
|
|
||||||
responseBody.append(tmp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
responseBody.push_back('}');
|
|
||||||
responseContentType = "application/json";
|
|
||||||
|
|
||||||
}
|
|
||||||
return 200;
|
|
||||||
|
|
||||||
} // else 404
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Get network
|
|
||||||
|
|
||||||
responseBody = OSUtils::jsonDump(network);
|
|
||||||
responseContentType = "application/json";
|
|
||||||
return 200;
|
|
||||||
|
|
||||||
}
|
|
||||||
} else if (path.size() == 1) {
|
|
||||||
// List networks
|
|
||||||
|
|
||||||
std::set<uint64_t> networkIds;
|
|
||||||
_db.networks(networkIds);
|
|
||||||
char tmp[64];
|
|
||||||
responseBody = "[";
|
|
||||||
responseBody.reserve((networkIds.size() + 1) * 24);
|
|
||||||
for(std::set<uint64_t>::const_iterator i(networkIds.begin());i!=networkIds.end();++i) {
|
|
||||||
if (responseBody.length() > 1)
|
|
||||||
responseBody.push_back(',');
|
|
||||||
OSUtils::ztsnprintf(tmp,sizeof(tmp),"\"%.16llx\"",(unsigned long long)*i);
|
|
||||||
responseBody.append(tmp);
|
|
||||||
}
|
|
||||||
responseBody.push_back(']');
|
|
||||||
responseContentType = "application/json";
|
|
||||||
|
|
||||||
return 200;
|
|
||||||
|
|
||||||
} // else 404
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// Controller status
|
|
||||||
|
|
||||||
char tmp[4096];
|
|
||||||
const bool dbOk = _db.isReady();
|
|
||||||
OSUtils::ztsnprintf(tmp,sizeof(tmp),"{\n\t\"controller\": true,\n\t\"apiVersion\": %d,\n\t\"clock\": %llu,\n\t\"databaseReady\": %s\n}\n",ZT_NETCONF_CONTROLLER_API_VERSION,(unsigned long long)OSUtils::now(),dbOk ? "true" : "false");
|
|
||||||
responseBody = tmp;
|
|
||||||
responseContentType = "application/json";
|
|
||||||
return dbOk ? 200 : 503;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return 404;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int EmbeddedNetworkController::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)
|
|
||||||
{
|
|
||||||
if (path.empty())
|
|
||||||
return 404;
|
|
||||||
|
|
||||||
json b;
|
|
||||||
try {
|
|
||||||
b = OSUtils::jsonParse(body);
|
|
||||||
if (!b.is_object()) {
|
|
||||||
responseBody = "{ \"message\": \"body is not a JSON object\" }";
|
|
||||||
responseContentType = "application/json";
|
|
||||||
return 400;
|
|
||||||
}
|
|
||||||
} catch ( ... ) {
|
|
||||||
responseBody = "{ \"message\": \"body JSON is invalid\" }";
|
|
||||||
responseContentType = "application/json";
|
|
||||||
return 400;
|
|
||||||
}
|
|
||||||
const int64_t now = OSUtils::now();
|
|
||||||
|
|
||||||
if (path[0] == "network") {
|
|
||||||
|
|
||||||
if ((path.size() >= 2)&&(path[1].length() == 16)) {
|
|
||||||
uint64_t nwid = Utils::hexStrToU64(path[1].c_str());
|
|
||||||
char nwids[24];
|
char nwids[24];
|
||||||
OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid);
|
OSUtils::ztsnprintf(nwids, sizeof(nwids), "%.16llx", networkID);
|
||||||
|
|
||||||
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];
|
|
||||||
OSUtils::ztsnprintf(addrs,sizeof(addrs),"%.10llx",(unsigned long long)address);
|
|
||||||
|
|
||||||
json member,network;
|
|
||||||
_db.get(nwid,network,address,member);
|
|
||||||
DB::initMember(member);
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (b.count("activeBridge")) member["activeBridge"] = OSUtils::jsonBool(b["activeBridge"], false);
|
|
||||||
if (b.count("noAutoAssignIps")) member["noAutoAssignIps"] = OSUtils::jsonBool(b["noAutoAssignIps"], false);
|
|
||||||
if (b.count("authenticationExpiryTime")) member["authenticationExpiryTime"] = (uint64_t)OSUtils::jsonInt(b["authenticationExpiryTime"], 0ULL);
|
|
||||||
if (b.count("authenticationURL")) member["authenticationURL"] = OSUtils::jsonString(b["authenticationURL"], "");
|
|
||||||
|
|
||||||
if (b.count("remoteTraceTarget")) {
|
|
||||||
const std::string rtt(OSUtils::jsonString(b["remoteTraceTarget"],""));
|
|
||||||
if (rtt.length() == 10) {
|
|
||||||
member["remoteTraceTarget"] = rtt;
|
|
||||||
} else {
|
|
||||||
member["remoteTraceTarget"] = json();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (b.count("remoteTraceLevel")) member["remoteTraceLevel"] = OSUtils::jsonInt(b["remoteTraceLevel"],0ULL);
|
|
||||||
|
|
||||||
if (b.count("authorized")) {
|
|
||||||
const bool newAuth = OSUtils::jsonBool(b["authorized"],false);
|
|
||||||
if (newAuth != OSUtils::jsonBool(member["authorized"],false)) {
|
|
||||||
member["authorized"] = newAuth;
|
|
||||||
member[((newAuth) ? "lastAuthorizedTime" : "lastDeauthorizedTime")] = now;
|
|
||||||
if (newAuth) {
|
|
||||||
member["lastAuthorizedCredentialType"] = "api";
|
|
||||||
member["lastAuthorizedCredential"] = json();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b.count("ipAssignments")) {
|
|
||||||
json &ipa = b["ipAssignments"];
|
|
||||||
if (ipa.is_array()) {
|
|
||||||
json mipa(json::array());
|
|
||||||
for(unsigned long i=0;i<ipa.size();++i) {
|
|
||||||
std::string ips = ipa[i];
|
|
||||||
InetAddress ip(ips.c_str());
|
|
||||||
if ((ip.ss_family == AF_INET)||(ip.ss_family == AF_INET6)) {
|
|
||||||
char tmpip[64];
|
|
||||||
mipa.push_back(ip.toIpString(tmpip));
|
|
||||||
if (mipa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
member["ipAssignments"] = mipa;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b.count("tags")) {
|
|
||||||
json &tags = b["tags"];
|
|
||||||
if (tags.is_array()) {
|
|
||||||
std::map<uint64_t,uint64_t> mtags;
|
|
||||||
for(unsigned long i=0;i<tags.size();++i) {
|
|
||||||
json &tag = tags[i];
|
|
||||||
if ((tag.is_array())&&(tag.size() == 2))
|
|
||||||
mtags[OSUtils::jsonInt(tag[0],0ULL) & 0xffffffffULL] = OSUtils::jsonInt(tag[1],0ULL) & 0xffffffffULL;
|
|
||||||
}
|
|
||||||
json mtagsa = json::array();
|
|
||||||
for(std::map<uint64_t,uint64_t>::iterator t(mtags.begin());t!=mtags.end();++t) {
|
|
||||||
json ta = json::array();
|
|
||||||
ta.push_back(t->first);
|
|
||||||
ta.push_back(t->second);
|
|
||||||
mtagsa.push_back(ta);
|
|
||||||
if (mtagsa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
member["tags"] = mtagsa;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b.count("capabilities")) {
|
|
||||||
json &capabilities = b["capabilities"];
|
|
||||||
if (capabilities.is_array()) {
|
|
||||||
json mcaps = json::array();
|
|
||||||
for(unsigned long i=0;i<capabilities.size();++i) {
|
|
||||||
mcaps.push_back(OSUtils::jsonInt(capabilities[i],0ULL));
|
|
||||||
if (mcaps.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
std::sort(mcaps.begin(),mcaps.end());
|
|
||||||
mcaps.erase(std::unique(mcaps.begin(),mcaps.end()),mcaps.end());
|
|
||||||
member["capabilities"] = mcaps;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch ( ... ) {
|
|
||||||
responseBody = "{ \"message\": \"exception while processing parameters in JSON body\" }";
|
|
||||||
responseContentType = "application/json";
|
|
||||||
return 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
member["id"] = addrs;
|
|
||||||
member["address"] = addrs; // legacy
|
|
||||||
member["nwid"] = nwids;
|
|
||||||
|
|
||||||
DB::cleanMember(member);
|
|
||||||
_db.save(member,true);
|
|
||||||
responseBody = OSUtils::jsonDump(member);
|
|
||||||
responseContentType = "application/json";
|
|
||||||
|
|
||||||
return 200;
|
|
||||||
} // else 404
|
|
||||||
|
|
||||||
} else {
|
|
||||||
// POST to network ID
|
|
||||||
|
|
||||||
// Magic ID ending with ______ picks a random unused network ID
|
|
||||||
if (path[1].substr(10) == "______") {
|
|
||||||
nwid = 0;
|
|
||||||
uint64_t nwidPrefix = (Utils::hexStrToU64(path[1].substr(0,10).c_str()) << 24) & 0xffffffffff000000ULL;
|
|
||||||
uint64_t nwidPostfix = 0;
|
|
||||||
for(unsigned long k=0;k<100000;++k) { // sanity limit on trials
|
|
||||||
Utils::getSecureRandom(&nwidPostfix,sizeof(nwidPostfix));
|
|
||||||
uint64_t tryNwid = nwidPrefix | (nwidPostfix & 0xffffffULL);
|
|
||||||
if ((tryNwid & 0xffffffULL) == 0ULL) tryNwid |= 1ULL;
|
|
||||||
if (!_db.hasNetwork(tryNwid)) {
|
|
||||||
nwid = tryNwid;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!nwid)
|
|
||||||
return 503;
|
|
||||||
}
|
|
||||||
OSUtils::ztsnprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid);
|
|
||||||
|
|
||||||
json network;
|
json network;
|
||||||
_db.get(nwid,network);
|
_db.get(networkID, network);
|
||||||
DB::initNetwork(network);
|
DB::initNetwork(network);
|
||||||
|
|
||||||
try {
|
|
||||||
if (b.count("name")) network["name"] = OSUtils::jsonString(b["name"],"");
|
if (b.count("name")) network["name"] = OSUtils::jsonString(b["name"],"");
|
||||||
if (b.count("private")) network["private"] = OSUtils::jsonBool(b["private"],true);
|
if (b.count("private")) network["private"] = OSUtils::jsonBool(b["private"],true);
|
||||||
if (b.count("enableBroadcast")) network["enableBroadcast"] = OSUtils::jsonBool(b["enableBroadcast"],false);
|
if (b.count("enableBroadcast")) network["enableBroadcast"] = OSUtils::jsonBool(b["enableBroadcast"],false);
|
||||||
@ -1058,88 +801,281 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch ( ... ) {
|
|
||||||
responseBody = "{ \"message\": \"exception occurred while parsing body variables\" }";
|
|
||||||
responseContentType = "application/json";
|
|
||||||
return 400;
|
|
||||||
}
|
|
||||||
|
|
||||||
network["id"] = nwids;
|
network["id"] = nwids;
|
||||||
network["nwid"] = nwids; // legacy
|
network["nwid"] = nwids;
|
||||||
|
|
||||||
DB::cleanNetwork(network);
|
DB::cleanNetwork(network);
|
||||||
_db.save(network, true);
|
_db.save(network, true);
|
||||||
|
|
||||||
responseBody = OSUtils::jsonDump(network);
|
return network.dump();
|
||||||
responseContentType = "application/json";
|
|
||||||
return 200;
|
|
||||||
} // else 404
|
|
||||||
|
|
||||||
} // else 404
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 404;
|
void EmbeddedNetworkController::configureHTTPControlPlane(
|
||||||
}
|
httplib::Server &s,
|
||||||
|
const std::function<void(const httplib::Request&, httplib::Response&, std::string)> setContent)
|
||||||
unsigned int EmbeddedNetworkController::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)
|
|
||||||
{
|
{
|
||||||
if (path.empty())
|
s.Get("/controller/network", [&](const httplib::Request &req, httplib::Response &res) {
|
||||||
return 404;
|
std::set<uint64_t> networkIds;
|
||||||
|
_db.networks(networkIds);
|
||||||
|
char tmp[64];
|
||||||
|
|
||||||
if (path[0] == "network") {
|
auto out = json::array();
|
||||||
if ((path.size() >= 2)&&(path[1].length() == 16)) {
|
for(std::set<uint64_t>::const_iterator i(networkIds.begin()); i != networkIds.end(); ++i) {
|
||||||
const uint64_t nwid = Utils::hexStrToU64(path[1].c_str());
|
OSUtils::ztsnprintf(tmp, sizeof(tmp), "%.16llx", *i);
|
||||||
if (path.size() >= 3) {
|
out.push_back(tmp);
|
||||||
if ((path.size() == 4)&&(path[2] == "member")&&(path[3].length() == 10)) {
|
}
|
||||||
const uint64_t address = Utils::hexStrToU64(path[3].c_str());
|
|
||||||
|
|
||||||
|
setContent(req, res, out.dump());
|
||||||
|
});
|
||||||
|
|
||||||
|
s.Get("/controller/network/([0-9a-fA-F]{16})", [&](const httplib::Request &req, httplib::Response &res) {
|
||||||
|
auto networkID = req.matches[1];
|
||||||
|
uint64_t nwid = Utils::hexStrToU64(networkID.str().c_str());
|
||||||
|
json network;
|
||||||
|
if (!_db.get(nwid, network)) {
|
||||||
|
res.status = 404;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setContent(req, res, network.dump());
|
||||||
|
});
|
||||||
|
|
||||||
|
auto createNewNetwork = [&](const httplib::Request &req, httplib::Response &res) {
|
||||||
|
fprintf(stderr, "creating new network (new style)\n");
|
||||||
|
uint64_t nwid = 0;
|
||||||
|
uint64_t nwidPrefix = (Utils::hexStrToU64(_signingIdAddressString.c_str()) << 24) & 0xffffffffff000000ULL;
|
||||||
|
uint64_t nwidPostfix = 0;
|
||||||
|
for(unsigned long k=0;k<100000;++k) { // sanity limit on trials
|
||||||
|
Utils::getSecureRandom(&nwidPostfix,sizeof(nwidPostfix));
|
||||||
|
uint64_t tryNwid = nwidPrefix | (nwidPostfix & 0xffffffULL);
|
||||||
|
if ((tryNwid & 0xffffffULL) == 0ULL) tryNwid |= 1ULL;
|
||||||
|
if (!_db.hasNetwork(tryNwid)) {
|
||||||
|
nwid = tryNwid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!nwid) {
|
||||||
|
res.status = 503;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setContent(req, res, networkUpdateFromPostData(nwid, req.body));
|
||||||
|
};
|
||||||
|
s.Put("/controller/network", createNewNetwork);
|
||||||
|
s.Post("/controller/network", createNewNetwork);
|
||||||
|
|
||||||
|
auto createNewNetworkOldAndBusted = [&](const httplib::Request &req, httplib::Response &res) {
|
||||||
|
auto inID = req.matches[1].str();
|
||||||
|
|
||||||
|
if (inID != _signingIdAddressString) {
|
||||||
|
res.status = 400;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint64_t nwid = 0;
|
||||||
|
uint64_t nwidPrefix = (Utils::hexStrToU64(inID.c_str()) << 24) & 0xffffffffff000000ULL;
|
||||||
|
uint64_t nwidPostfix = 0;
|
||||||
|
for(unsigned long k=0;k<100000;++k) { // sanity limit on trials
|
||||||
|
Utils::getSecureRandom(&nwidPostfix,sizeof(nwidPostfix));
|
||||||
|
uint64_t tryNwid = nwidPrefix | (nwidPostfix & 0xffffffULL);
|
||||||
|
if ((tryNwid & 0xffffffULL) == 0ULL) tryNwid |= 1ULL;
|
||||||
|
if (!_db.hasNetwork(tryNwid)) {
|
||||||
|
nwid = tryNwid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!nwid) {
|
||||||
|
res.status = 503;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setContent(req, res, networkUpdateFromPostData(nwid, req.body));
|
||||||
|
};
|
||||||
|
s.Put("/controller/network/([0-9a-fA-F]{10})______", createNewNetworkOldAndBusted);
|
||||||
|
s.Post("/controller/network/([0-9a-fA-F]{10})______", createNewNetworkOldAndBusted);
|
||||||
|
|
||||||
|
s.Delete("/controller/network/([0-9a-fA-F]{16})", [&](const httplib::Request &req, httplib::Response &res) {
|
||||||
|
auto networkID = req.matches[1].str();
|
||||||
|
uint64_t nwid = Utils::hexStrToU64(networkID.c_str());
|
||||||
|
|
||||||
|
json network;
|
||||||
|
if (!_db.get(nwid,network)) {
|
||||||
|
res.status = 404;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_db.eraseNetwork(nwid);
|
||||||
|
setContent(req, res, network.dump());
|
||||||
|
});
|
||||||
|
|
||||||
|
s.Get("/controller/network/([0-9a-fA-F]{16})/member", [&](const httplib::Request &req, httplib::Response &res) {
|
||||||
|
auto networkID = req.matches[1];
|
||||||
|
uint64_t nwid = Utils::hexStrToU64(networkID.str().c_str());
|
||||||
|
json network;
|
||||||
|
if (!_db.get(nwid, network)) {
|
||||||
|
res.status = 404;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
json out = json::array();
|
||||||
|
std::vector<json> memTmp;
|
||||||
|
if (_db.get(nwid, network, memTmp)) {
|
||||||
|
for (auto m = memTmp.begin(); m != memTmp.end(); ++m) {
|
||||||
|
int revision = OSUtils::jsonInt((*m)["revsision"], 0);
|
||||||
|
std::string id = OSUtils::jsonString((*m)["id"], "");
|
||||||
|
if (id.length() == 10) {
|
||||||
|
json tmp = json::object();
|
||||||
|
tmp[id] = revision;
|
||||||
|
out.push_back(tmp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setContent(req, res, out.dump());
|
||||||
|
});
|
||||||
|
|
||||||
|
s.Get("/controller/network/([0-9a-fA-F]{16})/member/([0-9a-fA-F]{10})", [&](const httplib::Request &req, httplib::Response &res) {
|
||||||
|
auto networkID = req.matches[1];
|
||||||
|
auto memberID = req.matches[2];
|
||||||
|
uint64_t nwid = Utils::hexStrToU64(networkID.str().c_str());
|
||||||
|
uint64_t memid = Utils::hexStrToU64(memberID.str().c_str());
|
||||||
|
json network;
|
||||||
|
json member;
|
||||||
|
if (!_db.get(nwid, network, memid, member)) {
|
||||||
|
res.status = 404;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setContent(req, res, member.dump());
|
||||||
|
});
|
||||||
|
|
||||||
|
auto memberPost = [&](const httplib::Request &req, httplib::Response &res) {
|
||||||
|
auto networkID = req.matches[1].str();
|
||||||
|
auto memberID = req.matches[2].str();
|
||||||
|
uint64_t nwid = Utils::hexStrToU64(networkID.c_str());
|
||||||
|
uint64_t memid = Utils::hexStrToU64(memberID.c_str());
|
||||||
|
json network;
|
||||||
|
json member;
|
||||||
|
_db.get(nwid, network, memid, member);
|
||||||
|
DB::initMember(member);
|
||||||
|
|
||||||
|
json b = OSUtils::jsonParse(req.body);
|
||||||
|
|
||||||
|
if (b.count("activeBridge")) member["activeBridge"] = OSUtils::jsonBool(b["activeBridge"], false);
|
||||||
|
if (b.count("noAutoAssignIps")) member["noAutoAssignIps"] = OSUtils::jsonBool(b["noAutoAssignIps"], false);
|
||||||
|
if (b.count("authenticationExpiryTime")) member["authenticationExpiryTime"] = (uint64_t)OSUtils::jsonInt(b["authenticationExpiryTime"], 0ULL);
|
||||||
|
if (b.count("authenticationURL")) member["authenticationURL"] = OSUtils::jsonString(b["authenticationURL"], "");
|
||||||
|
|
||||||
|
if (b.count("remoteTraceTarget")) {
|
||||||
|
const std::string rtt(OSUtils::jsonString(b["remoteTraceTarget"],""));
|
||||||
|
if (rtt.length() == 10) {
|
||||||
|
member["remoteTraceTarget"] = rtt;
|
||||||
|
} else {
|
||||||
|
member["remoteTraceTarget"] = json();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (b.count("remoteTraceLevel")) member["remoteTraceLevel"] = OSUtils::jsonInt(b["remoteTraceLevel"],0ULL);
|
||||||
|
|
||||||
|
if (b.count("authorized")) {
|
||||||
|
const bool newAuth = OSUtils::jsonBool(b["authorized"],false);
|
||||||
|
if (newAuth != OSUtils::jsonBool(member["authorized"],false)) {
|
||||||
|
member["authorized"] = newAuth;
|
||||||
|
member[((newAuth) ? "lastAuthorizedTime" : "lastDeauthorizedTime")] = OSUtils::now();
|
||||||
|
if (newAuth) {
|
||||||
|
member["lastAuthorizedCredentialType"] = "api";
|
||||||
|
member["lastAuthorizedCredential"] = json();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b.count("ipAssignments")) {
|
||||||
|
json &ipa = b["ipAssignments"];
|
||||||
|
if (ipa.is_array()) {
|
||||||
|
json mipa(json::array());
|
||||||
|
for(unsigned long i=0;i<ipa.size();++i) {
|
||||||
|
std::string ips = ipa[i];
|
||||||
|
InetAddress ip(ips.c_str());
|
||||||
|
if ((ip.ss_family == AF_INET)||(ip.ss_family == AF_INET6)) {
|
||||||
|
char tmpip[64];
|
||||||
|
mipa.push_back(ip.toIpString(tmpip));
|
||||||
|
if (mipa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
member["ipAssignments"] = mipa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b.count("tags")) {
|
||||||
|
json &tags = b["tags"];
|
||||||
|
if (tags.is_array()) {
|
||||||
|
std::map<uint64_t,uint64_t> mtags;
|
||||||
|
for(unsigned long i=0;i<tags.size();++i) {
|
||||||
|
json &tag = tags[i];
|
||||||
|
if ((tag.is_array())&&(tag.size() == 2))
|
||||||
|
mtags[OSUtils::jsonInt(tag[0],0ULL) & 0xffffffffULL] = OSUtils::jsonInt(tag[1],0ULL) & 0xffffffffULL;
|
||||||
|
}
|
||||||
|
json mtagsa = json::array();
|
||||||
|
for(std::map<uint64_t,uint64_t>::iterator t(mtags.begin());t!=mtags.end();++t) {
|
||||||
|
json ta = json::array();
|
||||||
|
ta.push_back(t->first);
|
||||||
|
ta.push_back(t->second);
|
||||||
|
mtagsa.push_back(ta);
|
||||||
|
if (mtagsa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
member["tags"] = mtagsa;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (b.count("capabilities")) {
|
||||||
|
json &capabilities = b["capabilities"];
|
||||||
|
if (capabilities.is_array()) {
|
||||||
|
json mcaps = json::array();
|
||||||
|
for(unsigned long i=0;i<capabilities.size();++i) {
|
||||||
|
mcaps.push_back(OSUtils::jsonInt(capabilities[i],0ULL));
|
||||||
|
if (mcaps.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::sort(mcaps.begin(),mcaps.end());
|
||||||
|
mcaps.erase(std::unique(mcaps.begin(),mcaps.end()),mcaps.end());
|
||||||
|
member["capabilities"] = mcaps;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
member["id"] = memberID;
|
||||||
|
member["address"] = memberID;
|
||||||
|
member["nwid"] = networkID;
|
||||||
|
|
||||||
|
DB::cleanMember(member);
|
||||||
|
_db.save(member, true);
|
||||||
|
|
||||||
|
setContent(req, res, member.dump());
|
||||||
|
};
|
||||||
|
s.Put("/controller/network/([0-9a-fA-F]{16})/member/([0-9a-fA-F]{10})", memberPost);
|
||||||
|
s.Post("/controller/network/([0-9a-fA-F]{16})/member/([0-9a-fA-F]{10})", memberPost);
|
||||||
|
|
||||||
|
s.Delete("/controller/network/([0-9a-fA-F]{16})/member/([0-9a-fA-F]{10})", [&](const httplib::Request &req, httplib::Response &res) {
|
||||||
|
auto networkID = req.matches[1].str();
|
||||||
|
auto memberID = req.matches[2].str();
|
||||||
|
|
||||||
|
uint64_t nwid = Utils::hexStrToU64(networkID.c_str());
|
||||||
|
uint64_t address = Utils::hexStrToU64(memberID.c_str());
|
||||||
json network, member;
|
json network, member;
|
||||||
_db.get(nwid,network,address,member);
|
|
||||||
|
if (!_db.get(nwid, network, address, member)) {
|
||||||
|
res.status = 404;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!member.size()) {
|
||||||
|
res.status = 404;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
_db.eraseMember(nwid, address);
|
_db.eraseMember(nwid, address);
|
||||||
|
|
||||||
{
|
setContent(req, res, member.dump());
|
||||||
std::lock_guard<std::mutex> l(_memberStatus_l);
|
});
|
||||||
_memberStatus.erase(_MemberStatusKey(nwid,address));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!member.size())
|
|
||||||
return 404;
|
|
||||||
responseBody = OSUtils::jsonDump(member);
|
|
||||||
responseContentType = "application/json";
|
|
||||||
return 200;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
json network;
|
|
||||||
_db.get(nwid,network);
|
|
||||||
_db.eraseNetwork(nwid);
|
|
||||||
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> l(_memberStatus_l);
|
|
||||||
for(auto i=_memberStatus.begin();i!=_memberStatus.end();) {
|
|
||||||
if (i->first.networkId == nwid)
|
|
||||||
_memberStatus.erase(i++);
|
|
||||||
else ++i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!network.size())
|
|
||||||
return 404;
|
|
||||||
responseBody = OSUtils::jsonDump(network);
|
|
||||||
responseContentType = "application/json";
|
|
||||||
return 200;
|
|
||||||
}
|
|
||||||
} // else 404
|
|
||||||
|
|
||||||
} // else 404
|
|
||||||
|
|
||||||
return 404;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt)
|
void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt)
|
||||||
|
@ -37,6 +37,8 @@
|
|||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
|
|
||||||
|
#include <cpp-httplib/httplib.h>
|
||||||
|
|
||||||
#include "DB.hpp"
|
#include "DB.hpp"
|
||||||
#include "DBMirrorSet.hpp"
|
#include "DBMirrorSet.hpp"
|
||||||
|
|
||||||
@ -66,27 +68,9 @@ public:
|
|||||||
const Identity &identity,
|
const Identity &identity,
|
||||||
const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
|
const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
|
||||||
|
|
||||||
unsigned int handleControlPlaneHttpGET(
|
void configureHTTPControlPlane(
|
||||||
const std::vector<std::string> &path,
|
httplib::Server &s,
|
||||||
const std::map<std::string,std::string> &urlArgs,
|
const std::function<void(const httplib::Request&, httplib::Response&, std::string)>);
|
||||||
const std::map<std::string,std::string> &headers,
|
|
||||||
const std::string &body,
|
|
||||||
std::string &responseBody,
|
|
||||||
std::string &responseContentType);
|
|
||||||
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);
|
|
||||||
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);
|
|
||||||
|
|
||||||
void handleRemoteTrace(const ZT_RemoteTrace &rt);
|
void handleRemoteTrace(const ZT_RemoteTrace &rt);
|
||||||
|
|
||||||
@ -98,6 +82,8 @@ private:
|
|||||||
void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
|
void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
|
||||||
void _startThreads();
|
void _startThreads();
|
||||||
|
|
||||||
|
std::string networkUpdateFromPostData(uint64_t networkID, const std::string &body);
|
||||||
|
|
||||||
struct _RQEntry
|
struct _RQEntry
|
||||||
{
|
{
|
||||||
uint64_t nwid;
|
uint64_t nwid;
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user