More control/ refactoring

This commit is contained in:
Adam Ierymenko 2014-09-17 09:50:49 -07:00
parent e22fae2397
commit edff13dcae
5 changed files with 84 additions and 96 deletions

View file

@ -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() : throw() :
_impl((void *)new _NodeControlClientImpl) _impl((void *)new _NodeControlClientImpl)
{ {
_NodeControlClientImpl *impl = (_NodeControlClientImpl *)_impl; _NodeControlClientImpl *impl = (_NodeControlClientImpl *)_impl;
impl->ipcc = (IpcConnection *)0; impl->resultHandler = resultHandler;
impl->arg = arg;
if (!hp) try {
hp = ZT_DEFAULTS.defaultHomePath.c_str(); impl->ipcc = new IpcConnection(ep,&_CBipcResultHandler,_impl);
impl->ipcc->printf("auth %s"ZT_EOL_S,authToken);
std::string at; } catch ( ... ) {
if (authToken) impl->ipcc = (IpcConnection *)0;
at = authToken; impl->err = "failure connecting to running ZeroTier One service";
else if (!Utils::readFile(authTokenDefaultSystemPath(),at)) {
if (!Utils::readFile(authTokenDefaultUserPath(),at)) {
impl->err = "no authentication token specified and authtoken.secret not readable";
return;
}
} }
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() NodeControlClient::~NodeControlClient()
@ -153,17 +130,25 @@ const char *NodeControlClient::authTokenDefaultUserPath()
return dlp.c_str(); return dlp.c_str();
} }
const char *NodeControlClient::authTokenDefaultSystemPath() std::string NodeControlClient::getAuthToken(const char *path,bool generateIfNotFound)
{ {
static std::string dsp; unsigned char randbuf[24];
static Mutex dsp_m; std::string token;
Mutex::Lock _l(dsp_m); if (Utils::readFile(path,token))
return Utils::trim(token);
else token = "";
if (!dsp.length()) if (generateIfNotFound) {
dsp = (ZT_DEFAULTS.defaultHomePath + ZT_PATH_SEPARATOR_S"authtoken.secret"); 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 } // namespace ZeroTier

View file

@ -31,14 +31,16 @@
#include <string> #include <string>
#include <vector> #include <vector>
#ifdef __WINDOWS__
#define ZT_IPC_ENDPOINT_BASE "\\\\.\\pipe\\ZeroTierOne-"
#else
#define ZT_IPC_ENDPOINT_BASE "/tmp/.ZeroTierOne-"
#endif
namespace ZeroTier { namespace ZeroTier {
/** /**
* Client for controlling a local ZeroTier One node * 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 class NodeControlClient
{ {
@ -48,12 +50,11 @@ public:
* *
* Initialization may fail. Call error() to check. * 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 resultHandler Function to call when commands provide results
* @param arg First argument to result handler * @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(); throw();
~NodeControlClient(); ~NodeControlClient();
@ -89,14 +90,18 @@ public:
static inline std::vector<std::string> splitLine(const std::string &line) { return splitLine(line.c_str()); } 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(); 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: private:
// NodeControlClient is not copyable // NodeControlClient is not copyable

View file

@ -29,7 +29,9 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include "../node/Constants.hpp"
#include "NodeControlService.hpp" #include "NodeControlService.hpp"
#include "NodeControlClient.hpp"
#include "../node/Node.hpp" #include "../node/Node.hpp"
#include "../node/Utils.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 terminate [<reason>]"ZT_EOL_S);
ipcc->printf("200 help updatecheck"ZT_EOL_S); ipcc->printf("200 help updatecheck"ZT_EOL_S);
} else if (cmd[0] == "auth") { } 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); Mutex::Lock _l(_connections_m);
_connections[ipcc] = true; _connections[ipcc] = true;
ipcc->printf("200 auth OK"ZT_EOL_S); 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 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 } // namespace ZeroTier

View file

@ -38,12 +38,6 @@
#include "../node/NonCopyable.hpp" #include "../node/NonCopyable.hpp"
#include "../node/Thread.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 { namespace ZeroTier {
class Node; class Node;
@ -65,19 +59,11 @@ public:
~NodeControlService(); ~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() void threadMain()
throw(); 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: private:
static void _CBcommandHandler(void *arg,IpcConnection *ipcc,IpcConnection::EventType event,const char *commandLine); static void _CBcommandHandler(void *arg,IpcConnection *ipcc,IpcConnection::EventType event,const char *commandLine);
void _doCommand(IpcConnection *ipcc,const char *commandLine); void _doCommand(IpcConnection *ipcc,const char *commandLine);

View file

@ -114,9 +114,10 @@ static void printHelp(FILE *out,const char *cn)
static void _CBresultHandler(void *arg,const char *line) static void _CBresultHandler(void *arg,const char *line)
{ {
if (line) { if (line) {
if ((line[0] == '.')&&(line[1] == (char)0)) if ((line[0] == '.')&&(line[1] == (char)0)) {
fflush(stdout);
*((bool *)arg) = true; *((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; return 1;
} }
if (!homeDir)
homeDir = ZT_DEFAULTS.defaultHomePath.c_str();
try { 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; 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(); const char *err = client.error();
if (err) { if (err) {
fprintf(stderr,"%s: fatal error: unable to connect (is ZeroTier One running?) (%s)"ZT_EOL_S,argv[0],err); fprintf(stderr,"%s: fatal error: unable to connect (is ZeroTier One running?) (%s)"ZT_EOL_S,argv[0],err);
return 1; return 1;
} }
client.send(query.c_str()); client.send(query.c_str());
while (!done) while (!done) Thread::sleep(100); // dis be ghetto
Thread::sleep(100); // 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 ( ... ) { } 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; return 1;
} }
@ -758,12 +783,19 @@ int main(int argc,char **argv)
bool needsReset = false; bool needsReset = false;
EthernetTapFactory *tapFactory = (EthernetTapFactory *)0; EthernetTapFactory *tapFactory = (EthernetTapFactory *)0;
RoutingTable *routingTable = (RoutingTable *)0; RoutingTable *routingTable = (RoutingTable *)0;
NodeControlService *controlService = (NodeControlService *)0;
try { 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; tapFactory = ZTCreatePlatformEthernetTapFactory;
routingTable = ZTCreatePlatformRoutingTable; routingTable = ZTCreatePlatformRoutingTable;
node = new Node(homeDir,tapFactory,routingTable,udpPort,tcpPort,needsReset); node = new Node(homeDir,tapFactory,routingTable,udpPort,tcpPort,needsReset);
controlService = new NodeControlService(node,authToken.c_str());
switch(node->run()) { switch(node->run()) {
#ifdef __WINDOWS__ #ifdef __WINDOWS__
@ -807,9 +839,6 @@ int main(int argc,char **argv)
default: default:
break; break;
} }
delete node;
node = (Node *)0;
} catch ( std::exception &exc ) { } catch ( std::exception &exc ) {
fprintf(stderr,"%s: unexpected exception: %s"ZT_EOL_S,argv[0],exc.what()); fprintf(stderr,"%s: unexpected exception: %s"ZT_EOL_S,argv[0],exc.what());
exitCode = 3; exitCode = 3;
@ -818,6 +847,8 @@ int main(int argc,char **argv)
exitCode = 3; exitCode = 3;
} }
delete controlService;
delete node; node = (Node *)0;
delete routingTable; delete routingTable;
delete tapFactory; delete tapFactory;