Răsfoiți Sursa

More control/ refactoring

Adam Ierymenko 11 ani în urmă
părinte
comite
edff13dcae

+ 26 - 41
control/NodeControlClient.cpp

@@ -51,43 +51,20 @@ static void _CBipcResultHandler(void *arg,IpcConnection *ipcc,IpcConnection::Eve
 	}
 }
 
-NodeControlClient::NodeControlClient(const char *hp,void (*resultHandler)(void *,const char *),void *arg,const char *authToken)
+NodeControlClient::NodeControlClient(const char *ep,const char *authToken,void (*resultHandler)(void *,const char *),void *arg)
 	throw() :
 	_impl((void *)new _NodeControlClientImpl)
 {
 	_NodeControlClientImpl *impl = (_NodeControlClientImpl *)_impl;
-	impl->ipcc = (IpcConnection *)0;
-
-	if (!hp)
-		hp = ZT_DEFAULTS.defaultHomePath.c_str();
-
-	std::string at;
-	if (authToken)
-		at = authToken;
-	else if (!Utils::readFile(authTokenDefaultSystemPath(),at)) {
-		if (!Utils::readFile(authTokenDefaultUserPath(),at)) {
-			impl->err = "no authentication token specified and authtoken.secret not readable";
-			return;
-		}
+	impl->resultHandler = resultHandler;
+	impl->arg = arg;
+	try {
+		impl->ipcc = new IpcConnection(ep,&_CBipcResultHandler,_impl);
+		impl->ipcc->printf("auth %s"ZT_EOL_S,authToken);
+	} catch ( ... ) {
+		impl->ipcc = (IpcConnection *)0;
+		impl->err = "failure connecting to running ZeroTier One service";
 	}
-
-	std::string myid;
-	if (Utils::readFile((std::string(hp) + ZT_PATH_SEPARATOR_S + "identity.public").c_str(),myid)) {
-		std::string myaddr(myid.substr(0,myid.find(':')));
-		if (myaddr.length() != 10)
-			impl->err = "invalid address extracted from identity.public";
-		else {
-			try {
-				impl->resultHandler = resultHandler;
-				impl->arg = arg;
-				impl->ipcc = new IpcConnection((std::string(ZT_IPC_ENDPOINT_BASE) + myaddr).c_str(),&_CBipcResultHandler,_impl);
-				impl->ipcc->printf("auth %s"ZT_EOL_S,at.c_str());
-			} catch ( ... ) {
-				impl->ipcc = (IpcConnection *)0;
-				impl->err = "failure connecting to running ZeroTier One service";
-			}
-		}
-	} else impl->err = "unable to read identity.public";
 }
 
 NodeControlClient::~NodeControlClient()
@@ -153,17 +130,25 @@ const char *NodeControlClient::authTokenDefaultUserPath()
 	return dlp.c_str();
 }
 
-const char *NodeControlClient::authTokenDefaultSystemPath()
+std::string NodeControlClient::getAuthToken(const char *path,bool generateIfNotFound)
 {
-	static std::string dsp;
-	static Mutex dsp_m;
-
-	Mutex::Lock _l(dsp_m);
-
-	if (!dsp.length())
-		dsp = (ZT_DEFAULTS.defaultHomePath + ZT_PATH_SEPARATOR_S"authtoken.secret");
+	unsigned char randbuf[24];
+	std::string token;
+
+	if (Utils::readFile(path,token))
+		return Utils::trim(token);
+	else token = "";
+
+	if (generateIfNotFound) {
+		Utils::getSecureRandom(randbuf,sizeof(randbuf));
+		for(unsigned int i=0;i<sizeof(randbuf);++i)
+			token.push_back(("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")[(unsigned int)randbuf[i] % 62]);
+		if (!Utils::writeFile(path,token))
+			return std::string();
+		Utils::lockDownFile(path,false);
+	}
 
-	return dsp.c_str();
+	return token;
 }
 
 } // namespace ZeroTier

+ 15 - 10
control/NodeControlClient.hpp

@@ -31,14 +31,16 @@
 #include <string>
 #include <vector>
 
