mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-19 21:17:52 +00:00
More cleanup, and fix for the extremely unlikely case of identity collision.
This commit is contained in:
parent
f7b1437154
commit
ea1859541c
@ -9,13 +9,11 @@ The standard implementation uses SQLite3 with the attached schema. A separate se
|
||||
|
||||
By default this code is not built or included in the client. To build on Linux, BSD, or Mac add ZT_ENABLE_NETCONF_MASTER=1 to the make command line. It could be built on Windows as well, but you're on your own there. You'd have to build SQLite3 first, or get a pre-built copy somewhere.
|
||||
|
||||
### Running
|
||||
### Createing databases
|
||||
|
||||
To enable netconf functionality, place a properly initialized SQLite3 database called **netconf.db** into the ZeroTier working directory of the node you wish to serve network configurations and restart it. If that file is present it will be opened and the network configuration master function will be enabled. You will see this in the log file.
|
||||
If you execute a network controller enabled build of the ZeroTier One service, a *controller.db* will automatically be created and initialize. You can also create one manually with:
|
||||
|
||||
To initialize a database run:
|
||||
|
||||
sqlite3 -init netconf-schema.sql netconf.db
|
||||
sqlite3 -init schema.sql controller.db
|
||||
|
||||
Then type '.quit' to exit the SQLite3 command shell.
|
||||
|
||||
|
@ -53,14 +53,10 @@
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
SqliteNetworkController::SqliteNetworkController(const Identity &signingId,const char *dbPath) :
|
||||
_signingId(signingId),
|
||||
SqliteNetworkController::SqliteNetworkController(const char *dbPath) :
|
||||
_dbPath(dbPath),
|
||||
_db((sqlite3 *)0)
|
||||
{
|
||||
if (!_signingId.hasPrivate())
|
||||
throw std::runtime_error("SqliteNetworkController signing identity must have a private key");
|
||||
|
||||
if (sqlite3_open_v2(dbPath,&_db,SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE,(const char *)0) != SQLITE_OK)
|
||||
throw std::runtime_error("SqliteNetworkController cannot open database file");
|
||||
sqlite3_busy_timeout(_db,10000);
|
||||
@ -137,13 +133,18 @@ SqliteNetworkController::~SqliteNetworkController()
|
||||
}
|
||||
}
|
||||
|
||||
NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(const InetAddress &fromAddr,const Identity &identity,uint64_t nwid,const Dictionary &metaData,uint64_t haveRevision,Dictionary &netconf)
|
||||
NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(const InetAddress &fromAddr,const Identity &signingId,const Identity &identity,uint64_t nwid,const Dictionary &metaData,uint64_t haveRevision,Dictionary &netconf)
|
||||
{
|
||||
Mutex::Lock _l(_lock);
|
||||
|
||||
// Note: we can't reuse prepared statements that return const char * pointers without
|
||||
// making our own copy in e.g. a std::string first.
|
||||
|
||||
if ((!signingId)||(!signingId.hasPrivate())) {
|
||||
netconf["error"] = "signing identity invalid or lacks private key";
|
||||
return NetworkController::NETCONF_QUERY_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
||||
struct {
|
||||
char id[24];
|
||||
const char *name;
|
||||
@ -449,7 +450,7 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
|
||||
|
||||
if (network.isPrivate) {
|
||||
CertificateOfMembership com(network.revision,16,nwid,identity.address());
|
||||
if (com.sign(_signingId)) // basically can't fail unless our identity is invalid
|
||||
if (com.sign(signingId)) // basically can't fail unless our identity is invalid
|
||||
netconf[ZT_NETWORKCONFIG_DICT_KEY_CERTIFICATE_OF_MEMBERSHIP] = com.toString();
|
||||
else {
|
||||
netconf["error"] = "unable to sign COM";
|
||||
@ -457,7 +458,7 @@ NetworkController::ResultCode SqliteNetworkController::doNetworkConfigRequest(co
|
||||
}
|
||||
}
|
||||
|
||||
if (!netconf.sign(_signingId)) {
|
||||
if (!netconf.sign(signingId)) {
|
||||
netconf["error"] = "unable to sign netconf dictionary";
|
||||
return NETCONF_QUERY_INTERNAL_SERVER_ERROR;
|
||||
}
|
||||
|
@ -49,11 +49,12 @@ public:
|
||||
class DBC;
|
||||
friend class SqliteNetworkController::DBC;
|
||||
|
||||
SqliteNetworkController(const Identity &signingId,const char *dbPath);
|
||||
SqliteNetworkController(const char *dbPath);
|
||||
virtual ~SqliteNetworkController();
|
||||
|
||||
virtual NetworkController::ResultCode doNetworkConfigRequest(
|
||||
const InetAddress &fromAddr,
|
||||
const Identity &signingId,
|
||||
const Identity &identity,
|
||||
uint64_t nwid,
|
||||
const Dictionary &metaData,
|
||||
@ -61,7 +62,6 @@ public:
|
||||
Dictionary &netconf);
|
||||
|
||||
private:
|
||||
Identity _signingId;
|
||||
std::string _dbPath;
|
||||
sqlite3 *_db;
|
||||
|
||||
|
@ -674,7 +674,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,cons
|
||||
|
||||
if (RR->localNetworkController) {
|
||||
Dictionary netconf;
|
||||
switch(RR->localNetworkController->doNetworkConfigRequest((h > 0) ? InetAddress() : _remoteAddress,peer->identity(),nwid,metaData,haveRevision,netconf)) {
|
||||
switch(RR->localNetworkController->doNetworkConfigRequest((h > 0) ? InetAddress() : _remoteAddress,RR->identity,peer->identity(),nwid,metaData,haveRevision,netconf)) {
|
||||
case NetworkController::NETCONF_QUERY_OK: {
|
||||
const std::string netconfStr(netconf.toString());
|
||||
if (netconfStr.length() > 0xffff) { // sanity check since field ix 16-bit
|
||||
|
@ -250,7 +250,7 @@ void Network::requestConfiguration()
|
||||
if (RR->localNetworkController) {
|
||||
SharedPtr<NetworkConfig> nconf(config2());
|
||||
Dictionary newconf;
|
||||
switch(RR->localNetworkController->doNetworkConfigRequest(InetAddress(),RR->identity,_id,Dictionary(),(nconf) ? nconf->revision() : (uint64_t)0,newconf)) {
|
||||
switch(RR->localNetworkController->doNetworkConfigRequest(InetAddress(),RR->identity,RR->identity,_id,Dictionary(),(nconf) ? nconf->revision() : (uint64_t)0,newconf)) {
|
||||
case NetworkController::NETCONF_QUERY_OK:
|
||||
this->setConfiguration(newconf,true);
|
||||
return;
|
||||
|
@ -71,6 +71,7 @@ public:
|
||||
* to indicate the error.
|
||||
*
|
||||
* @param fromAddr Originating wire address or null address if packet is not direct (or from self)
|
||||
* @param signingId Identity that should be used to sign results -- must include private key
|
||||
* @param identity Originating peer ZeroTier identity
|
||||
* @param nwid 64-bit network ID
|
||||
* @param metaData Meta-data bundled with request (empty if none)
|
||||
@ -80,6 +81,7 @@ public:
|
||||
*/
|
||||
virtual NetworkController::ResultCode doNetworkConfigRequest(
|
||||
const InetAddress &fromAddr,
|
||||
const Identity &signingId,
|
||||
const Identity &identity,
|
||||
uint64_t nwid,
|
||||
const Dictionary &metaData,
|
||||
|
96
one.cpp
96
one.cpp
@ -69,10 +69,11 @@
|
||||
|
||||
#define ZT1_AUTHTOKEN_SECRET_PATH "authtoken.secret"
|
||||
#define ZT1_PID_PATH "zerotier-one.pid"
|
||||
#define ZT1_CONTROLLER_DB_PATH "controller.db"
|
||||
|
||||
using namespace ZeroTier;
|
||||
|
||||
static OneService *zt1Service = (OneService *)0;
|
||||
static OneService *volatile zt1Service = (OneService *)0;
|
||||
|
||||
/****************************************************************************/
|
||||
/* zerotier-cli personality */
|
||||
@ -437,29 +438,11 @@ static void printHelp(const char *cn,FILE *out)
|
||||
{
|
||||
fprintf(out,"ZeroTier One version %d.%d.%d"ZT_EOL_S"(c)2011-2015 ZeroTier, Inc."ZT_EOL_S,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION);
|
||||
fprintf(out,"Licensed under the GNU General Public License v3"ZT_EOL_S""ZT_EOL_S);
|
||||
|
||||
#ifdef ZT_AUTO_UPDATE
|
||||
fprintf(out,"Auto-update enabled build, will update from URL:"ZT_EOL_S);
|
||||
fprintf(out," %s"ZT_EOL_S,ZT_DEFAULTS.updateLatestNfoURL.c_str());
|
||||
fprintf(out,"Update authentication signing authorities: "ZT_EOL_S);
|
||||
int no = 0;
|
||||
for(std::map< Address,Identity >::const_iterator sa(ZT_DEFAULTS.updateAuthorities.begin());sa!=ZT_DEFAULTS.updateAuthorities.end();++sa) {
|
||||
if (no == 0)
|
||||
fprintf(out," %s",sa->first.toString().c_str());
|
||||
else fprintf(out,", %s",sa->first.toString().c_str());
|
||||
if (++no == 6) {
|
||||
fprintf(out,ZT_EOL_S);
|
||||
no = 0;
|
||||
}
|
||||
}
|
||||
fprintf(out,ZT_EOL_S""ZT_EOL_S);
|
||||
#endif // ZT_AUTO_UPDATE
|
||||
|
||||
fprintf(out,"Usage: %s [-switches] [home directory] [-q <query>]"ZT_EOL_S""ZT_EOL_S,cn);
|
||||
fprintf(out,"Available switches:"ZT_EOL_S);
|
||||
fprintf(out," -h - Display this help"ZT_EOL_S);
|
||||
fprintf(out," -v - Show version"ZT_EOL_S);
|
||||
fprintf(out," -p<port> - Port for UDP (default: 9993)"ZT_EOL_S);
|
||||
fprintf(out," -p<port> - Port for UDP and TCP/HTTP (default: 9993)"ZT_EOL_S);
|
||||
//fprintf(out," -T<path> - Override root topology, do not authenticate or update"ZT_EOL_S);
|
||||
#ifdef __UNIX_LIKE__
|
||||
fprintf(out," -d - Fork and run as daemon (Unix-ish OSes)"ZT_EOL_S);
|
||||
@ -643,8 +626,24 @@ int main(int argc,char **argv)
|
||||
|
||||
if (!homeDir.length())
|
||||
homeDir = OneService::platformDefaultHomePath();
|
||||
|
||||
OSUtils::mkdir(homeDir.c_str());
|
||||
if (!homeDir.length()) {
|
||||
fprintf(stderr,"%s: no home path specified and no platform default available"ZT_EOL_S,argv[0]);
|
||||
return 1;
|
||||
} else {
|
||||
std::vector<std::string> hpsp(Utils::split(homeDir.c_str(),ZT_PATH_SEPARATOR_S,"",""));
|
||||
std::string ptmp;
|
||||
if (homeDir[0] == ZT_PATH_SEPARATOR)
|
||||
ptmp.push_back(ZT_PATH_SEPARATOR);
|
||||
for(std::vector<std::string>::iterator pi(hpsp.begin());pi!=hpsp.end();++pi) {
|
||||
if (ptmp.length() > 0)
|
||||
ptmp.push_back(ZT_PATH_SEPARATOR);
|
||||
ptmp.append(*pi);
|
||||
if ((*pi != ".")&&(*pi != "..")) {
|
||||
if (!OSUtils::mkdir(ptmp))
|
||||
throw std::runtime_error("home path does not exist, and could not create");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string authToken;
|
||||
{
|
||||
@ -713,4 +712,57 @@ int main(int argc,char **argv)
|
||||
}
|
||||
#endif // __WINDOWS__
|
||||
|
||||
NetworkController *controller = (NetworkController *)0;
|
||||
#ifdef ZT_ENABLE_NETWORK_CONTROLLER
|
||||
try {
|
||||
controller = new SqliteNetworkController((homeDir + ZT_PATH_SEPARATOR_S + ZT1_CONTROLLER_DB_PATH).c_str());
|
||||
} catch (std::exception &exc) {
|
||||
fprintf(stderr,"%s: failure initializing SqliteNetworkController: %s"ZT_EOL_S,exc.what());
|
||||
return 1;
|
||||
} catch ( ... ) {
|
||||
fprintf(stderr,"%s: failure initializing SqliteNetworkController: unknown exception"ZT_EOL_S);
|
||||
return 1;
|
||||
}
|
||||
#endif // ZT_ENABLE_NETWORK_CONTROLLER
|
||||
|
||||
unsigned int returnValue = 0;
|
||||
|
||||
try {
|
||||
for(;;) {
|
||||
zt1Service = OneService::newInstance(homeDir.c_str(),port,controller,(overrideRootTopology.length() > 0) ? overrideRootTopology.c_str() : (const char *)0);
|
||||
switch(zt1Service->run()) {
|
||||
case OneService::ONE_STILL_RUNNING: // shouldn't happen, run() won't return until done
|
||||
case OneService::ONE_NORMAL_TERMINATION:
|
||||
break;
|
||||
case OneService::ONE_UNRECOVERABLE_ERROR:
|
||||
fprintf(stderr,"%s: fatal error: %s"ZT_EOL_S,argv[0],zt1Service->fatalErrorMessage().c_str());
|
||||
returnValue = 1;
|
||||
break;
|
||||
case OneService::ONE_IDENTITY_COLLISION: {
|
||||
delete zt1Service;
|
||||
zt1Service = (OneService *)0;
|
||||
std::string oldid;
|
||||
OSUtils::readFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str(),oldid);
|
||||
if (oldid.length()) {
|
||||
OSUtils::writeFile((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret.saved_after_collision").c_str(),oldid);
|
||||
OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.secret").c_str());
|
||||
OSUtils::rm((homeDir + ZT_PATH_SEPARATOR_S + "identity.public").c_str());
|
||||
}
|
||||
} continue; // restart!
|
||||
}
|
||||
break; // terminate loop -- normally we don't keep restarting
|
||||
}
|
||||
} catch (std::exception &exc) {
|
||||
fprintf(stderr,"%s: fatal error: %s"ZT_EOL_S,argv[0],exc.what());
|
||||
returnValue = 1;
|
||||
} catch ( ... ) {
|
||||
fprintf(stderr,"%s: fatal error: unknown exception"ZT_EOL_S,argv[0]);
|
||||
returnValue = 1;
|
||||
}
|
||||
|
||||
delete zt1Service;
|
||||
zt1Service = (OneService *)0;
|
||||
delete controller;
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
|
@ -143,22 +143,6 @@ public:
|
||||
struct sockaddr_in in4;
|
||||
struct sockaddr_in6 in6;
|
||||
|
||||
if (*hp) {
|
||||
std::vector<std::string> hpsp(Utils::split(hp,ZT_PATH_SEPARATOR_S,"",""));
|
||||
std::string ptmp;
|
||||
if (*hp == '/')
|
||||
ptmp.push_back('/');
|
||||
for(std::vector<std::string>::iterator pi(hpsp.begin());pi!=hpsp.end();++pi) {
|
||||
if (ptmp.length() > 0)
|
||||
ptmp.push_back(ZT_PATH_SEPARATOR);
|
||||
ptmp.append(*pi);
|
||||
if ((*pi != ".")&&(*pi != "..")) {
|
||||
if (!OSUtils::mkdir(ptmp))
|
||||
throw std::runtime_error("home path does not exist, and could not create");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
::memset((void *)&in4,0,sizeof(in4));
|
||||
in4.sin_family = AF_INET;
|
||||
in4.sin_port = Utils::hton((uint16_t)port);
|
||||
|
@ -32,7 +32,7 @@
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class NetworkConfigMaster;
|
||||
class NetworkController;
|
||||
|
||||
/**
|
||||
* Local service for ZeroTier One as system VPN/NFV provider
|
||||
@ -85,7 +85,7 @@ public:
|
||||
static OneService *newInstance(
|
||||
const char *hp,
|
||||
unsigned int port,
|
||||
NetworkConfigMaster *master = (NetworkConfigMaster *)0,
|
||||
NetworkController *master = (NetworkController *)0,
|
||||
const char *overrideRootTopology = (const char *)0);
|
||||
|
||||
virtual ~OneService();
|
||||
|
Loading…
Reference in New Issue
Block a user