mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-04-19 13:36:54 +02:00
kill all the old http endpoint code
This commit is contained in:
parent
412172cdf1
commit
c0eef435ca
3 changed files with 0 additions and 1215 deletions
|
@ -1076,595 +1076,6 @@ void EmbeddedNetworkController::configureHTTPControlPlane(
|
|||
});
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if ((!path.empty())&&(path[0] == "network")) {
|
||||
|
||||
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);
|
||||
|
||||
json network;
|
||||
_db.get(nwid,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);
|
||||
if (b.count("multicastLimit")) network["multicastLimit"] = OSUtils::jsonInt(b["multicastLimit"],32ULL);
|
||||
if (b.count("mtu")) network["mtu"] = std::max(std::min((unsigned int)OSUtils::jsonInt(b["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU);
|
||||
|
||||
if (b.count("remoteTraceTarget")) {
|
||||
const std::string rtt(OSUtils::jsonString(b["remoteTraceTarget"],""));
|
||||
if (rtt.length() == 10) {
|
||||
network["remoteTraceTarget"] = rtt;
|
||||
} else {
|
||||
network["remoteTraceTarget"] = json();
|
||||
}
|
||||
}
|
||||
if (b.count("remoteTraceLevel")) network["remoteTraceLevel"] = OSUtils::jsonInt(b["remoteTraceLevel"],0ULL);
|
||||
|
||||
if (b.count("v4AssignMode")) {
|
||||
json nv4m;
|
||||
json &v4m = b["v4AssignMode"];
|
||||
if (v4m.is_string()) { // backward compatibility
|
||||
nv4m["zt"] = (OSUtils::jsonString(v4m,"") == "zt");
|
||||
} else if (v4m.is_object()) {
|
||||
nv4m["zt"] = OSUtils::jsonBool(v4m["zt"],false);
|
||||
} else nv4m["zt"] = false;
|
||||
network["v4AssignMode"] = nv4m;
|
||||
}
|
||||
|
||||
if (b.count("v6AssignMode")) {
|
||||
json nv6m;
|
||||
json &v6m = b["v6AssignMode"];
|
||||
if (!nv6m.is_object()) nv6m = json::object();
|
||||
if (v6m.is_string()) { // backward compatibility
|
||||
std::vector<std::string> v6ms(OSUtils::split(OSUtils::jsonString(v6m,"").c_str(),",","",""));
|
||||
std::sort(v6ms.begin(),v6ms.end());
|
||||
v6ms.erase(std::unique(v6ms.begin(),v6ms.end()),v6ms.end());
|
||||
nv6m["rfc4193"] = false;
|
||||
nv6m["zt"] = false;
|
||||
nv6m["6plane"] = false;
|
||||
for(std::vector<std::string>::iterator i(v6ms.begin());i!=v6ms.end();++i) {
|
||||
if (*i == "rfc4193")
|
||||
nv6m["rfc4193"] = true;
|
||||
else if (*i == "zt")
|
||||
nv6m["zt"] = true;
|
||||
else if (*i == "6plane")
|
||||
nv6m["6plane"] = true;
|
||||
}
|
||||
} else if (v6m.is_object()) {
|
||||
if (v6m.count("rfc4193")) nv6m["rfc4193"] = OSUtils::jsonBool(v6m["rfc4193"],false);
|
||||
if (v6m.count("zt")) nv6m["zt"] = OSUtils::jsonBool(v6m["zt"],false);
|
||||
if (v6m.count("6plane")) nv6m["6plane"] = OSUtils::jsonBool(v6m["6plane"],false);
|
||||
} else {
|
||||
nv6m["rfc4193"] = false;
|
||||
nv6m["zt"] = false;
|
||||
nv6m["6plane"] = false;
|
||||
}
|
||||
network["v6AssignMode"] = nv6m;
|
||||
}
|
||||
|
||||
if (b.count("routes")) {
|
||||
json &rts = b["routes"];
|
||||
if (rts.is_array()) {
|
||||
json nrts = json::array();
|
||||
for(unsigned long i=0;i<rts.size();++i) {
|
||||
json &rt = rts[i];
|
||||
if (rt.is_object()) {
|
||||
json &target = rt["target"];
|
||||
json &via = rt["via"];
|
||||
if (target.is_string()) {
|
||||
InetAddress t(target.get<std::string>().c_str());
|
||||
InetAddress v;
|
||||
if (via.is_string()) v.fromString(via.get<std::string>().c_str());
|
||||
if ( ((t.ss_family == AF_INET)||(t.ss_family == AF_INET6)) && (t.netmaskBitsValid()) ) {
|
||||
json tmp;
|
||||
char tmp2[64];
|
||||
tmp["target"] = t.toString(tmp2);
|
||||
if (v.ss_family == t.ss_family)
|
||||
tmp["via"] = v.toIpString(tmp2);
|
||||
else tmp["via"] = json();
|
||||
nrts.push_back(tmp);
|
||||
if (nrts.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
network["routes"] = nrts;
|
||||
}
|
||||
}
|
||||
|
||||
if (b.count("ipAssignmentPools")) {
|
||||
json &ipp = b["ipAssignmentPools"];
|
||||
if (ipp.is_array()) {
|
||||
json nipp = json::array();
|
||||
for(unsigned long i=0;i<ipp.size();++i) {
|
||||
json &ip = ipp[i];
|
||||
if ((ip.is_object())&&(ip.count("ipRangeStart"))&&(ip.count("ipRangeEnd"))) {
|
||||
InetAddress f(OSUtils::jsonString(ip["ipRangeStart"],"").c_str());
|
||||
InetAddress t(OSUtils::jsonString(ip["ipRangeEnd"],"").c_str());
|
||||
if ( ((f.ss_family == AF_INET)||(f.ss_family == AF_INET6)) && (f.ss_family == t.ss_family) ) {
|
||||
json tmp = json::object();
|
||||
char tmp2[64];
|
||||
tmp["ipRangeStart"] = f.toIpString(tmp2);
|
||||
tmp["ipRangeEnd"] = t.toIpString(tmp2);
|
||||
nipp.push_back(tmp);
|
||||
if (nipp.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
network["ipAssignmentPools"] = nipp;
|
||||
}
|
||||
}
|
||||
|
||||
if (b.count("rules")) {
|
||||
json &rules = b["rules"];
|
||||
if (rules.is_array()) {
|
||||
json nrules = json::array();
|
||||
for(unsigned long i=0;i<rules.size();++i) {
|
||||
json &rule = rules[i];
|
||||
if (rule.is_object()) {
|
||||
ZT_VirtualNetworkRule ztr;
|
||||
if (_parseRule(rule,ztr)) {
|
||||
nrules.push_back(_renderRule(ztr));
|
||||
if (nrules.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
network["rules"] = nrules;
|
||||
}
|
||||
}
|
||||
|
||||
if (b.count("authTokens")) {
|
||||
json &authTokens = b["authTokens"];
|
||||
if (authTokens.is_object()) {
|
||||
json nat;
|
||||
for(json::iterator t(authTokens.begin());t!=authTokens.end();++t) {
|
||||
if ((t.value().is_number())&&(t.value() >= 0))
|
||||
nat[t.key()] = t.value();
|
||||
}
|
||||
network["authTokens"] = nat;
|
||||
} else {
|
||||
network["authTokens"] = {{}};
|
||||
}
|
||||
}
|
||||
|
||||
if (b.count("capabilities")) {
|
||||
json &capabilities = b["capabilities"];
|
||||
if (capabilities.is_array()) {
|
||||
std::map< uint64_t,json > ncaps;
|
||||
for(unsigned long i=0;i<capabilities.size();++i) {
|
||||
json &cap = capabilities[i];
|
||||
if (cap.is_object()) {
|
||||
json ncap = json::object();
|
||||
const uint64_t capId = OSUtils::jsonInt(cap["id"],0ULL);
|
||||
ncap["id"] = capId;
|
||||
ncap["default"] = OSUtils::jsonBool(cap["default"],false);
|
||||
|
||||
json &rules = cap["rules"];
|
||||
json nrules = json::array();
|
||||
if (rules.is_array()) {
|
||||
for(unsigned long i=0;i<rules.size();++i) {
|
||||
json &rule = rules[i];
|
||||
if (rule.is_object()) {
|
||||
ZT_VirtualNetworkRule ztr;
|
||||
if (_parseRule(rule,ztr)) {
|
||||
nrules.push_back(_renderRule(ztr));
|
||||
if (nrules.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ncap["rules"] = nrules;
|
||||
|
||||
ncaps[capId] = ncap;
|
||||
}
|
||||
}
|
||||
|
||||
json ncapsa = json::array();
|
||||
for(std::map< uint64_t,json >::iterator c(ncaps.begin());c!=ncaps.end();++c) {
|
||||
ncapsa.push_back(c->second);
|
||||
if (ncapsa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
|
||||
break;
|
||||
}
|
||||
network["capabilities"] = ncapsa;
|
||||
}
|
||||
}
|
||||
|
||||
if (b.count("tags")) {
|
||||
json &tags = b["tags"];
|
||||
if (tags.is_array()) {
|
||||
std::map< uint64_t,json > ntags;
|
||||
for(unsigned long i=0;i<tags.size();++i) {
|
||||
json &tag = tags[i];
|
||||
if (tag.is_object()) {
|
||||
json ntag = json::object();
|
||||
const uint64_t tagId = OSUtils::jsonInt(tag["id"],0ULL);
|
||||
ntag["id"] = tagId;
|
||||
json &dfl = tag["default"];
|
||||
if (dfl.is_null())
|
||||
ntag["default"] = dfl;
|
||||
else ntag["default"] = OSUtils::jsonInt(dfl,0ULL);
|
||||
ntags[tagId] = ntag;
|
||||
}
|
||||
}
|
||||
|
||||
json ntagsa = json::array();
|
||||
for(std::map< uint64_t,json >::iterator t(ntags.begin());t!=ntags.end();++t) {
|
||||
ntagsa.push_back(t->second);
|
||||
if (ntagsa.size() >= ZT_CONTROLLER_MAX_ARRAY_SIZE)
|
||||
break;
|
||||
}
|
||||
network["tags"] = ntagsa;
|
||||
}
|
||||
}
|
||||
|
||||
if (b.count("dns")) {
|
||||
json &dns = b["dns"];
|
||||
if (dns.is_object()) {
|
||||
json nd;
|
||||
|
||||
nd["domain"] = dns["domain"];
|
||||
|
||||
json &srv = dns["servers"];
|
||||
if (srv.is_array()) {
|
||||
json ns = json::array();
|
||||
for(unsigned int i=0;i<srv.size();++i) {
|
||||
ns.push_back(srv[i]);
|
||||
}
|
||||
nd["servers"] = ns;
|
||||
}
|
||||
|
||||
network["dns"] = nd;
|
||||
}
|
||||
}
|
||||
|
||||
} catch ( ... ) {
|
||||
responseBody = "{ \"message\": \"exception occurred while parsing body variables\" }";
|
||||
responseContentType = "application/json";
|
||||
return 400;
|
||||
}
|
||||
|
||||
network["id"] = nwids;
|
||||
network["nwid"] = nwids; // legacy
|
||||
|
||||
DB::cleanNetwork(network);
|
||||
_db.save(network,true);
|
||||
|
||||
responseBody = OSUtils::jsonDump(network);
|
||||
responseContentType = "application/json";
|
||||
return 200;
|
||||
} // else 404
|
||||
|
||||
} // else 404
|
||||
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (path.empty())
|
||||
return 404;
|
||||
|
||||
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());
|
||||
|
||||
json network,member;
|
||||
_db.get(nwid,network,address,member);
|
||||
_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;
|
||||
}
|
||||
|
||||
void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt)
|
||||
{
|
||||
static volatile unsigned long idCounter = 0;
|
||||
|
|
|
@ -72,28 +72,6 @@ public:
|
|||
httplib::Server &s,
|
||||
const std::function<void(const httplib::Request&, httplib::Response&, std::string)>);
|
||||
|
||||
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 handleRemoteTrace(const ZT_RemoteTrace &rt);
|
||||
|
||||
virtual void onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network);
|
||||
|
|
|
@ -2007,559 +2007,6 @@ public:
|
|||
});
|
||||
|
||||
}
|
||||
// =========================================================================
|
||||
// Internal implementation methods for control plane, route setup, etc.
|
||||
// =========================================================================
|
||||
|
||||
inline unsigned int handleControlPlaneHttpRequest(
|
||||
const InetAddress &fromAddress,
|
||||
unsigned int httpMethod,
|
||||
const std::string &path,
|
||||
const std::map<std::string,std::string> &headers,
|
||||
const std::string &body,
|
||||
std::string &responseBody,
|
||||
std::string &responseContentType)
|
||||
{
|
||||
char tmp[256];
|
||||
unsigned int scode = 404;
|
||||
json res;
|
||||
std::vector<std::string> ps(OSUtils::split(path.c_str(),"/","",""));
|
||||
std::map<std::string,std::string> urlArgs;
|
||||
|
||||
/* Note: this is kind of restricted in what it'll take. It does not support
|
||||
* URL encoding, and /'s in URL args will screw it up. But the only URL args
|
||||
* it really uses in ?jsonp=functionName, and otherwise it just takes simple
|
||||
* paths to simply-named resources. */
|
||||
if (!ps.empty()) {
|
||||
std::size_t qpos = ps[ps.size() - 1].find('?');
|
||||
if (qpos != std::string::npos) {
|
||||
std::string args(ps[ps.size() - 1].substr(qpos + 1));
|
||||
ps[ps.size() - 1] = ps[ps.size() - 1].substr(0,qpos);
|
||||
std::vector<std::string> asplit(OSUtils::split(args.c_str(),"&","",""));
|
||||
for(std::vector<std::string>::iterator a(asplit.begin());a!=asplit.end();++a) {
|
||||
std::size_t eqpos = a->find('=');
|
||||
if (eqpos == std::string::npos)
|
||||
urlArgs[*a] = "";
|
||||
else urlArgs[a->substr(0,eqpos)] = a->substr(eqpos + 1);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return 404;
|
||||
}
|
||||
|
||||
bool isAuth = false;
|
||||
{
|
||||
std::map<std::string,std::string>::const_iterator ah(headers.find("x-zt1-auth"));
|
||||
if ((ah != headers.end())&&(_authToken == ah->second)) {
|
||||
isAuth = true;
|
||||
} else {
|
||||
ah = urlArgs.find("auth");
|
||||
if ((ah != urlArgs.end())&&(_authToken == ah->second))
|
||||
isAuth = true;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __SYNOLOGY__
|
||||
// Authenticate via Synology's built-in cgi script
|
||||
if (!isAuth) {
|
||||
int synotoken_pos = path.find("SynoToken");
|
||||
int argpos = path.find('?');
|
||||
if(synotoken_pos != std::string::npos && argpos != std::string::npos) {
|
||||
std::string cookie = path.substr(argpos+1, synotoken_pos-(argpos+1));
|
||||
std::string synotoken = path.substr(synotoken_pos);
|
||||
std::string cookie_val = cookie.substr(cookie.find('=')+1);
|
||||
std::string synotoken_val = synotoken.substr(synotoken.find('=')+1);
|
||||
// Set necessary env for auth script
|
||||
std::map<std::string,std::string>::const_iterator ah2(headers.find("x-forwarded-for"));
|
||||
setenv("HTTP_COOKIE", cookie_val.c_str(), true);
|
||||
setenv("HTTP_X_SYNO_TOKEN", synotoken_val.c_str(), true);
|
||||
setenv("REMOTE_ADDR", ah2->second.c_str(),true);
|
||||
char user[256], buf[1024];
|
||||
FILE *fp = NULL;
|
||||
bzero(user, 256);
|
||||
fp = popen("/usr/syno/synoman/webman/modules/authenticate.cgi", "r");
|
||||
if(!fp)
|
||||
isAuth = false;
|
||||
else {
|
||||
bzero(buf, sizeof(buf));
|
||||
fread(buf, 1024, 1, fp);
|
||||
if(strlen(buf) > 0) {
|
||||
snprintf(user, 256, "%s", buf);
|
||||
isAuth = true;
|
||||
}
|
||||
}
|
||||
pclose(fp);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (httpMethod == HTTP_GET) {
|
||||
if (isAuth) {
|
||||
if (ps[0] == "bond") {
|
||||
if (_node->bondController()->inUse()) {
|
||||
if (ps.size() == 3) {
|
||||
if (ps[2].length() == 10) {
|
||||
// check if hex string
|
||||
|
||||
ZT_PeerList *pl = _node->peers();
|
||||
if (pl) {
|
||||
uint64_t wantp = Utils::hexStrToU64(ps[2].c_str());
|
||||
for(unsigned long i=0;i<pl->peerCount;++i) {
|
||||
if (pl->peers[i].address == wantp) {
|
||||
if (ps[1] == "show") {
|
||||
SharedPtr<Bond> bond = _node->bondController()->getBondByPeerId(wantp);
|
||||
if (bond) {
|
||||
_peerToJson(res,&(pl->peers[i]),bond,(_tcpFallbackTunnel != (TcpConnection *)0));
|
||||
scode = 200;
|
||||
} else {
|
||||
scode = 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_node->freeQueryResult((void *)pl);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
scode = 400; /* bond controller is not enabled */
|
||||
}
|
||||
} else if (ps[0] == "config") {
|
||||
Mutex::Lock lc(_localConfig_m);
|
||||
res = _localConfig;
|
||||
scode = 200;
|
||||
} else if (ps[0] == "status") {
|
||||
ZT_NodeStatus status;
|
||||
_node->status(&status);
|
||||
|
||||
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.10llx",status.address);
|
||||
res["address"] = tmp;
|
||||
res["publicIdentity"] = status.publicIdentity;
|
||||
res["online"] = (bool)(status.online != 0);
|
||||
res["tcpFallbackActive"] = (_tcpFallbackTunnel != (TcpConnection *)0);
|
||||
res["versionMajor"] = ZEROTIER_ONE_VERSION_MAJOR;
|
||||
res["versionMinor"] = ZEROTIER_ONE_VERSION_MINOR;
|
||||
res["versionRev"] = ZEROTIER_ONE_VERSION_REVISION;
|
||||
res["versionBuild"] = ZEROTIER_ONE_VERSION_BUILD;
|
||||
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%d.%d.%d",ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION);
|
||||
res["version"] = tmp;
|
||||
res["clock"] = OSUtils::now();
|
||||
|
||||
{
|
||||
Mutex::Lock _l(_localConfig_m);
|
||||
res["config"] = _localConfig;
|
||||
}
|
||||
json &settings = res["config"]["settings"];
|
||||
settings["allowTcpFallbackRelay"] = OSUtils::jsonBool(settings["allowTcpFallbackRelay"],_allowTcpFallbackRelay);
|
||||
settings["forceTcpRelay"] = OSUtils::jsonBool(settings["forceTcpRelay"],_forceTcpRelay);
|
||||
settings["primaryPort"] = OSUtils::jsonInt(settings["primaryPort"],(uint64_t)_primaryPort) & 0xffff;
|
||||
settings["secondaryPort"] = OSUtils::jsonInt(settings["secondaryPort"],(uint64_t)_secondaryPort) & 0xffff;
|
||||
settings["tertiaryPort"] = OSUtils::jsonInt(settings["tertiaryPort"],(uint64_t)_tertiaryPort) & 0xffff;
|
||||
// Enumerate all local address/port pairs that this node is listening on
|
||||
std::vector<InetAddress> boundAddrs(_binder.allBoundLocalInterfaceAddresses());
|
||||
auto boundAddrArray = json::array();
|
||||
for (int i = 0; i < boundAddrs.size(); i++) {
|
||||
char ipBuf[64] = { 0 };
|
||||
boundAddrs[i].toString(ipBuf);
|
||||
boundAddrArray.push_back(ipBuf);
|
||||
}
|
||||
settings["listeningOn"] = boundAddrArray;
|
||||
// Enumerate all external address/port pairs that are reported for this node
|
||||
std::vector<InetAddress> surfaceAddrs = _node->SurfaceAddresses();
|
||||
auto surfaceAddrArray = json::array();
|
||||
for (int i = 0; i < surfaceAddrs.size(); i++) {
|
||||
char ipBuf[64] = { 0 };
|
||||
surfaceAddrs[i].toString(ipBuf);
|
||||
surfaceAddrArray.push_back(ipBuf);
|
||||
}
|
||||
settings["surfaceAddresses"] = surfaceAddrArray;
|
||||
|
||||
#ifdef ZT_USE_MINIUPNPC
|
||||
settings["portMappingEnabled"] = OSUtils::jsonBool(settings["portMappingEnabled"],true);
|
||||
#else
|
||||
settings["portMappingEnabled"] = false; // not supported in build
|
||||
#endif
|
||||
#ifndef ZT_SDK
|
||||
settings["softwareUpdate"] = OSUtils::jsonString(settings["softwareUpdate"],ZT_SOFTWARE_UPDATE_DEFAULT);
|
||||
settings["softwareUpdateChannel"] = OSUtils::jsonString(settings["softwareUpdateChannel"],ZT_SOFTWARE_UPDATE_DEFAULT_CHANNEL);
|
||||
#endif
|
||||
const World planet(_node->planet());
|
||||
res["planetWorldId"] = planet.id();
|
||||
res["planetWorldTimestamp"] = planet.timestamp();
|
||||
|
||||
scode = 200;
|
||||
} else if (ps[0] == "moon") {
|
||||
std::vector<World> moons(_node->moons());
|
||||
if (ps.size() == 1) {
|
||||
// Return [array] of all moons
|
||||
|
||||
res = json::array();
|
||||
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) {
|
||||
json mj;
|
||||
_moonToJson(mj,*m);
|
||||
res.push_back(mj);
|
||||
}
|
||||
|
||||
scode = 200;
|
||||
} else {
|
||||
// Return a single moon by ID
|
||||
|
||||
const uint64_t id = Utils::hexStrToU64(ps[1].c_str());
|
||||
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) {
|
||||
if (m->id() == id) {
|
||||
_moonToJson(res,*m);
|
||||
scode = 200;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
} else if (ps[0] == "network") {
|
||||
Mutex::Lock _l(_nets_m);
|
||||
if (ps.size() == 1) {
|
||||
// Return [array] of all networks
|
||||
|
||||
res = nlohmann::json::array();
|
||||
|
||||
for (auto it = _nets.begin(); it != _nets.end(); ++it) {
|
||||
NetworkState &ns = it->second;
|
||||
nlohmann::json nj;
|
||||
_networkToJson(nj, ns);
|
||||
res.push_back(nj);
|
||||
}
|
||||
|
||||
scode = 200;
|
||||
} else if (ps.size() == 2) {
|
||||
// Return a single network by ID or 404 if not found
|
||||
|
||||
const uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str());
|
||||
if (_nets.find(wantnw) != _nets.end()) {
|
||||
res = json::object();
|
||||
NetworkState& ns = _nets[wantnw];
|
||||
_networkToJson(res, ns);
|
||||
scode = 200;
|
||||
}
|
||||
} else {
|
||||
scode = 404;
|
||||
}
|
||||
} else if (ps[0] == "peer") {
|
||||
ZT_PeerList *pl = _node->peers();
|
||||
if (pl) {
|
||||
if (ps.size() == 1) {
|
||||
// Return [array] of all peers
|
||||
|
||||
res = nlohmann::json::array();
|
||||
for(unsigned long i=0;i<pl->peerCount;++i) {
|
||||
nlohmann::json pj;
|
||||
SharedPtr<Bond> bond = SharedPtr<Bond>();
|
||||
if (pl->peers[i].isBonded) {
|
||||
const uint64_t id = pl->peers[i].address;
|
||||
bond = _node->bondController()->getBondByPeerId(id);
|
||||
}
|
||||
_peerToJson(pj,&(pl->peers[i]),bond,(_tcpFallbackTunnel != (TcpConnection *)0));
|
||||
res.push_back(pj);
|
||||
}
|
||||
|
||||
scode = 200;
|
||||
} else if (ps.size() == 2) {
|
||||
// Return a single peer by ID or 404 if not found
|
||||
|
||||
uint64_t wantp = Utils::hexStrToU64(ps[1].c_str());
|
||||
for(unsigned long i=0;i<pl->peerCount;++i) {
|
||||
if (pl->peers[i].address == wantp) {
|
||||
SharedPtr<Bond> bond = SharedPtr<Bond>();
|
||||
if (pl->peers[i].isBonded) {
|
||||
bond = _node->bondController()->getBondByPeerId(wantp);
|
||||
}
|
||||
_peerToJson(res,&(pl->peers[i]),bond,(_tcpFallbackTunnel != (TcpConnection *)0));
|
||||
scode = 200;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} else scode = 404;
|
||||
_node->freeQueryResult((void *)pl);
|
||||
} else scode = 500;\
|
||||
} else if (ps[0] == "metrics") {
|
||||
std::string statspath = _homePath + ZT_PATH_SEPARATOR + "metrics.prom";
|
||||
if (!OSUtils::readFile(statspath.c_str(), responseBody)) {
|
||||
scode = 500;
|
||||
} else {
|
||||
scode = 200;
|
||||
responseContentType = "text/plain";
|
||||
}
|
||||
} else {
|
||||
if (_controller) {
|
||||
scode = _controller->handleControlPlaneHttpGET(std::vector<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
|
||||
} else scode = 404;
|
||||
}
|
||||
#if ZT_SSO_ENABLED
|
||||
} else if (ps[0] == "sso") {
|
||||
std::string htmlTemplatePath = _homePath + ZT_PATH_SEPARATOR + "sso-auth.template.html";
|
||||
std::string htmlTemplate;
|
||||
if (!OSUtils::readFile(htmlTemplatePath.c_str(), htmlTemplate)) {
|
||||
htmlTemplate = ssoResponseTemplate;
|
||||
}
|
||||
|
||||
responseContentType = "text/html";
|
||||
json outData;
|
||||
|
||||
char *error = zeroidc::zeroidc_get_url_param_value("error", path.c_str());
|
||||
if (error != nullptr) {
|
||||
char *desc = zeroidc::zeroidc_get_url_param_value("error_description", path.c_str());
|
||||
scode = 500;
|
||||
|
||||
json data;
|
||||
outData["isError"] = true;
|
||||
outData["messageText"] = (std::string("ERROR ") + error + std::string(": ") + desc);
|
||||
responseBody = inja::render(htmlTemplate, outData);
|
||||
|
||||
zeroidc::free_cstr(desc);
|
||||
zeroidc::free_cstr(error);
|
||||
|
||||
return scode;
|
||||
}
|
||||
|
||||
// SSO redirect handling
|
||||
char* state = zeroidc::zeroidc_get_url_param_value("state", path.c_str());
|
||||
char* nwid = zeroidc::zeroidc_network_id_from_state(state);
|
||||
|
||||
outData["networkId"] = std::string(nwid);
|
||||
|
||||
const uint64_t id = Utils::hexStrToU64(nwid);
|
||||
|
||||
zeroidc::free_cstr(nwid);
|
||||
zeroidc::free_cstr(state);
|
||||
|
||||
Mutex::Lock l(_nets_m);
|
||||
if (_nets.find(id) != _nets.end()) {
|
||||
NetworkState& ns = _nets[id];
|
||||
char* code = zeroidc::zeroidc_get_url_param_value("code", path.c_str());
|
||||
char *ret = ns.doTokenExchange(code);
|
||||
json ssoResult = json::parse(ret);
|
||||
if (ssoResult.is_object()) {
|
||||
if (ssoResult.contains("errorMessage")) {
|
||||
outData["isError"] = true;
|
||||
outData["messageText"] = ssoResult["errorMessage"];
|
||||
responseBody = inja::render(htmlTemplate, outData);
|
||||
scode = 500;
|
||||
} else {
|
||||
scode = 200;
|
||||
outData["isError"] = false;
|
||||
outData["messageText"] = "Authentication Successful. You may now access the network.";
|
||||
responseBody = inja::render(htmlTemplate, outData);
|
||||
}
|
||||
} else {
|
||||
// not an object? We got a problem
|
||||
outData["isError"] = true;
|
||||
outData["messageText"] = "ERROR: Unkown SSO response. Please contact your administrator.";
|
||||
responseBody = inja::render(htmlTemplate, outData);
|
||||
scode= 500;
|
||||
}
|
||||
|
||||
zeroidc::free_cstr(code);
|
||||
zeroidc::free_cstr(ret);
|
||||
|
||||
return scode;
|
||||
} else {
|
||||
scode = 404;
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
scode = 401; // isAuth == false && !sso
|
||||
}
|
||||
} else if ((httpMethod == HTTP_POST)||(httpMethod == HTTP_PUT)) {
|
||||
if (isAuth) {
|
||||
if (ps[0] == "bond") {
|
||||
if (_node->bondController()->inUse()) {
|
||||
if (ps.size() == 3) {
|
||||
if (ps[2].length() == 10) {
|
||||
// check if hex string
|
||||
const uint64_t id = Utils::hexStrToU64(ps[2].c_str());
|
||||
if (ps[1] == "rotate") {
|
||||
exit(0);
|
||||
SharedPtr<Bond> bond = _node->bondController()->getBondByPeerId(id);
|
||||
if (bond) {
|
||||
scode = bond->abForciblyRotateLink() ? 200 : 400;
|
||||
} else {
|
||||
fprintf(stderr, "unable to find bond to peer %llx\n", (unsigned long long)id);
|
||||
scode = 400;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
scode = 400; /* bond controller is not enabled */
|
||||
}
|
||||
} else if (ps[0] == "config") {
|
||||
// Right now we only support writing the things the UI supports changing.
|
||||
if (ps.size() == 2) {
|
||||
if (ps[1] == "settings") {
|
||||
try {
|
||||
json j(OSUtils::jsonParse(body));
|
||||
if (j.is_object()) {
|
||||
Mutex::Lock lcl(_localConfig_m);
|
||||
json lc(_localConfig);
|
||||
for(json::const_iterator s(j.begin());s!=j.end();++s) {
|
||||
lc["settings"][s.key()] = s.value();
|
||||
}
|
||||
std::string lcStr = OSUtils::jsonDump(lc, 4);
|
||||
if (OSUtils::writeFile((_homePath + ZT_PATH_SEPARATOR_S "local.conf").c_str(), lcStr)) {
|
||||
_localConfig = lc;
|
||||
}
|
||||
} else {
|
||||
scode = 400;
|
||||
}
|
||||
} catch ( ... ) {
|
||||
scode = 400;
|
||||
}
|
||||
} else {
|
||||
scode = 404;
|
||||
}
|
||||
} else {
|
||||
scode = 404;
|
||||
}
|
||||
} else if (ps[0] == "moon") {
|
||||
if (ps.size() == 2) {
|
||||
|
||||
uint64_t seed = 0;
|
||||
try {
|
||||
json j(OSUtils::jsonParse(body));
|
||||
if (j.is_object()) {
|
||||
seed = Utils::hexStrToU64(OSUtils::jsonString(j["seed"],"0").c_str());
|
||||
}
|
||||
} catch ( ... ) {
|
||||
// discard invalid JSON
|
||||
}
|
||||
|
||||
std::vector<World> moons(_node->moons());
|
||||
const uint64_t id = Utils::hexStrToU64(ps[1].c_str());
|
||||
for(std::vector<World>::const_iterator m(moons.begin());m!=moons.end();++m) {
|
||||
if (m->id() == id) {
|
||||
_moonToJson(res,*m);
|
||||
scode = 200;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((scode != 200)&&(seed != 0)) {
|
||||
char tmp[64];
|
||||
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.16llx",id);
|
||||
res["id"] = tmp;
|
||||
res["roots"] = json::array();
|
||||
res["timestamp"] = 0;
|
||||
res["signature"] = json();
|
||||
res["updatesMustBeSignedBy"] = json();
|
||||
res["waiting"] = true;
|
||||
_node->orbit((void *)0,id,seed);
|
||||
scode = 200;
|
||||
}
|
||||
|
||||
} else scode = 404;
|
||||
} else if (ps[0] == "network") {
|
||||
if (ps.size() == 2) {
|
||||
|
||||
uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str());
|
||||
_node->join(wantnw,(void *)0,(void *)0); // does nothing if we are a member
|
||||
Mutex::Lock l(_nets_m);
|
||||
if (!_nets.empty()) {
|
||||
if (_nets.find(wantnw) != _nets.end()) {
|
||||
NetworkState& ns = _nets[wantnw];
|
||||
try {
|
||||
json j(OSUtils::jsonParse(body));
|
||||
|
||||
json &allowManaged = j["allowManaged"];
|
||||
if (allowManaged.is_boolean()) {
|
||||
ns.setAllowManaged((bool)allowManaged);
|
||||
}
|
||||
json& allowGlobal = j["allowGlobal"];
|
||||
if (allowGlobal.is_boolean()) {
|
||||
ns.setAllowGlobal((bool)allowGlobal);
|
||||
}
|
||||
json& allowDefault = j["allowDefault"];
|
||||
if (allowDefault.is_boolean()) {
|
||||
ns.setAllowDefault((bool)allowDefault);
|
||||
}
|
||||
json& allowDNS = j["allowDNS"];
|
||||
if (allowDNS.is_boolean()) {
|
||||
ns.setAllowDNS((bool)allowDNS);
|
||||
}
|
||||
} catch (...) {
|
||||
// discard invalid JSON
|
||||
}
|
||||
setNetworkSettings(wantnw, ns.settings());
|
||||
if (ns.tap()) {
|
||||
syncManagedStuff(ns,true,true,true);
|
||||
}
|
||||
|
||||
_networkToJson(res, ns);
|
||||
|
||||
scode = 200;
|
||||
}
|
||||
} else scode = 500;
|
||||
|
||||
} else scode = 404;
|
||||
} else {
|
||||
if (_controller)
|
||||
scode = _controller->handleControlPlaneHttpPOST(std::vector<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
|
||||
else scode = 404;
|
||||
}
|
||||
} else {
|
||||
scode = 401; // isAuth == false
|
||||
}
|
||||
} else if (httpMethod == HTTP_DELETE) {
|
||||
if (isAuth) {
|
||||
|
||||
if (ps[0] == "moon") {
|
||||
if (ps.size() == 2) {
|
||||
_node->deorbit((void *)0,Utils::hexStrToU64(ps[1].c_str()));
|
||||
res["result"] = true;
|
||||
scode = 200;
|
||||
} // else 404
|
||||
} else if (ps[0] == "network") {
|
||||
ZT_VirtualNetworkList *nws = _node->networks();
|
||||
if (nws) {
|
||||
if (ps.size() == 2) {
|
||||
uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str());
|
||||
for(unsigned long i=0;i<nws->networkCount;++i) {
|
||||
if (nws->networks[i].nwid == wantnw) {
|
||||
_node->leave(wantnw,(void **)0,(void *)0);
|
||||
res["result"] = true;
|
||||
scode = 200;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // else 404
|
||||
_node->freeQueryResult((void *)nws);
|
||||
} else scode = 500;
|
||||
} else {
|
||||
if (_controller)
|
||||
scode = _controller->handleControlPlaneHttpDELETE(std::vector<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
|
||||
else scode = 404;
|
||||
}
|
||||
} else scode = 401; // isAuth = false
|
||||
} else {
|
||||
scode = 400;
|
||||
}
|
||||
|
||||
if (responseBody.length() == 0) {
|
||||
if ((res.is_object())||(res.is_array()))
|
||||
responseBody = OSUtils::jsonDump(res);
|
||||
else responseBody = "{}";
|
||||
responseContentType = "application/json";
|
||||
}
|
||||
|
||||
// Wrap result in jsonp function call if the user included a jsonp= url argument.
|
||||
// Also double-check isAuth since forbidding this without auth feels safer.
|
||||
std::map<std::string,std::string>::const_iterator jsonp(urlArgs.find("jsonp"));
|
||||
if ((isAuth)&&(jsonp != urlArgs.end())&&(responseContentType == "application/json")) {
|
||||
if (responseBody.length() > 0)
|
||||
responseBody = jsonp->second + "(" + responseBody + ");";
|
||||
else responseBody = jsonp->second + "(null);";
|
||||
responseContentType = "application/javascript";
|
||||
}
|
||||
|
||||
return scode;
|
||||
}
|
||||
|
||||
// Must be called after _localConfig is read or modified
|
||||
void applyLocalConfig()
|
||||
|
@ -3941,56 +3388,6 @@ public:
|
|||
_node->processVirtualNetworkFrame((void*)0, OSUtils::now(), nwid, from.toInt(), to.toInt(), etherType, vlanId, data, len, &_nextBackgroundTaskDeadline);
|
||||
}
|
||||
|
||||
inline void onHttpRequestToServer(TcpConnection* tc)
|
||||
{
|
||||
char tmpn[4096];
|
||||
std::string data;
|
||||
std::string contentType("text/plain"); // default if not changed in handleRequest()
|
||||
unsigned int scode = 404;
|
||||
|
||||
// Note that we check allowed IP ranges when HTTP connections are first detected in
|
||||
// phyOnTcpData(). If we made it here the source IP is okay.
|
||||
|
||||
try {
|
||||
scode = handleControlPlaneHttpRequest(tc->remoteAddr, tc->parser.method, tc->url, tc->headers, tc->readq, data, contentType);
|
||||
}
|
||||
catch (std::exception& exc) {
|
||||
fprintf(stderr, "WARNING: unexpected exception processing control HTTP request: %s" ZT_EOL_S, exc.what());
|
||||
scode = 500;
|
||||
}
|
||||
catch (...) {
|
||||
fprintf(stderr, "WARNING: unexpected exception processing control HTTP request: unknown exception" ZT_EOL_S);
|
||||
scode = 500;
|
||||
}
|
||||
|
||||
const char* scodestr;
|
||||
switch (scode) {
|
||||
case 200: scodestr = "OK"; break;
|
||||
case 400: scodestr = "Bad Request"; break;
|
||||
case 401: scodestr = "Unauthorized"; break;
|
||||
case 403: scodestr = "Forbidden"; break;
|
||||
case 404: scodestr = "Not Found"; break;
|
||||
case 500: scodestr = "Internal Server Error"; break;
|
||||
case 501: scodestr = "Not Implemented"; break;
|
||||
case 503: scodestr = "Service Unavailable"; break;
|
||||
default: scodestr = "Error"; break;
|
||||
}
|
||||
|
||||
OSUtils::ztsnprintf(tmpn, sizeof(tmpn), "HTTP/1.1 %.3u %s\r\nCache-Control: no-cache\r\nPragma: no-cache\r\nContent-Type: %s\r\nContent-Length: %lu\r\nConnection: close\r\n\r\n",
|
||||
scode,
|
||||
scodestr,
|
||||
contentType.c_str(),
|
||||
(unsigned long)data.length());
|
||||
{
|
||||
Mutex::Lock _l(tc->writeq_m);
|
||||
tc->writeq = tmpn;
|
||||
if (tc->parser.method != HTTP_HEAD)
|
||||
tc->writeq.append(data);
|
||||
}
|
||||
|
||||
_phy.setNotifyWritable(tc->sock, true);
|
||||
}
|
||||
|
||||
inline void onHttpResponseFromClient(TcpConnection* tc)
|
||||
{
|
||||
_phy.close(tc->sock);
|
||||
|
@ -4205,7 +3602,6 @@ static int ShttpOnMessageComplete(http_parser *parser)
|
|||
{
|
||||
TcpConnection *tc = reinterpret_cast<TcpConnection *>(parser->data);
|
||||
if (tc->type == TcpConnection::TCP_HTTP_INCOMING) {
|
||||
tc->parent->onHttpRequestToServer(tc);
|
||||
} else {
|
||||
tc->parent->onHttpResponseFromClient(tc);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue