mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2025-06-06 12:33:44 +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)
|
void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt)
|
||||||
{
|
{
|
||||||
static volatile unsigned long idCounter = 0;
|
static volatile unsigned long idCounter = 0;
|
||||||
|
|
|
@ -72,28 +72,6 @@ public:
|
||||||
httplib::Server &s,
|
httplib::Server &s,
|
||||||
const std::function<void(const httplib::Request&, httplib::Response&, std::string)>);
|
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);
|
void handleRemoteTrace(const ZT_RemoteTrace &rt);
|
||||||
|
|
||||||
virtual void onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network);
|
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
|
// Must be called after _localConfig is read or modified
|
||||||
void applyLocalConfig()
|
void applyLocalConfig()
|
||||||
|
@ -3941,56 +3388,6 @@ public:
|
||||||
_node->processVirtualNetworkFrame((void*)0, OSUtils::now(), nwid, from.toInt(), to.toInt(), etherType, vlanId, data, len, &_nextBackgroundTaskDeadline);
|
_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)
|
inline void onHttpResponseFromClient(TcpConnection* tc)
|
||||||
{
|
{
|
||||||
_phy.close(tc->sock);
|
_phy.close(tc->sock);
|
||||||
|
@ -4205,7 +3602,6 @@ static int ShttpOnMessageComplete(http_parser *parser)
|
||||||
{
|
{
|
||||||
TcpConnection *tc = reinterpret_cast<TcpConnection *>(parser->data);
|
TcpConnection *tc = reinterpret_cast<TcpConnection *>(parser->data);
|
||||||
if (tc->type == TcpConnection::TCP_HTTP_INCOMING) {
|
if (tc->type == TcpConnection::TCP_HTTP_INCOMING) {
|
||||||
tc->parent->onHttpRequestToServer(tc);
|
|
||||||
} else {
|
} else {
|
||||||
tc->parent->onHttpResponseFromClient(tc);
|
tc->parent->onHttpResponseFromClient(tc);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue