mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-05 03:53:44 +02: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
5 changed files with 5595 additions and 3345 deletions
|
@ -15,9 +15,12 @@
|
|||
|
||||
namespace ZeroTier {
|
||||
|
||||
DBMirrorSet::DBMirrorSet(DB::ChangeListener *listener) :
|
||||
_listener(listener),
|
||||
_running(true)
|
||||
DBMirrorSet::DBMirrorSet(DB::ChangeListener *listener)
|
||||
: _listener(listener)
|
||||
, _running(true)
|
||||
, _syncCheckerThread()
|
||||
, _dbs()
|
||||
, _dbs_l()
|
||||
{
|
||||
_syncCheckerThread = std::thread([this]() {
|
||||
for(;;) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <type_traits>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/time.h>
|
||||
|
@ -553,274 +554,16 @@ void EmbeddedNetworkController::request(
|
|||
_queue.post(qe);
|
||||
}
|
||||
|
||||
unsigned int EmbeddedNetworkController::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)
|
||||
std::string EmbeddedNetworkController::networkUpdateFromPostData(uint64_t networkID, const std::string &body)
|
||||
{
|
||||
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];
|
||||
OSUtils::ztsnprintf(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];
|
||||
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);
|
||||
OSUtils::ztsnprintf(nwids, sizeof(nwids), "%.16llx", networkID);
|
||||
|
||||
json network;
|
||||
_db.get(nwid,network);
|
||||
_db.get(networkID, network);
|
||||
DB::initNetwork(network);
|
||||
|
||||
try {
|
||||
if (b.count("name")) network["name"] = OSUtils::jsonString(b["name"],"");
|
||||
if (b.count("private")) network["private"] = OSUtils::jsonBool(b["private"],true);
|
||||
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["nwid"] = nwids; // legacy
|
||||
network["nwid"] = nwids;
|
||||
|
||||
DB::cleanNetwork(network);
|
||||
_db.save(network, true);
|
||||
|
||||
responseBody = OSUtils::jsonDump(network);
|
||||
responseContentType = "application/json";
|
||||
return 200;
|
||||
} // else 404
|
||||
|
||||
} // else 404
|
||||
|
||||
return network.dump();
|
||||
}
|
||||
|
||||
return 404;
|
||||
}
|
||||
|
||||
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)
|
||||
void EmbeddedNetworkController::configureHTTPControlPlane(
|
||||
httplib::Server &s,
|
||||
const std::function<void(const httplib::Request&, httplib::Response&, std::string)> setContent)
|
||||
{
|
||||
if (path.empty())
|
||||
return 404;
|
||||
s.Get("/controller/network", [&](const httplib::Request &req, httplib::Response &res) {
|
||||
std::set<uint64_t> networkIds;
|
||||
_db.networks(networkIds);
|
||||
char tmp[64];
|
||||
|
||||
if (path[0] == "network") {
|
||||
if ((path.size() >= 2)&&(path[1].length() == 16)) {
|
||||
const uint64_t nwid = Utils::hexStrToU64(path[1].c_str());
|
||||
if (path.size() >= 3) {
|
||||
if ((path.size() == 4)&&(path[2] == "member")&&(path[3].length() == 10)) {
|
||||
const uint64_t address = Utils::hexStrToU64(path[3].c_str());
|
||||
auto out = json::array();
|
||||
for(std::set<uint64_t>::const_iterator i(networkIds.begin()); i != networkIds.end(); ++i) {
|
||||
OSUtils::ztsnprintf(tmp, sizeof(tmp), "%.16llx", *i);
|
||||
out.push_back(tmp);
|
||||
}
|
||||
|
||||
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;
|
||||
_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);
|
||||
|
||||
{
|
||||
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;
|
||||
setContent(req, res, member.dump());
|
||||
});
|
||||
}
|
||||
|
||||
void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt)
|
||||
|
|
|
@ -37,6 +37,8 @@
|
|||
|
||||
#include <nlohmann/json.hpp>
|
||||
|
||||
#include <cpp-httplib/httplib.h>
|
||||
|
||||
#include "DB.hpp"
|
||||
#include "DBMirrorSet.hpp"
|
||||
|
||||
|
@ -66,27 +68,9 @@ public:
|
|||
const Identity &identity,
|
||||
const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
|
||||
|
||||
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);
|
||||
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 configureHTTPControlPlane(
|
||||
httplib::Server &s,
|
||||
const std::function<void(const httplib::Request&, httplib::Response&, std::string)>);
|
||||
|
||||
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 _startThreads();
|
||||
|
||||
std::string networkUpdateFromPostData(uint64_t networkID, const std::string &body);
|
||||
|
||||
struct _RQEntry
|
||||
{
|
||||
uint64_t nwid;
|
||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue