Browse Source

Bunch more control plane work, and shelve old UI -- React FTW.

Adam Ierymenko 10 years ago
parent
commit
1cfa67bbdd
43 changed files with 233 additions and 120 deletions
  1. 0 0
      attic/ZeroTierUI/Info.plist
  2. 0 0
      attic/ZeroTierUI/README.md
  3. 0 0
      attic/ZeroTierUI/WindowsBuildOfficial.bat
  4. 0 0
      attic/ZeroTierUI/ZT1GUI.png
  5. 0 0
      attic/ZeroTierUI/ZT1GUI.xcf
  6. 0 0
      attic/ZeroTierUI/ZeroTierUI.pro
  7. 0 0
      attic/ZeroTierUI/ZeroTierUI.rc
  8. 0 0
      attic/ZeroTierUI/aboutwindow.cpp
  9. 0 0
      attic/ZeroTierUI/aboutwindow.h
  10. 0 0
      attic/ZeroTierUI/aboutwindow.ui
  11. 0 0
      attic/ZeroTierUI/installdialog.cpp
  12. 0 0
      attic/ZeroTierUI/installdialog.h
  13. 0 0
      attic/ZeroTierUI/installdialog.ui
  14. 0 0
      attic/ZeroTierUI/licensedialog.cpp
  15. 0 0
      attic/ZeroTierUI/licensedialog.h
  16. 0 0
      attic/ZeroTierUI/licensedialog.ui
  17. 0 0
      attic/ZeroTierUI/mac_doprivileged.h
  18. 0 0
      attic/ZeroTierUI/mac_doprivileged.mm
  19. 0 0
      attic/ZeroTierUI/main.cpp
  20. 0 0
      attic/ZeroTierUI/main.h
  21. 0 0
      attic/ZeroTierUI/mainwindow.cpp
  22. 0 0
      attic/ZeroTierUI/mainwindow.h
  23. 0 0
      attic/ZeroTierUI/mainwindow.ui
  24. 0 0
      attic/ZeroTierUI/networkwidget.cpp
  25. 0 0
      attic/ZeroTierUI/networkwidget.h
  26. 0 0
      attic/ZeroTierUI/networkwidget.ui
  27. 0 0
      attic/ZeroTierUI/onetimedialog.cpp
  28. 0 0
      attic/ZeroTierUI/onetimedialog.h
  29. 0 0
      attic/ZeroTierUI/onetimedialog.ui
  30. 0 0
      attic/ZeroTierUI/quickstartdialog.ui
  31. 0 0
      attic/ZeroTierUI/resources.qrc
  32. 0 0
      attic/ZeroTierUI/stylesheet.css
  33. 0 0
      attic/ZeroTierUI/zt1icon.icns
  34. 0 0
      attic/ZeroTierUI/zt1icon.ico
  35. 0 0
      attic/ZeroTierUI/zt1icon.png
  36. 0 0
      attic/testnet.cpp
  37. 13 0
      include/ZeroTierOne.h
  38. 10 11
      make-mac.mk
  39. 3 0
      node/Node.cpp
  40. 1 1
      node/Peer.cpp
  41. 195 96
      service/ControlPlane.cpp
  42. 4 1
      service/ControlPlane.hpp
  43. 7 11
      service/One.cpp

+ 0 - 0
ZeroTierUI/Info.plist → attic/ZeroTierUI/Info.plist


+ 0 - 0
ZeroTierUI/README.md → attic/ZeroTierUI/README.md


+ 0 - 0
ZeroTierUI/WindowsBuildOfficial.bat → attic/ZeroTierUI/WindowsBuildOfficial.bat


+ 0 - 0
ZeroTierUI/ZT1GUI.png → attic/ZeroTierUI/ZT1GUI.png


+ 0 - 0
ZeroTierUI/ZT1GUI.xcf → attic/ZeroTierUI/ZT1GUI.xcf


+ 0 - 0
ZeroTierUI/ZeroTierUI.pro → attic/ZeroTierUI/ZeroTierUI.pro


+ 0 - 0
ZeroTierUI/ZeroTierUI.rc → attic/ZeroTierUI/ZeroTierUI.rc