+#ifdef __WINDOWS__
+#define ZT_IPC_ENDPOINT_BASE "\\\\.\\pipe\\ZeroTierOne-"
+#else
+#define ZT_IPC_ENDPOINT_BASE "/tmp/.ZeroTierOne-"
+#endif
+
 namespace ZeroTier {
 
 /**
  * Client for controlling a local ZeroTier One node
- *
- * Windows note: be sure you call WSAStartup() before using this,
- * otherwise it will be unable to open a local UDP socket to
- * communicate with the service.
  */
 class NodeControlClient
 {
@@ -48,12 +50,11 @@ public:
 	 *
 	 * Initialization may fail. Call error() to check.
 	 *
-	 * @param hp Home path of ZeroTier One instance or NULL for default system home path
+	 * @param ep Endpoint to connect to (OS-dependent)
 	 * @param resultHandler Function to call when commands provide results
 	 * @param arg First argument to result handler
-	 * @param authToken Authentication token or NULL (default) to read from authtoken.secret in home path
 	 */
-	NodeControlClient(const char *hp,void (*resultHandler)(void *,const char *),void *arg,const char *authToken = (const char *)0)
+	NodeControlClient(const char *ep,const char *authToken,void (*resultHandler)(void *,const char *),void *arg)
 		throw();
 
 	~NodeControlClient();
@@ -89,14 +90,18 @@ public:
 	static inline std::vector<std::string> splitLine(const std::string &line) { return splitLine(line.c_str()); }
 
 	/**
-	 * @return Default path for current user's authtoken.secret
+	 * @return Default path for current user's authtoken.secret or ~/.zeroTierOneAuthToken (location is platform-dependent)
 	 */
 	static const char *authTokenDefaultUserPath();
 
 	/**
-	 * @return Default path to system authtoken.secret
+	 * Load (or generate) the authentication token
+	 *
+	 * @param path Full path to authtoken.secret
+	 * @param generateIfNotFound If true, generate and save if not found or readable (requires appropriate privileges, returns empty on failure)
+	 * @return Authentication token or empty string on failure
 	 */
-	static const char *authTokenDefaultSystemPath();
+	static std::string getAuthToken(const char *path,bool generateIfNotFound);
 
 private:
 	// NodeControlClient is not copyable

+ 3 - 22
control/NodeControlService.cpp

@@ -29,7 +29,9 @@
 #include <string.h>
 #include <stdlib.h>
 
+#include "../node/Constants.hpp"
 #include "NodeControlService.hpp"
+#include "NodeControlClient.hpp"
 #include "../node/Node.hpp"
 #include "../node/Utils.hpp"
 
@@ -114,7 +116,7 @@ void NodeControlService::_doCommand(IpcConnection *ipcc,const char *commandLine)
 		ipcc->printf("200 help terminate [<reason>]"ZT_EOL_S);
 		ipcc->printf("200 help updatecheck"ZT_EOL_S);
 	} else if (cmd[0] == "auth") {
-		if ((cmd.size() > 1)&&(_authToken == cmd[1])) {
+		if ((cmd.size() > 1)&&(_authToken.length() > 0)&&(_authToken == cmd[1])) {
 			Mutex::Lock _l(_connections_m);
 			_connections[ipcc] = true;
 			ipcc->printf("200 auth OK"ZT_EOL_S);
@@ -226,25 +228,4 @@ void NodeControlService::_doCommand(IpcConnection *ipcc,const char *commandLine)
 	ipcc->printf("."ZT_EOL_S); // blank line ends response
 }
 
-std::string NodeControlService::readOrCreateAuthtoken(const char *path,bool generateIfNotFound)
-{
-	unsigned char randbuf[24];
-	std::string token;
-
-	if (Utils::readFile(path,token))
-		return token;
-	else token = "";
-
-	if (generateIfNotFound) {
-		Utils::getSecureRandom(randbuf,sizeof(randbuf));
-		for(unsigned int i=0;i<sizeof(randbuf);++i)
-			token.push_back(("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789")[(unsigned int)randbuf[i] % 62]);
-		if (!Utils::writeFile(path,token))
-			return std::string();
-		Utils::lockDownFile(path,false);
-	}
-
-	return token;
-}
-
 } // namespace ZeroTier

+ 2 - 16
control/NodeControlService.hpp

@@ -38,12 +38,6 @@
 #include "../node/NonCopyable.hpp"
 #include "../node/Thread.hpp"
 
-#ifdef __WINDOWS__
-#define ZT_IPC_ENDPOINT_BASE "\\\\.\\pipe\\ZeroTierOne-"
-#else
-#define ZT_IPC_ENDPOINT_BASE "/tmp/.ZeroTierOne-"
-#endif
-
 namespace ZeroTier {
 
 class Node;
@@ -65,19 +59,11 @@ public:
 
 	~NodeControlService();
 
-	// Background thread waits for node to initialize, then creates IpcListener
+	// Background thread waits for node to initialize, then creates IpcListener and
+	// terminates. It also terminates on delete if it hasn't bootstrapped yet.
 	void threadMain()
 		throw();
 
-	/**
-	 * Load (or generate) the authentication token
-	 *
-	 * @param path Full path to authtoken.secret
-	 * @param generateIfNotFound If true, generate and save if not found or readable
-	 * @return Authentication token or empty string on failure
-	 */
-	static std::string readOrCreateAuthtoken(const char *path,bool generateIfNotFound);
-
 private:
 	static void _CBcommandHandler(void *arg,IpcConnection *ipcc,IpcConnection::EventType event,const char *commandLine);
 	void _doCommand(IpcConnection *ipcc,const char *commandLine);

+ 40 - 9
main.cpp

@@ -114,9 +114,10 @@ static void printHelp(FILE *out,const char *cn)
 static void _CBresultHandler(void *arg,const char *line)
 {
 	if (line) {
-		if ((line[0] == '.')&&(line[1] == (char)0))
+		if ((line[0] == '.')&&(line[1] == (char)0)) {
+			fflush(stdout);
 			*((bool *)arg) = true;
-		else fprintf(stdout,"%s"ZT_EOL_S,line);
+		} else fprintf(stdout,"%s"ZT_EOL_S,line);
 	}
 }
 
@@ -153,19 +154,43 @@ static int main(const char *homeDir,int argc,char **argv)
 		return 1;
 	}
 
+	if (!homeDir)
+		homeDir = ZT_DEFAULTS.defaultHomePath.c_str();
+
 	try {
+		std::string buf;
+		if (!Utils::readFile((std::string(homeDir) + ZT_PATH_SEPARATOR_S + "identity.public").c_str(),buf)) {
+			fprintf(stderr,"%s: fatal error: unable to read node address from identity.public in home path"ZT_EOL_S,argv[0]);
+			return 1;
+		}
+		Identity id;
+		if (!id.fromString(buf)) {
+			fprintf(stderr,"%s: fatal error: unable to read node address from identity.public in home path"ZT_EOL_S,argv[0]);
+			return 1;
+		}
+
+		std::string authToken(NodeControlClient::getAuthToken((std::string(homeDir) + ZT_PATH_SEPARATOR_S + "authtoken.secret").c_str(),false));
+		if (!authToken.length())
+			authToken = NodeControlClient::getAuthToken(NodeControlClient::authTokenDefaultUserPath(),false);
+		if (!authToken.length()) {
+			fprintf(stderr,"%s: fatal error: unable to read authentication token from home path or user home"ZT_EOL_S,argv[0]);
+			return 1;
+		}
+
 		volatile bool done = false;
-		NodeControlClient client(homeDir,&_CBresultHandler,(void *)&done);
+		NodeControlClient client((std::string(ZT_IPC_ENDPOINT_BASE) + id.address().toString()).c_str(),authToken.c_str(),&_CBresultHandler,(void *)&done);
 		const char *err = client.error();
 		if (err) {
 			fprintf(stderr,"%s: fatal error: unable to connect (is ZeroTier One running?) (%s)"ZT_EOL_S,argv[0],err);
 			return 1;
 		}
 		client.send(query.c_str());
-		while (!done)
-			Thread::sleep(100); // ghetto
+		while (!done) Thread::sleep(100); // dis be ghetto
+	} catch (std::exception &exc) {
+		fprintf(stderr,"%s: fatal error: unable to connect (is ZeroTier One running?) (%s)"ZT_EOL_S,argv[0],exc.what());
+		return 1;
 	} catch ( ... ) {
-		fprintf(stderr,"%s: fatal error: unable to connect (is ZeroTier One running?)"ZT_EOL_S,argv[0]);
+		fprintf(stderr,"%s: fatal error: unable to connect (is ZeroTier One running?) (unknown exception)"ZT_EOL_S,argv[0]);
 		return 1;
 	}
 
@@ -758,12 +783,19 @@ int main(int argc,char **argv)
 	bool needsReset = false;
 	EthernetTapFactory *tapFactory = (EthernetTapFactory *)0;
 	RoutingTable *routingTable = (RoutingTable *)0;
+	NodeControlService *controlService = (NodeControlService *)0;
 
 	try {
+		// Get or create authtoken.secret -- note that if this fails, authentication
+		// will always fail since an empty auth token won't work. This should always
+		// succeed unless something is wrong with the filesystem.
+		std::string authToken(NodeControlClient::getAuthToken((std::string(homeDir) + ZT_PATH_SEPARATOR_S + "authtoken.secret").c_str(),true));
+
 		tapFactory = ZTCreatePlatformEthernetTapFactory;
 		routingTable = ZTCreatePlatformRoutingTable;
 
 		node = new Node(homeDir,tapFactory,routingTable,udpPort,tcpPort,needsReset);
+		controlService = new NodeControlService(node,authToken.c_str());
 
 		switch(node->run()) {
 #ifdef __WINDOWS__
@@ -807,9 +839,6 @@ int main(int argc,char **argv)
 			default:
 				break;
 		}
-
-		delete node;
-		node = (Node *)0;
 	} catch ( std::exception &exc ) {
 		fprintf(stderr,"%s: unexpected exception: %s"ZT_EOL_S,argv[0],exc.what());
 		exitCode = 3;
@@ -818,6 +847,8 @@ int main(int argc,char **argv)
 		exitCode = 3;
 	}
 
+	delete controlService;
+	delete node; node = (Node *)0;
 	delete routingTable;
 	delete tapFactory;