diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 95c9cc82b..46ce94941 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -1076,595 +1076,6 @@ void EmbeddedNetworkController::configureHTTPControlPlane( }); } -unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET( - const std::vector &path, - const std::map &urlArgs, - const std::map &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 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 networkIds; - _db.networks(networkIds); - char tmp[64]; - responseBody = "["; - responseBody.reserve((networkIds.size() + 1) * 24); - for(std::set::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 &path, - const std::map &urlArgs, - const std::map &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= ZT_CONTROLLER_MAX_ARRAY_SIZE) - break; - } - } - member["ipAssignments"] = mipa; - } - } - - if (b.count("tags")) { - json &tags = b["tags"]; - if (tags.is_array()) { - std::map mtags; - for(unsigned long i=0;i::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= 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 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::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().c_str()); - InetAddress v; - if (via.is_string()) v.fromString(via.get().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= 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= 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= 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::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 &path, - const std::map &urlArgs, - const std::map &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 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 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; diff --git a/controller/EmbeddedNetworkController.hpp b/controller/EmbeddedNetworkController.hpp index 7269a83cc..347869b47 100644 --- a/controller/EmbeddedNetworkController.hpp +++ b/controller/EmbeddedNetworkController.hpp @@ -72,28 +72,6 @@ public: httplib::Server &s, const std::function); - unsigned int handleControlPlaneHttpGET( - const std::vector &path, - const std::map &urlArgs, - const std::map &headers, - const std::string &body, - std::string &responseBody, - std::string &responseContentType); - unsigned int handleControlPlaneHttpPOST( - const std::vector &path, - const std::map &urlArgs, - const std::map &headers, - const std::string &body, - std::string &responseBody, - std::string &responseContentType); - unsigned int handleControlPlaneHttpDELETE( - const std::vector &path, - const std::map &urlArgs, - const std::map &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); diff --git a/service/OneService.cpp b/service/OneService.cpp index b6d33fec5..1154168ec 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -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 &headers, - const std::string &body, - std::string &responseBody, - std::string &responseContentType) - { - char tmp[256]; - unsigned int scode = 404; - json res; - std::vector ps(OSUtils::split(path.c_str(),"/","","")); - std::map 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 asplit(OSUtils::split(args.c_str(),"&","","")); - for(std::vector::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::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::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;ipeerCount;++i) { - if (pl->peers[i].address == wantp) { - if (ps[1] == "show") { - SharedPtr 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 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 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 moons(_node->moons()); - if (ps.size() == 1) { - // Return [array] of all moons - - res = json::array(); - for(std::vector::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::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;ipeerCount;++i) { - nlohmann::json pj; - SharedPtr bond = SharedPtr(); - 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;ipeerCount;++i) { - if (pl->peers[i].address == wantp) { - SharedPtr bond = SharedPtr(); - 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(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 = _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 moons(_node->moons()); - const uint64_t id = Utils::hexStrToU64(ps[1].c_str()); - for(std::vector::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(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;inetworkCount;++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(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::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(parser->data); if (tc->type == TcpConnection::TCP_HTTP_INCOMING) { - tc->parent->onHttpRequestToServer(tc); } else { tc->parent->onHttpResponseFromClient(tc); }