+ 0 - 0
ZeroTierUI/aboutwindow.cpp → attic/ZeroTierUI/aboutwindow.cpp


+ 0 - 0
ZeroTierUI/aboutwindow.h → attic/ZeroTierUI/aboutwindow.h


+ 0 - 0
ZeroTierUI/aboutwindow.ui → attic/ZeroTierUI/aboutwindow.ui


+ 0 - 0
ZeroTierUI/installdialog.cpp → attic/ZeroTierUI/installdialog.cpp


+ 0 - 0
ZeroTierUI/installdialog.h → attic/ZeroTierUI/installdialog.h


+ 0 - 0
ZeroTierUI/installdialog.ui → attic/ZeroTierUI/installdialog.ui


+ 0 - 0
ZeroTierUI/licensedialog.cpp → attic/ZeroTierUI/licensedialog.cpp


+ 0 - 0
ZeroTierUI/licensedialog.h → attic/ZeroTierUI/licensedialog.h


+ 0 - 0
ZeroTierUI/licensedialog.ui → attic/ZeroTierUI/licensedialog.ui


+ 0 - 0
ZeroTierUI/mac_doprivileged.h → attic/ZeroTierUI/mac_doprivileged.h


+ 0 - 0
ZeroTierUI/mac_doprivileged.mm → attic/ZeroTierUI/mac_doprivileged.mm


+ 0 - 0
ZeroTierUI/main.cpp → attic/ZeroTierUI/main.cpp


+ 0 - 0
ZeroTierUI/main.h → attic/ZeroTierUI/main.h


+ 0 - 0
ZeroTierUI/mainwindow.cpp → attic/ZeroTierUI/mainwindow.cpp


+ 0 - 0
ZeroTierUI/mainwindow.h → attic/ZeroTierUI/mainwindow.h


+ 0 - 0
ZeroTierUI/mainwindow.ui → attic/ZeroTierUI/mainwindow.ui


+ 0 - 0
ZeroTierUI/networkwidget.cpp → attic/ZeroTierUI/networkwidget.cpp


+ 0 - 0
ZeroTierUI/networkwidget.h → attic/ZeroTierUI/networkwidget.h


+ 0 - 0
ZeroTierUI/networkwidget.ui → attic/ZeroTierUI/networkwidget.ui


+ 0 - 0
ZeroTierUI/onetimedialog.cpp → attic/ZeroTierUI/onetimedialog.cpp


+ 0 - 0
ZeroTierUI/onetimedialog.h → attic/ZeroTierUI/onetimedialog.h


+ 0 - 0
ZeroTierUI/onetimedialog.ui → attic/ZeroTierUI/onetimedialog.ui


+ 0 - 0
ZeroTierUI/quickstartdialog.ui → attic/ZeroTierUI/quickstartdialog.ui


+ 0 - 0
ZeroTierUI/resources.qrc → attic/ZeroTierUI/resources.qrc


+ 0 - 0
ZeroTierUI/stylesheet.css → attic/ZeroTierUI/stylesheet.css


+ 0 - 0
ZeroTierUI/zt1icon.icns → attic/ZeroTierUI/zt1icon.icns


+ 0 - 0
ZeroTierUI/zt1icon.ico → attic/ZeroTierUI/zt1icon.ico


+ 0 - 0
ZeroTierUI/zt1icon.png → attic/ZeroTierUI/zt1icon.png


+ 0 - 0
testnet.cpp → attic/testnet.cpp


+ 13 - 0
include/ZeroTierOne.h

@@ -524,6 +524,16 @@ typedef struct
 	 * Is path fixed? (i.e. not learned, static)
 	 * Is path fixed? (i.e. not learned, static)
 	 */
 	 */
 	int fixed;
 	int fixed;
