diff options
-rw-r--r-- | control/NodeControlClient.cpp | 67 | ||||
-rw-r--r-- | control/NodeControlClient.hpp | 25 | ||||
-rw-r--r-- | control/NodeControlService.cpp | 25 | ||||
-rw-r--r-- | control/NodeControlService.hpp | 18 | ||||
-rw-r--r-- | main.cpp | 49 |
5 files changed, 86 insertions, 98 deletions
diff --git a/control/NodeControlClient.cpp b/control/NodeControlClient.cpp index 2281a8ad..df1a62b6 100644 --- a/control/NodeControlClient.cpp +++ b/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 diff --git a/control/NodeControlClient.hpp b/control/NodeControlClient.hpp index 37184f7b..8512ef7d 100644 --- a/control/NodeControlClient.hpp +++ b/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 diff --git a/control/NodeControlService.cpp b/control/NodeControlService.cpp index 536752cc..661c4c63 100644 --- a/control/NodeControlService.cpp +++ b/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 diff --git a/control/NodeControlService.hpp b/control/NodeControlService.hpp index 737878e0..782ff3b8 100644 --- a/control/NodeControlService.hpp +++ b/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); @@ -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; |