summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--control/NodeControlClient.cpp67
-rw-r--r--control/NodeControlClient.hpp25
-rw-r--r--control/NodeControlService.cpp25
-rw-r--r--control/NodeControlService.hpp18
-rw-r--r--main.cpp49
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);
diff --git a/main.cpp b/main.cpp
index 67d4a808..e6fc1127 100644
--- a/main.cpp
+++ b/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;