+
+	/**
+	 * Is path active?
+	 */
+	int active;
+
+	/**
+	 * Is path preferred?
+	 */
+	int preferred;
 } ZT1_PeerPhysicalPath;
 } ZT1_PeerPhysicalPath;
 
 
 /**
 /**
@@ -796,6 +806,9 @@ enum ZT1_ResultCode ZT1_Node_processBackgroundTasks(ZT1_Node *node,uint64_t now,
  * This may generate calls to the port config callback before it returns,
  * This may generate calls to the port config callback before it returns,
  * or these may be deffered if a netconf is not available yet.
  * or these may be deffered if a netconf is not available yet.
  *
  *
+ * If we are already a member of the network, nothing is done and OK is
+ * returned.
+ *
  * @param node Node instance
  * @param node Node instance
  * @param nwid 64-bit ZeroTier network ID
  * @param nwid 64-bit ZeroTier network ID
  * @return OK (0) or error code if a fatal error condition has occurred
  * @return OK (0) or error code if a fatal error condition has occurred

+ 10 - 11
make-mac.mk

@@ -63,18 +63,18 @@ selftest: $(OBJS) selftest.o
 	$(CXX) $(CXXFLAGS) -o zerotier-selftest selftest.o $(OBJS) $(LIBS)
 	$(CXX) $(CXXFLAGS) -o zerotier-selftest selftest.o $(OBJS) $(LIBS)
 	$(STRIP) zerotier-selftest
 	$(STRIP) zerotier-selftest
 
 
-testnet: $(TESTNET_OBJS) $(OBJS) testnet.o
-	$(CXX) $(CXXFLAGS) -o zerotier-testnet testnet.o $(OBJS) $(TESTNET_OBJS) $(LIBS)
-	$(STRIP) zerotier-testnet
+#testnet: $(TESTNET_OBJS) $(OBJS) testnet.o
+#	$(CXX) $(CXXFLAGS) -o zerotier-testnet testnet.o $(OBJS) $(TESTNET_OBJS) $(LIBS)
+#	$(STRIP) zerotier-testnet
 
 
 # Requires that ../Qt be symlinked to the Qt root to use for UI build
 # Requires that ../Qt be symlinked to the Qt root to use for UI build
-mac-ui: FORCE
-	mkdir -p build-ZeroTierUI-release
-	cd build-ZeroTierUI-release ; ../../Qt/bin/qmake ../ZeroTierUI/ZeroTierUI.pro ; make -j 4
-	strip "build-ZeroTierUI-release/ZeroTier One.app/Contents/MacOS/ZeroTier One"
-	find "build-ZeroTierUI-release/ZeroTier One.app" -type f -name '.DS_Store' -print0 | xargs -0 rm -f
-	$(CODESIGN) -f -s $(CODESIGN_CERT) "build-ZeroTierUI-release/ZeroTier One.app"
-	$(CODESIGN) -vvv "build-ZeroTierUI-release/ZeroTier One.app"
+#mac-ui: FORCE
+#	mkdir -p build-ZeroTierUI-release
+#	cd build-ZeroTierUI-release ; ../../Qt/bin/qmake ../ZeroTierUI/ZeroTierUI.pro ; make -j 4
+#	strip "build-ZeroTierUI-release/ZeroTier One.app/Contents/MacOS/ZeroTier One"
+#	find "build-ZeroTierUI-release/ZeroTier One.app" -type f -name '.DS_Store' -print0 | xargs -0 rm -f
+#	$(CODESIGN) -f -s $(CODESIGN_CERT) "build-ZeroTierUI-release/ZeroTier One.app"
+#	$(CODESIGN) -vvv "build-ZeroTierUI-release/ZeroTier One.app"
 
 
 clean:
 clean:
 	rm -rf *.dSYM build-* *.o netconf/*.o service/*.o node/*.o osdep/*.o ext/http-parser/*.o ext/lz4/*.o zerotier-* ZeroTierOneInstaller-* "ZeroTier One.zip" "ZeroTier One.dmg"
 	rm -rf *.dSYM build-* *.o netconf/*.o service/*.o node/*.o osdep/*.o ext/http-parser/*.o ext/lz4/*.o zerotier-* ZeroTierOneInstaller-* "ZeroTier One.zip" "ZeroTier One.dmg"
@@ -82,7 +82,6 @@ clean:
 # For our use -- builds official signed binary, packages in installer and download DMG
 # For our use -- builds official signed binary, packages in installer and download DMG
 official: FORCE
 official: FORCE
 	make -j 4 ZT_OFFICIAL_RELEASE=1
 	make -j 4 ZT_OFFICIAL_RELEASE=1
-	make mac-ui ZT_OFFICIAL_RELEASE=1
 	./buildinstaller.sh
 	./buildinstaller.sh
 	make mac-dmg ZT_OFFICIAL_RELEASE=1
 	make mac-dmg ZT_OFFICIAL_RELEASE=1
 
 

+ 3 - 0
node/Node.cpp

@@ -357,12 +357,15 @@ ZT1_PeerList *Node::peers() const
 		p->role = RR->topology->isSupernode(pi->second->address()) ? ZT1_PEER_ROLE_SUPERNODE : ZT1_PEER_ROLE_LEAF;
 		p->role = RR->topology->isSupernode(pi->second->address()) ? ZT1_PEER_ROLE_SUPERNODE : ZT1_PEER_ROLE_LEAF;
 
 
 		std::vector<Path> paths(pi->second->paths());
 		std::vector<Path> paths(pi->second->paths());
+		Path *bestPath = pi->second->getBestPath(_now);
 		p->pathCount = 0;
 		p->pathCount = 0;
 		for(std::vector<Path>::iterator path(paths.begin());path!=paths.end();++path) {
 		for(std::vector<Path>::iterator path(paths.begin());path!=paths.end();++path) {
 			memcpy(&(p->paths[p->pathCount].address),&(path->address()),sizeof(struct sockaddr_storage));
 			memcpy(&(p->paths[p->pathCount].address),&(path->address()),sizeof(struct sockaddr_storage));
 			p->paths[p->pathCount].lastSend = path->lastSend();
 			p->paths[p->pathCount].lastSend = path->lastSend();
 			p->paths[p->pathCount].lastReceive = path->lastReceived();
 			p->paths[p->pathCount].lastReceive = path->lastReceived();
 			p->paths[p->pathCount].fixed = path->fixed() ? 1 : 0;
 			p->paths[p->pathCount].fixed = path->fixed() ? 1 : 0;
+			p->paths[p->pathCount].active = path->active(_now) ? 1 : 0;
+			p->paths[p->pathCount].preferred = ((bestPath)&&(*path == *bestPath)) ? 1 : 0;
 			++p->pathCount;
 			++p->pathCount;
 		}
 		}
 	}
 	}

+ 1 - 1
node/Peer.cpp

@@ -111,7 +111,7 @@ void Peer::received(
 					 * paths without confirming that a bidirectional link is in
 					 * paths without confirming that a bidirectional link is in
 					 * fact present, but any packet that decodes and authenticates
 					 * fact present, but any packet that decodes and authenticates
 					 * correctly is considered valid. */
 					 * correctly is considered valid. */
