summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorAdam Ierymenko <adam.ierymenko@gmail.com>2015-04-14 13:56:28 -0700
committerAdam Ierymenko <adam.ierymenko@gmail.com>2015-04-14 13:56:28 -0700
commit1cfa67bbdd4242a52484f13f3533babb4d4c07a6 (patch)
treed772b3b7cc40371afaa494c4e623511133e0e33e /service
parenta2605561af19d7de7ed492d1faf00d7ff161c6ea (diff)
downloadinfinitytier-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.cpp291
-rw-r--r--service/ControlPlane.hpp5
-rw-r--r--service/One.cpp18
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;