diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2015-04-14 13:56:28 -0700 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2015-04-14 13:56:28 -0700 |
commit | 1cfa67bbdd4242a52484f13f3533babb4d4c07a6 (patch) | |
tree | d772b3b7cc40371afaa494c4e623511133e0e33e /service | |
parent | a2605561af19d7de7ed492d1faf00d7ff161c6ea (diff) | |
download | infinitytier-1cfa67bbdd4242a52484f13f3533babb4d4c07a6.tar.gz infinitytier-1cfa67bbdd4242a52484f13f3533babb4d4c07a6.zip |
Bunch more control plane work, and shelve old UI -- React FTW.
Diffstat (limited to 'service')
-rw-r--r-- | service/ControlPlane.cpp | 291 | ||||
-rw-r--r-- | service/ControlPlane.hpp | 5 | ||||
-rw-r--r-- | service/One.cpp | 18 |
3 files changed, 206 insertions, 108 deletions
diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp index dceba8d6..5077dce9 100644 --- a/service/ControlPlane.cpp +++ b/service/ControlPlane.cpp @@ -36,6 +36,8 @@ #include "../node/Node.hpp" #include "../node/Utils.hpp" +#define ZT_BUILD_IN_WEB_UI + namespace ZeroTier { static std::string _jsonEscape(const char *s) @@ -102,7 +104,12 @@ static std::string _jsonEnumerate(const ZT1_PeerPhysicalPath *pp,unsigned int co buf.push_back(','); buf.append("{\"address\":\""); buf.append(_jsonEscape(reinterpret_cast<const InetAddress *>(&(pp[i].address))->toString())); - Utils::snprintf(tmp,sizeof(tmp),"\",\"lastSend\":%llu,\"lastReceive\":%llu,\"fixed\":%s}",pp[i].lastSend,pp[i].lastReceive,(pp[i].fixed == 0) ? "falase" : "true"); + Utils::snprintf(tmp,sizeof(tmp),"\",\"lastSend\":%llu,\"lastReceive\":%llu,\"fixed\":%s,\"active\":%s,\"preferred\":%s}", + pp[i].lastSend, + pp[i].lastReceive, + (pp[i].fixed == 0) ? "false" : "true", + (pp[i].active == 0) ? "false" : "true", + (pp[i].preferred == 0) ? "false" : "true"); buf.append(tmp); } buf.push_back(']'); @@ -186,9 +193,8 @@ static void _jsonAppend(std::string &buf,const ZT1_Peer *peer) buf.append(json); } -ControlPlane::ControlPlane(Node *n,const std::set<std::string> atoks) : - _node(n), - _authTokens(atoks) +ControlPlane::ControlPlane(Node *n) : + _node(n) { } @@ -197,6 +203,7 @@ ControlPlane::~ControlPlane() } unsigned int ControlPlane::handleRequest( + const InetAddress &fromAddress, unsigned int httpMethod, const std::string &path, const std::map<std::string,std::string> &headers, @@ -209,11 +216,13 @@ unsigned int ControlPlane::handleRequest( std::vector<std::string> ps(Utils::split(path.c_str(),"/","","")); std::map<std::string,std::string> urlArgs; + if (!((fromAddress.ipsEqual(InetAddress::LO4))||(fromAddress.ipsEqual(InetAddress::LO6)))) + return 403; // Forbidden: we only allow access from localhost right now + /* 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=funcionName, and otherwise it just takes simple * paths to simply-named resources. */ - if (ps.size() > 0) { std::size_t qpos = ps[ps.size() - 1].find('?'); if (qpos != std::string::npos) { @@ -228,112 +237,202 @@ unsigned int ControlPlane::handleRequest( } } } else { - ps.push_back(std::string("index")); + ps.push_back(std::string("index.html")); } + bool isAuth = true; // TODO: auth tokens + if (httpMethod == HTTP_GET) { - if (ps[0] == "index") { - responseContentType = "text/html"; + + std::string ext; + std::size_t dotIdx = ps[0].find_last_of('.'); + if (dotIdx != std::string::npos) + ext = ps[0].substr(dotIdx); + + if ((ps.size() == 1)&&(ext.length() >= 2)&&(ext[0] == '.')) { +#ifdef ZT_BUILD_IN_WEB_UI + // .anything == static page -- also the only thing you can get without isAuth == true + if (ext == ".html") + responseContentType = "text/html"; + else if (ext == ".js") + responseContentType = "application/javascript"; + else if (ext == ".json") + responseContentType = "application/json"; + else if (ext == ".css") + responseContentType = "text/css"; + else if (ext == ".png") + responseContentType = "image/png"; + else if (ext == ".jpg") + responseContentType = "image/jpeg"; + else if (ext == ".gif") + responseContentType = "image/gif"; + else if (ext == ".txt") + responseContentType = "text/plain"; + else if (ext == ".xml") + responseContentType = "text/xml"; + else if (ext == ".svg") + responseContentType = "image/svg+xml"; + else responseContentType = "application/octet-stream"; responseBody = "<html><body>Hello World!</body></html>"; scode = 200; - } else if (ps[0] == "status") { - responseContentType = "application/json"; - ZT1_NodeStatus status; - _node->status(&status); - Utils::snprintf(json,sizeof(json), - "{" - "\"address\":\"%.10llx\"," - "\"publicIdentity\":\"%s\"," - "\"online\":%s," - "\"versionMajor\":%d," - "\"versionMinor\":%d," - "\"versionRev\":%d," - "\"version\":\"%d.%d.%d\"" - "}", - status.address, - status.publicIdentity, - (status.online) ? "true" : "false", - ZEROTIER_ONE_VERSION_MAJOR, - ZEROTIER_ONE_VERSION_MINOR, - ZEROTIER_ONE_VERSION_REVISION, - ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION); - responseBody = json; - scode = 200; - } else if (ps[0] == "config") { - responseContentType = "application/json"; - responseBody = "{}"; // TODO - scode = 200; - } else if (ps[0] == "network") { - ZT1_VirtualNetworkList *nws = _node->networks(); - if (nws) { - if (ps.size() == 1) { - // Return [array] of all networks - responseContentType = "application/json"; - responseBody = "["; - for(unsigned long i=0;i<nws->networkCount;++i) { - if (i > 0) - responseBody.push_back(','); - _jsonAppend(responseBody,&(nws->networks[i])); - } - responseBody.push_back(']'); - scode = 200; - } else if (ps.size() == 2) { - // Return a single network by ID or 404 if not found - uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str()); - for(unsigned long i=0;i<nws->networkCount;++i) { - if (nws->networks[i].nwid == wantnw) { +#endif // ZT_BUILD_IN_WEB_UI + } else if (isAuth) { + if (ps[0] == "status") { + responseContentType = "application/json"; + ZT1_NodeStatus status; + _node->status(&status); + Utils::snprintf(json,sizeof(json), + "{" + "\"address\":\"%.10llx\"," + "\"publicIdentity\":\"%s\"," + "\"online\":%s," + "\"versionMajor\":%d," + "\"versionMinor\":%d," + "\"versionRev\":%d," + "\"version\":\"%d.%d.%d\"" + "}", + status.address, + status.publicIdentity, + (status.online) ? "true" : "false", + ZEROTIER_ONE_VERSION_MAJOR, + ZEROTIER_ONE_VERSION_MINOR, + ZEROTIER_ONE_VERSION_REVISION, + ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION); + responseBody = json; + scode = 200; + } else if (ps[0] == "config") { + responseContentType = "application/json"; + responseBody = "{}"; // TODO + scode = 200; + } else if (ps[0] == "network") { + if ((ps.size() > 1)&&(ps[1] == "controller")) { + // TODO + } else { + ZT1_VirtualNetworkList *nws = _node->networks(); + if (nws) { + if (ps.size() == 1) { + // Return [array] of all networks responseContentType = "application/json"; - _jsonAppend(responseBody,&(nws->networks[i])); + responseBody = "["; + for(unsigned long i=0;i<nws->networkCount;++i) { + if (i > 0) + responseBody.push_back(','); + _jsonAppend(responseBody,&(nws->networks[i])); + } + responseBody.push_back(']'); scode = 200; - break; - } - } - } // else 404 - _node->freeQueryResult((void *)nws); - } else { - scode = 500; - } - } else if (ps[0] == "peer") { - ZT1_PeerList *pl = _node->peers(); - if (pl) { - if (ps.size() == 1) { - // Return [array] of all peers - responseContentType = "application/json"; - responseBody = "["; - for(unsigned long i=0;i<pl->peerCount;++i) { - if (i > 0) - responseBody.push_back(','); - _jsonAppend(responseBody,&(pl->peers[i])); - } - responseBody.push_back(']'); - 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) { - responseContentType = "application/json"; + } else if (ps.size() == 2) { + // Return a single network by ID or 404 if not found + uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str()); + for(unsigned long i=0;i<nws->networkCount;++i) { + if (nws->networks[i].nwid == wantnw) { + responseContentType = "application/json"; + _jsonAppend(responseBody,&(nws->networks[i])); + scode = 200; + break; + } + } + } // else 404 + _node->freeQueryResult((void *)nws); + } else scode = 500; + } + } else if (ps[0] == "peer") { + ZT1_PeerList *pl = _node->peers(); + if (pl) { + if (ps.size() == 1) { + // Return [array] of all peers + responseContentType = "application/json"; + responseBody = "["; + for(unsigned long i=0;i<pl->peerCount;++i) { + if (i > 0) + responseBody.push_back(','); _jsonAppend(responseBody,&(pl->peers[i])); - scode = 200; - break; } - } - } // else 404 - _node->freeQueryResult((void *)pl); - } else { - scode = 500; - } - } - } else if ((httpMethod == HTTP_POST)||(httpMethod == HTTP_PUT)) { // PUT is weird in REST but we'll take it anyway + responseBody.push_back(']'); + 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) { + responseContentType = "application/json"; + _jsonAppend(responseBody,&(pl->peers[i])); + scode = 200; + break; + } + } + } // else 404 + _node->freeQueryResult((void *)pl); + } else scode = 500; + } // else 404 + } else scode = 401; // isAuth == false + + } else if ((httpMethod == HTTP_POST)||(httpMethod == HTTP_PUT)) { + + if (isAuth) { + if (ps[0] == "config") { + // TODO + } else if (ps[0] == "network") { + if ((ps.size() > 1)&&(ps[1] == "controller")) { + // TODO + } else { + if (ps.size() == 2) { + uint64_t wantnw = Utils::hexStrToU64(ps[1].c_str()); + _node->join(wantnw); // does nothing if we are a member + ZT1_VirtualNetworkList *nws = _node->networks(); + if (nws) { + for(unsigned long i=0;i<nws->networkCount;++i) { + if (nws->networks[i].nwid == wantnw) { + responseContentType = "application/json"; + _jsonAppend(responseBody,&(nws->networks[i])); + scode = 200; + break; + } + } + _node->freeQueryResult((void *)nws); + } else scode = 500; + } // else 404 + } + } // else 404 + } else scode = 401; // isAuth == false + } else if (httpMethod == HTTP_DELETE) { + + if (isAuth) { + if (ps[0] == "config") { + // TODO + } else if (ps[0] == "network") { + if ((ps.size() > 1)&&(ps[1] == "controller")) { + // TODO + } else { + ZT1_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); + responseBody = "true"; + responseContentType = "application/json"; + scode = 200; + break; + } + } + } // else 404 + _node->freeQueryResult((void *)nws); + } else scode = 500; + } + } // else 404 + } else scode = 401; // isAuth = false + } else { scode = 400; - responseBody = "Method not supported for resource "; - responseBody.append(path); + responseBody = "Method not supported."; } + // Wrap result in jsonp function call if the user included a jsonp= url argument std::map<std::string,std::string>::const_iterator jsonp(urlArgs.find("jsonp")); - if (jsonp != urlArgs.end()) { + if ((jsonp != urlArgs.end())&&(responseContentType == "application/json")) { if (responseBody.length() > 0) responseBody = jsonp->second + "(" + responseBody + ");"; else responseBody = jsonp->second + "(null);"; diff --git a/service/ControlPlane.hpp b/service/ControlPlane.hpp index 29b84faa..87a65ead 100644 --- a/service/ControlPlane.hpp +++ b/service/ControlPlane.hpp @@ -37,6 +37,7 @@ namespace ZeroTier { class Node; +struct InetAddress; /** * HTTP control plane and static web server @@ -44,12 +45,13 @@ class Node; class ControlPlane { public: - ControlPlane(Node *n,const std::set<std::string> atoks); + ControlPlane(Node *n); ~ControlPlane(); /** * Handle HTTP request * + * @param fromAddress Originating IP address of request * @param httpMethod HTTP method (as defined in ext/http-parser/http_parser.h) * @param path Request path * @param headers Request headers @@ -59,6 +61,7 @@ public: * @return HTTP response code */ unsigned int handleRequest( + const InetAddress &fromAddress, unsigned int httpMethod, const std::string &path, const std::map<std::string,std::string> &headers, diff --git a/service/One.cpp b/service/One.cpp index 08210da1..5e81bc61 100644 --- a/service/One.cpp +++ b/service/One.cpp @@ -189,7 +189,7 @@ public: if (_master) _node->setNetconfMaster((void *)_master); - _controlPlane = new ControlPlane(_node,std::set<std::string>()); + _controlPlane = new ControlPlane(_node); _nextBackgroundTaskDeadline = 0; for(;;) { @@ -454,16 +454,12 @@ public: std::string contentType("text/plain"); // default if not changed in handleRequest() unsigned int scode = 404; - if ((htc->from.ipsEqual(InetAddress::LO4))||(htc->from.ipsEqual(InetAddress::LO6))) { - try { - if (_controlPlane) - scode = _controlPlane->handleRequest(htc->parser.method,htc->url,htc->headers,htc->body,data,contentType); - } catch ( ... ) { - scode = 500; - } - } else { - scode = 403; - htc->shouldKeepAlive = false; + try { + if (_controlPlane) + scode = _controlPlane->handleRequest(htc->from,htc->parser.method,htc->url,htc->headers,htc->body,data,contentType); + else scode = 500; + } catch ( ... ) { + scode = 500; } const char *scodestr; |