-					TRACE("got non-confirmation packet from unknown path %s(%s), pinging...",_id.address().toString().c_str(),remoteAddr.toString().c_str());
+					TRACE("got non-confirmation %s from unknown path %s(%s), pinging...",Packet::verbString(verb),_id.address().toString().c_str(),remoteAddr.toString().c_str());
 					attemptToContactAt(RR,remoteAddr,linkDesperation,now);
 					attemptToContactAt(RR,remoteAddr,linkDesperation,now);
 				}
 				}
 			}
 			}

+ 195 - 96
service/ControlPlane.cpp

@@ -36,6 +36,8 @@
 #include "../node/Node.hpp"
 #include "../node/Node.hpp"
 #include "../node/Utils.hpp"
 #include "../node/Utils.hpp"
 
 
+#define ZT_BUILD_IN_WEB_UI
+
 namespace ZeroTier {
 namespace ZeroTier {
 
 
 static std::string _jsonEscape(const char *s)
 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.push_back(',');
 		buf.append("{\"address\":\"");
 		buf.append("{\"address\":\"");
 		buf.append(_jsonEscape(reinterpret_cast<const InetAddress *>(&(pp[i].address))->toString()));
 		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.append(tmp);
 	}
 	}
 	buf.push_back(']');
 	buf.push_back(']');
@@ -186,9 +193,8 @@ static void _jsonAppend(std::string &buf,const ZT1_Peer *peer)
 	buf.append(json);
 	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(
 unsigned int ControlPlane::handleRequest(
+	const InetAddress &fromAddress,
 	unsigned int httpMethod,
 	unsigned int httpMethod,
 	const std::string &path,
 	const std::string &path,
 	const std::map<std::string,std::string> &headers,
 	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::vector<std::string> ps(Utils::split(path.c_str(),"/","",""));
 	std::map<std::string,std::string> urlArgs;
 	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
 	/* 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
 	 * 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
 	 * it really uses in ?jsonp=funcionName, and otherwise it just takes simple
 	 * paths to simply-named resources. */
 	 * paths to simply-named resources. */
-
 	if (ps.size() > 0) {
 	if (ps.size() > 0) {
 		std::size_t qpos = ps[ps.size() - 1].find('?');
 		std::size_t qpos = ps[ps.size() - 1].find('?');
 		if (qpos != std::string::npos) {
 		if (qpos != std::string::npos) {
@@ -228,112 +237,202 @@ unsigned int ControlPlane::handleRequest(
 			}
 			}
 		}
 		}
 	} else {
 	} 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 (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>";
 			responseBody = "<html><body>Hello World!</body></html>";
 			scode = 200;
 			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";
 							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;
 							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]));
 							_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) {
 	} 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 {
 	} else {
 		scode = 400;
 		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"));
 	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)
 		if (responseBody.length() > 0)
 			responseBody = jsonp->second + "(" + responseBody + ");";
 			responseBody = jsonp->second + "(" + responseBody + ");";
 		else responseBody = jsonp->second + "(null);";
 		else responseBody = jsonp->second + "(null);";

+ 4 - 1
service/ControlPlane.hpp

@@ -37,6 +37,7 @@
 namespace ZeroTier {
 namespace ZeroTier {
 
 
 class Node;
 class Node;
+struct InetAddress;
 
 
 /**
 /**
  * HTTP control plane and static web server
  * HTTP control plane and static web server
@@ -44,12 +45,13 @@ class Node;
 class ControlPlane
 class ControlPlane
 {
 {
 public:
 public:
-	ControlPlane(Node *n,const std::set<std::string> atoks);
+	ControlPlane(Node *n);
 	~ControlPlane();
 	~ControlPlane();
 
 
 	/**
 	/**
 	 * Handle HTTP request
 	 * Handle HTTP request
 	 *
 	 *
+	 * @param fromAddress Originating IP address of request
 	 * @param httpMethod HTTP method (as defined in ext/http-parser/http_parser.h)
 	 * @param httpMethod HTTP method (as defined in ext/http-parser/http_parser.h)
 	 * @param path Request path
 	 * @param path Request path
 	 * @param headers Request headers
 	 * @param headers Request headers
@@ -59,6 +61,7 @@ public:
 	 * @return HTTP response code
 	 * @return HTTP response code
 	 */
 	 */
 	unsigned int handleRequest(
 	unsigned int handleRequest(
+		const InetAddress &fromAddress,
 		unsigned int httpMethod,
 		unsigned int httpMethod,
 		const std::string &path,
 		const std::string &path,
 		const std::map<std::string,std::string> &headers,
 		const std::map<std::string,std::string> &headers,

+ 7 - 11
service/One.cpp

@@ -189,7 +189,7 @@ public:
 			if (_master)
 			if (_master)
 				_node->setNetconfMaster((void *)_master);
 				_node->setNetconfMaster((void *)_master);
 
 
-			_controlPlane = new ControlPlane(_node,std::set<std::string>());
+			_controlPlane = new ControlPlane(_node);
 
 
 			_nextBackgroundTaskDeadline = 0;
 			_nextBackgroundTaskDeadline = 0;
 			for(;;) {
 			for(;;) {
@@ -454,16 +454,12 @@ public:
 		std::string contentType("text/plain"); // default if not changed in handleRequest()
 		std::string contentType("text/plain"); // default if not changed in handleRequest()
 		unsigned int scode = 404;
 		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;
 		const char *scodestr;