summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorGrant Limberg <glimberg@gmail.com>2015-05-21 19:14:49 -0700
committerGrant Limberg <glimberg@gmail.com>2015-05-21 19:14:49 -0700
commitc430d88bd40d178685ac0a2e648d8c4ea675996c (patch)
treef69f497428fa34c6389173d39c889563dea9506c /service
parent9a00366b18bc2bdb3ddf4345edcc7a459eb5ed60 (diff)
parentd9006712f6ffc975d97097caf2d2b4264405b32c (diff)
downloadinfinitytier-c430d88bd40d178685ac0a2e648d8c4ea675996c.tar.gz
infinitytier-c430d88bd40d178685ac0a2e648d8c4ea675996c.zip
Merge branch 'adamierymenko-dev' into android-jni
Conflicts: .gitignore
Diffstat (limited to 'service')
-rw-r--r--service/ControlPlane.cpp32
-rw-r--r--service/ControlPlane.hpp28
-rw-r--r--service/OneService.cpp319
-rw-r--r--service/OneService.hpp18
-rw-r--r--service/README.md10
5 files changed, 355 insertions, 52 deletions
diff --git a/service/ControlPlane.cpp b/service/ControlPlane.cpp
index 1d9f9b4a..2e8290ed 100644
--- a/service/ControlPlane.cpp
+++ b/service/ControlPlane.cpp
@@ -33,7 +33,9 @@
#include "../ext/http-parser/http_parser.h"
+#ifdef ZT_ENABLE_NETWORK_CONTROLLER
#include "../controller/SqliteNetworkController.hpp"
+#endif
#include "../node/InetAddress.hpp"
#include "../node/Node.hpp"
@@ -245,6 +247,9 @@ static void _jsonAppend(unsigned int depth,std::string &buf,const ZT1_Peer *peer
ControlPlane::ControlPlane(OneService *svc,Node *n,const char *uiStaticPath) :
_svc(svc),
_node(n),
+#ifdef ZT_ENABLE_NETWORK_CONTROLLER
+ _controller((SqliteNetworkController *)0),
+#endif
_uiStaticPath((uiStaticPath) ? uiStaticPath : "")
{
}
@@ -445,10 +450,13 @@ unsigned int ControlPlane::handleRequest(
responseContentType = "text/plain";
scode = 200;
} else {
- std::map<std::string,SqliteNetworkController *>::const_iterator ss(_subsystems.find(ps[0]));
- if (ss != _subsystems.end())
- scode = ss->second->handleControlPlaneHttpGET(std::vector<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
+#ifdef ZT_ENABLE_NETWORK_CONTROLLER
+ if (_controller)
+ _controller->handleControlPlaneHttpGET(std::vector<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
else scode = 404;
+#else
+ scode = 404;
+#endif
}
} else scode = 401; // isAuth == false
@@ -478,10 +486,13 @@ unsigned int ControlPlane::handleRequest(
} else scode = 500;
}
} else {
- std::map<std::string,SqliteNetworkController *>::const_iterator ss(_subsystems.find(ps[0]));
- if (ss != _subsystems.end())
- scode = ss->second->handleControlPlaneHttpPOST(std::vector<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
+#ifdef ZT_ENABLE_NETWORK_CONTROLLER
+ if (_controller)
+ _controller->handleControlPlaneHttpPOST(std::vector<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
else scode = 404;
+#else
+ scode = 404;
+#endif
}
} else scode = 401; // isAuth == false
@@ -510,10 +521,13 @@ unsigned int ControlPlane::handleRequest(
_node->freeQueryResult((void *)nws);
} else scode = 500;
} else {
- std::map<std::string,SqliteNetworkController *>::const_iterator ss(_subsystems.find(ps[0]));
- if (ss != _subsystems.end())
- scode = ss->second->handleControlPlaneHttpDELETE(std::vector<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
+#ifdef ZT_ENABLE_NETWORK_CONTROLLER
+ if (_controller)
+ _controller->handleControlPlaneHttpDELETE(std::vector<std::string>(ps.begin()+1,ps.end()),urlArgs,headers,body,responseBody,responseContentType);
else scode = 404;
+#else
+ scode = 404;
+#endif
}
} else {
diff --git a/service/ControlPlane.hpp b/service/ControlPlane.hpp
index fc8a0182..75cd8cac 100644
--- a/service/ControlPlane.hpp
+++ b/service/ControlPlane.hpp
@@ -52,30 +52,26 @@ public:
ControlPlane(OneService *svc,Node *n,const char *uiStaticPath);
~ControlPlane();
+#ifdef ZT_ENABLE_NETWORK_CONTROLLER
/**
- * Add an authentication token for API access
+ * Set controller, which will be available under /controller
+ *
+ * @param c Network controller instance
*/
- inline void addAuthToken(const char *tok)
+ inline void setController(SqliteNetworkController *c)
{
Mutex::Lock _l(_lock);
- _authTokens.insert(std::string(tok));
+ _controller = c;
}
+#endif
/**
- * Mount a subsystem under a prefix
- *
- * Note that the prefix must not contain a dot -- this is reserved for
- * static pages -- and must not be a reserved prefix such as /peer
- * or /network. Do not include path / characters in the prefix. Example
- * would be 'controller' for SqliteNetworkController.
- *
- * @param prefix First element in URI path
- * @param subsys Object to call for results of GET and POST/PUT operations
+ * Add an authentication token for API access
*/
- inline void mount(const char *prefix,SqliteNetworkController *subsys)
+ inline void addAuthToken(const char *tok)
{
Mutex::Lock _l(_lock);
- _subsystems[std::string(prefix)] = subsys;
+ _authTokens.insert(std::string(tok));
}
/**
@@ -102,9 +98,11 @@ public:
private:
OneService *const _svc;
Node *const _node;
+#ifdef ZT_ENABLE_NETWORK_CONTROLLER
+ SqliteNetworkController *_controller;
+#endif
std::string _uiStaticPath;
std::set<std::string> _authTokens;
- std::map<std::string,SqliteNetworkController *> _subsystems;
Mutex _lock;
};
diff --git a/service/OneService.cpp b/service/OneService.cpp
index 13108aa1..3f45cd1e 100644
--- a/service/OneService.cpp
+++ b/service/OneService.cpp
@@ -28,6 +28,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdint.h>
#include <string>
#include <map>
@@ -46,15 +47,29 @@
#include "../node/Utils.hpp"
#include "../node/InetAddress.hpp"
#include "../node/MAC.hpp"
+#include "../node/Identity.hpp"
#include "../osdep/Phy.hpp"
+#include "../osdep/Thread.hpp"
#include "../osdep/OSUtils.hpp"
+#include "../osdep/Http.hpp"
+#include "../osdep/BackgroundResolver.hpp"
#include "OneService.hpp"
#include "ControlPlane.hpp"
+#ifdef ZT_ENABLE_NETWORK_CONTROLLER
+#include "../controller/SqliteNetworkController.hpp"
+#else
+class SqliteNetworkController;
+#endif // ZT_ENABLE_NETWORK_CONTROLLER
+
#ifdef __WINDOWS__
#include <ShlObj.h>
+#else
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
#endif
// Include the right tap device driver for this platform -- add new platforms here
@@ -85,15 +100,223 @@ namespace ZeroTier { typedef BSDEthernetTap EthernetTap; }
// How often to check for new multicast subscriptions on a tap device
#define ZT_TAP_CHECK_MULTICAST_INTERVAL 30000
+// Path under ZT1 home for controller database if controller is enabled
+#define ZT1_CONTROLLER_DB_PATH "controller.db"
+
+// TCP fallback relay host
+#define ZT1_TCP_FALLBACK_RELAY "tcp-fallback.zerotier.com"
+
+// Frequency at which we re-resolve the TCP fallback relay
+#define ZT1_TCP_FALLBACK_RERESOLVE_DELAY 86400000
+
namespace ZeroTier {
+namespace {
+
+#ifdef ZT_AUTO_UPDATE
+#define ZT_AUTO_UPDATE_MAX_HTTP_RESPONSE_SIZE (1024 * 1024 * 64)
+#define ZT_AUTO_UPDATE_CHECK_PERIOD 21600000
+class BackgroundSoftwareUpdateChecker
+{
+public:
+ bool isValidSigningIdentity(const Identity &id)
+ {
+ return (
+ /* 0005 */ (id == Identity("ba57ea350e:0:9d4be6d7f86c5660d5ee1951a3d759aa6e12a84fc0c0b74639500f1dbc1a8c566622e7d1c531967ebceb1e9d1761342f88324a8ba520c93c35f92f35080fa23f"))
+ /* 0006 */ ||(id == Identity("5067b21b83:0:8af477730f5055c48135b84bed6720a35bca4c0e34be4060a4c636288b1ec22217eb22709d610c66ed464c643130c51411bbb0294eef12fbe8ecc1a1e2c63a7a"))
+ /* 0007 */ ||(id == Identity("4f5e97a8f1:0:57880d056d7baeb04bbc057d6f16e6cb41388570e87f01492fce882485f65a798648595610a3ad49885604e7fb1db2dd3c2c534b75e42c3c0b110ad07b4bb138"))
+ /* 0008 */ ||(id == Identity("580bbb8e15:0:ad5ef31155bebc6bc413991992387e083fed26d699997ef76e7c947781edd47d1997161fa56ba337b1a2b44b129fd7c7197ce5185382f06011bc88d1363b4ddd"))
+ );
+ }
+
+ void doUpdateCheck()
+ {
+ std::string url(OneService::autoUpdateUrl());
+ if ((url.length() <= 7)||(url.substr(0,7) != "http://"))
+ return;
+
+ std::string httpHost;
+ std::string httpPath;
+ {
+ std::size_t slashIdx = url.substr(7).find_first_of('/');
+ if (slashIdx == std::string::npos) {
+ httpHost = url.substr(7);
+ httpPath = "/";
+ } else {
+ httpHost = url.substr(7,slashIdx);
+ httpPath = url.substr(slashIdx + 7);
+ }
+ }
+ if (httpHost.length() == 0)
+ return;
+
+ std::vector<InetAddress> ips(OSUtils::resolve(httpHost.c_str()));
+ for(std::vector<InetAddress>::iterator ip(ips.begin());ip!=ips.end();++ip) {
+ if (!ip->port())
+ ip->setPort(80);
+ std::string nfoPath = httpPath + "LATEST.nfo";
+ std::map<std::string,std::string> requestHeaders,responseHeaders;
+ std::string body;
+ requestHeaders["Host"] = httpHost;
+ unsigned int scode = Http::GET(ZT_AUTO_UPDATE_MAX_HTTP_RESPONSE_SIZE,60000,reinterpret_cast<const struct sockaddr *>(&(*ip)),nfoPath.c_str(),requestHeaders,responseHeaders,body);
+ //fprintf(stderr,"UPDATE %s %s %u %lu\n",ip->toString().c_str(),nfoPath.c_str(),scode,body.length());
+ if ((scode == 200)&&(body.length() > 0)) {
+ /* NFO fields:
+ *
+ * file=<filename>
+ * signedBy=<signing identity>
+ * ed25519=<ed25519 ECC signature of archive>
+ * vMajor=<major version>
+ * vMinor=<minor version>
+ * vRevision=<revision> */
+ Dictionary nfo(body);
+
+ unsigned int vMajor = Utils::strToUInt(nfo.get("vMajor","0").c_str());
+ unsigned int vMinor = Utils::strToUInt(nfo.get("vMinor","0").c_str());
+ unsigned int vRevision = Utils::strToUInt(nfo.get("vRevision","0").c_str());
+ if (Utils::compareVersion(vMajor,vMinor,vRevision,ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION) <= 0) {
+ //fprintf(stderr,"UPDATE %u.%u.%u is not newer than our version\n",vMajor,vMinor,vRevision);
+ return;
+ }
+
+ Identity signedBy;
+ if ((!signedBy.fromString(nfo.get("signedBy","")))||(!isValidSigningIdentity(signedBy))) {
+ //fprintf(stderr,"UPDATE invalid signedBy or not authorized signing identity.\n");
+ return;
+ }
+
+ std::string filePath(nfo.get("file",""));
+ if ((!filePath.length())||(filePath.find("..") != std::string::npos))
+ return;
+ filePath = httpPath + filePath;
+
+ std::string fileData;
+ if (Http::GET(ZT_AUTO_UPDATE_MAX_HTTP_RESPONSE_SIZE,60000,reinterpret_cast<const struct sockaddr *>(&(*ip)),filePath.c_str(),requestHeaders,responseHeaders,fileData) != 200) {
+ //fprintf(stderr,"UPDATE GET %s failed\n",filePath.c_str());
+ return;
+ }
+
+ std::string ed25519(nfo.get("ed25519",""));
+ if ((ed25519.length() == 0)||(!signedBy.verify(fileData.data(),(unsigned int)fileData.length(),ed25519.data(),(unsigned int)ed25519.length()))) {
+ //fprintf(stderr,"UPDATE %s failed signature check!\n",filePath.c_str());
+ return;
+ }
+
+ /* --------------------------------------------------------------- */
+ /* We made it! Begin OS-specific installation code. */
+
+#ifdef __APPLE__
+ /* OSX version is in the form of a MacOSX .pkg file, so we will
+ * launch installer (normally in /usr/sbin) to install it. It will
+ * then turn around and shut down the service, update files, and
+ * relaunch. */
+ {
+ char bashp[128],pkgp[128];
+ Utils::snprintf(bashp,sizeof(bashp),"/tmp/ZeroTierOne-update-%u.%u.%u.sh",vMajor,vMinor,vRevision);
+ Utils::snprintf(pkgp,sizeof(pkgp),"/tmp/ZeroTierOne-update-%u.%u.%u.pkg",vMajor,vMinor,vRevision);
+ FILE *pkg = fopen(pkgp,"w");
+ if ((!pkg)||(fwrite(fileData.data(),fileData.length(),1,pkg) != 1)) {
+ fclose(pkg);
+ unlink(bashp);
+ unlink(pkgp);
+ fprintf(stderr,"UPDATE error writing %s\n",pkgp);
+ return;
+ }
+ fclose(pkg);
+ FILE *bash = fopen(bashp,"w");
+ if (!bash) {
+ fclose(pkg);
+ unlink(bashp);
+ unlink(pkgp);
+ fprintf(stderr,"UPDATE error writing %s\n",bashp);
+ return;
+ }
+ fprintf(bash,
+ "#!/bin/bash\n"
+ "export PATH=/bin:/usr/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/sbin\n"
+ "sleep 2\n"
+ "installer -pkg \"%s\" -target /\n"
+ "sleep 1\n"
+ "rm -f \"%s\" \"%s\"\n"
+ "exit 0\n",
+ pkgp,
+ pkgp,
+ bashp);
+ fclose(bash);
+ long pid = (long)vfork();
+ if (pid == 0) {
+ execl("/bin/bash","/bin/bash",bashp,(char *)0);
+ exit(0);
+ }
+ }
+#endif // __APPLE__
+
+#ifdef __WINDOWS__
+ /* Windows version comes in the form of .MSI package that
+ * takes care of everything. */
+ {
+ char tempp[512],batp[512],msip[512],cmdline[512];
+ if (GetTempPathA(sizeof(tempp),tempp) <= 0)
+ return;
+ CreateDirectoryA(tempp,(LPSECURITY_ATTRIBUTES)0);
+ Utils::snprintf(batp,sizeof(batp),"%s\\ZeroTierOne-update-%u.%u.%u.bat",tempp,vMajor,vMinor,vRevision);
+ Utils::snprintf(msip,sizeof(msip),"%s\\ZeroTierOne-update-%u.%u.%u.msi",tempp,vMajor,vMinor,vRevision);
+ FILE *msi = fopen(msip,"wb");
+ if ((!msi)||(fwrite(fileData.data(),(size_t)fileData.length(),1,msi) != 1)) {
+ fclose(msi);
+ return;
+ }
+ fclose(msi);
+ FILE *bat = fopen(batp,"wb");
+ if (!bat)
+ return;
+ fprintf(bat,
+ "TIMEOUT.EXE /T 1 /NOBREAK\r\n"
+ "NET.EXE STOP \"ZeroTierOneService\"\r\n"
+ "TIMEOUT.EXE /T 1 /NOBREAK\r\n"
+ "MSIEXEC.EXE /i \"%s\" /qn\r\n"
+ "TIMEOUT.EXE /T 1 /NOBREAK\r\n"
+ "NET.EXE START \"ZeroTierOneService\"\r\n"
+ "DEL \"%s\"\r\n"
+ "DEL \"%s\"\r\n",
+ msip,
+ msip,
+ batp);
+ fclose(bat);
+ STARTUPINFOA si;
+ PROCESS_INFORMATION pi;
+ memset(&si,0,sizeof(si));
+ memset(&pi,0,sizeof(pi));
+ Utils::snprintf(cmdline,sizeof(cmdline),"CMD.EXE /c \"%s\"",batp);
+ CreateProcessA(NULL,cmdline,NULL,NULL,FALSE,CREATE_NO_WINDOW|CREATE_NEW_PROCESS_GROUP,NULL,NULL,&si,&pi);
+ }
+#endif // __WINDOWS__
+
+ /* --------------------------------------------------------------- */
+
+ return;
+ } // else try to fetch from next IP address
+ }
+ }
+
+ void threadMain()
+ throw()
+ {
+ try {
+ this->doUpdateCheck();
+ } catch ( ... ) {}
+ }
+};
+static BackgroundSoftwareUpdateChecker backgroundSoftwareUpdateChecker;
+#endif // ZT_AUTO_UPDATE
+
class OneServiceImpl;
static int SnodeVirtualNetworkConfigFunction(ZT1_Node *node,void *uptr,uint64_t nwid,enum ZT1_VirtualNetworkConfigOperation op,const ZT1_VirtualNetworkConfig *nwconf);
static void SnodeEventCallback(ZT1_Node *node,void *uptr,enum ZT1_Event event,const void *metaData);
static long SnodeDataStoreGetFunction(ZT1_Node *node,void *uptr,const char *name,void *buf,unsigned long bufSize,unsigned long readIndex,unsigned long *totalSize);
static int SnodeDataStorePutFunction(ZT1_Node *node,void *uptr,const char *name,const void *data,unsigned long len,int secure);
-static int SnodeWirePacketSendFunction(ZT1_Node *node,void *uptr,const struct sockaddr_storage *addr,unsigned int desperation,const void *data,unsigned int len);
+static int SnodeWirePacketSendFunction(ZT1_Node *node,void *uptr,const struct sockaddr_storage *addr,const void *data,unsigned int len);
static void SnodeVirtualNetworkFrameFunction(ZT1_Node *node,void *uptr,uint64_t nwid,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len);
static void StapFrameHandler(void *uptr,uint64_t nwid,const MAC &from,const MAC &to,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len);
@@ -147,10 +370,13 @@ struct TcpConnection
class OneServiceImpl : public OneService
{
public:
- OneServiceImpl(const char *hp,unsigned int port,NetworkController *master,const char *overrideRootTopology) :
+ OneServiceImpl(const char *hp,unsigned int port,const char *overrideRootTopology) :
_homePath((hp) ? hp : "."),
+ _tcpFallbackResolver(ZT1_TCP_FALLBACK_RELAY),
+#ifdef ZT_ENABLE_NETWORK_CONTROLLER
+ _controller((_homePath + ZT_PATH_SEPARATOR_S + ZT1_CONTROLLER_DB_PATH).c_str()),
+#endif
_phy(this,true),
- _master(master),
_overrideRootTopology((overrideRootTopology) ? overrideRootTopology : ""),
_node((Node *)0),
_controlPlane((ControlPlane *)0),
@@ -227,13 +453,16 @@ public:
SnodeEventCallback,
((_overrideRootTopology.length() > 0) ? _overrideRootTopology.c_str() : (const char *)0));
- if (_master)
- _node->setNetconfMaster((void *)_master);
+#ifdef ZT_ENABLE_NETWORK_CONTROLLER
+ _node->setNetconfMaster((void *)&_controller);
+#endif
_controlPlane = new ControlPlane(this,_node,(_homePath + ZT_PATH_SEPARATOR_S + "ui").c_str());
_controlPlane->addAuthToken(authToken.c_str());
- if (_master)
- _controlPlane->mount("controller",reinterpret_cast<SqliteNetworkController *>(_master));
+
+#ifdef ZT_ENABLE_NETWORK_CONTROLLER
+ _controlPlane->setController(&_controller);
+#endif
{ // Remember networks from previous session
std::vector<std::string> networksDotD(OSUtils::listDirectory((_homePath + ZT_PATH_SEPARATOR_S + "networks.d").c_str()));
@@ -246,6 +475,10 @@ public:
_nextBackgroundTaskDeadline = 0;
uint64_t lastTapMulticastGroupCheck = 0;
+ uint64_t lastTcpFallbackResolve = 0;
+#ifdef ZT_AUTO_UPDATE
+ uint64_t lastSoftwareUpdateCheck = 0;
+#endif // ZT_AUTO_UPDATE
for(;;) {
_run_m.lock();
if (!_run) {
@@ -263,6 +496,18 @@ public:
dl = _nextBackgroundTaskDeadline;
}
+#ifdef ZT_AUTO_UPDATE
+ if ((now - lastSoftwareUpdateCheck) >= ZT_AUTO_UPDATE_CHECK_PERIOD) {
+ lastSoftwareUpdateCheck = OSUtils::now();
+ Thread::start(&backgroundSoftwareUpdateChecker);
+ }
+#endif // ZT_AUTO_UPDATE
+
+ if ((now - lastTcpFallbackResolve) >= ZT1_TCP_FALLBACK_RERESOLVE_DELAY) {
+ lastTcpFallbackResolve = now;
+ _tcpFallbackResolver.resolveNow();
+ }
+
if ((now - lastTapMulticastGroupCheck) >= ZT_TAP_CHECK_MULTICAST_INTERVAL) {
lastTapMulticastGroupCheck = now;
Mutex::Lock _l(_taps_m);
@@ -345,7 +590,6 @@ public:
ZT1_ResultCode rc = _node->processWirePacket(
OSUtils::now(),
(const struct sockaddr_storage *)from, // Phy<> uses sockaddr_storage, so it'll always be that big
- 0, // desperation == 0, direct UDP
data,
len,
&_nextBackgroundTaskDeadline);
@@ -364,7 +608,8 @@ public:
if (!success)
return;
- // Outgoing connections are right now only tunnel connections
+ // Outgoing TCP connections are always TCP fallback tunnel connections.
+
TcpConnection *tc = &(_tcpConections[sock]);
tc->type = TcpConnection::TCP_TUNNEL_OUTGOING;
tc->shouldKeepAlive = true; // unused
@@ -392,7 +637,8 @@ public:
inline void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from)
{
- // Incoming connections are TCP HTTP requests
+ // Incoming TCP connections are HTTP JSON API requests.
+
TcpConnection *tc = &(_tcpConections[sockN]);
tc->type = TcpConnection::TCP_HTTP_INCOMING;
tc->shouldKeepAlive = true;
@@ -422,6 +668,7 @@ public:
{
TcpConnection *tc = reinterpret_cast<TcpConnection *>(*uptr);
switch(tc->type) {
+
case TcpConnection::TCP_HTTP_INCOMING:
case TcpConnection::TCP_HTTP_OUTGOING:
http_parser_execute(&(tc->parser),&HTTP_PARSER_SETTINGS,(const char *)data,len);
@@ -430,6 +677,7 @@ public:
return;
}
break;
+
case TcpConnection::TCP_TUNNEL_OUTGOING:
tc->body.append((const char *)data,len);
if (tc->body.length() > 65535) {
@@ -481,7 +729,6 @@ public:
ZT1_ResultCode rc = _node->processWirePacket(
OSUtils::now(),
(const struct sockaddr_storage *)&from, // Phy<> uses sockaddr_storage, so it'll always be that big
- 1, // desperation == 1, TCP tunnel proxy
data,
plen,
&_nextBackgroundTaskDeadline);
@@ -496,12 +743,14 @@ public:
return;
}
}
+
if (tc->body.length() > (mlen + 5))
tc->body = tc->body.substr(mlen + 5);
else tc->body = "";
}
}
break;
+
}
}
@@ -509,7 +758,7 @@ public:
{
TcpConnection *tc = reinterpret_cast<TcpConnection *>(*uptr);
if (tc->writeBuf.length()) {
- long sent = _phy.tcpSend(sock,tc->writeBuf.data(),tc->writeBuf.length(),true);
+ long sent = (long)_phy.tcpSend(sock,tc->writeBuf.data(),(unsigned long)tc->writeBuf.length(),true);
if (sent > 0) {
tc->lastActivity = OSUtils::now();
if ((unsigned long)sent == (unsigned long)tc->writeBuf.length()) {
@@ -598,9 +847,6 @@ public:
this->terminate();
} break;
- case ZT1_EVENT_SAW_MORE_RECENT_VERSION: {
- } break;
-
case ZT1_EVENT_TRACE: {
if (metaData) {
::fprintf(stderr,"%s"ZT_EOL_S,(const char *)metaData);
@@ -667,7 +913,7 @@ public:
}
}
- inline int nodeWirePacketSendFunction(const struct sockaddr_storage *addr,unsigned int desperation,const void *data,unsigned int len)
+ inline int nodeWirePacketSendFunction(const struct sockaddr_storage *addr,const void *data,unsigned int len)
{
switch(addr->ss_family) {
case AF_INET:
@@ -763,8 +1009,11 @@ private:
}
const std::string _homePath;
+ BackgroundResolver _tcpFallbackResolver;
+#ifdef ZT_ENABLE_NETWORK_CONTROLLER
+ SqliteNetworkController _controller;
+#endif
Phy<OneServiceImpl *> _phy;
- NetworkController *_master;
std::string _overrideRootTopology;
Node *_node;
PhySocket *_v4UdpSocket;
@@ -796,8 +1045,8 @@ static long SnodeDataStoreGetFunction(ZT1_Node *node,void *uptr,const char *name
{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeDataStoreGetFunction(name,buf,bufSize,readIndex,totalSize); }
static int SnodeDataStorePutFunction(ZT1_Node *node,void *uptr,const char *name,const void *data,unsigned long len,int secure)
{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeDataStorePutFunction(name,data,len,secure); }
-static int SnodeWirePacketSendFunction(ZT1_Node *node,void *uptr,const struct sockaddr_storage *addr,unsigned int desperation,const void *data,unsigned int len)
-{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeWirePacketSendFunction(addr,desperation,data,len); }
+static int SnodeWirePacketSendFunction(ZT1_Node *node,void *uptr,const struct sockaddr_storage *addr,const void *data,unsigned int len)
+{ return reinterpret_cast<OneServiceImpl *>(uptr)->nodeWirePacketSendFunction(addr,data,len); }
static void SnodeVirtualNetworkFrameFunction(ZT1_Node *node,void *uptr,uint64_t nwid,uint64_t sourceMac,uint64_t destMac,unsigned int etherType,unsigned int vlanId,const void *data,unsigned int len)
{ reinterpret_cast<OneServiceImpl *>(uptr)->nodeVirtualNetworkFrameFunction(nwid,sourceMac,destMac,etherType,vlanId,data,len); }
@@ -887,6 +1136,8 @@ static int ShttpOnMessageComplete(http_parser *parser)
return 0;
}
+} // anonymous namespace
+
std::string OneService::platformDefaultHomePath()
{
#ifdef __UNIX_LIKE__
@@ -896,8 +1147,8 @@ std::string OneService::platformDefaultHomePath()
return std::string("/Library/Application Support/ZeroTier/One");
#else
-#ifdef __FreeBSD__
- // FreeBSD likes /var/db instead of /var/lib
+#ifdef __BSD__
+ // BSD likes /var/db instead of /var/lib
return std::string("/var/db/zerotier-one");
#else
// Use /var/lib for Linux and other *nix
@@ -923,7 +1174,31 @@ std::string OneService::platformDefaultHomePath()
#endif // __UNIX_LIKE__ or not...
}
-OneService *OneService::newInstance(const char *hp,unsigned int port,NetworkController *master,const char *overrideRootTopology) { return new OneServiceImpl(hp,port,master,overrideRootTopology); }
+std::string OneService::autoUpdateUrl()
+{
+#ifdef ZT_AUTO_UPDATE
+
+/*
+#if defined(__LINUX__) && ( defined(__i386__) || defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(__i386) )
+ if (sizeof(void *) == 8)
+ return "http://download.zerotier.com/ZeroTierOneInstaller-linux-x64-LATEST.nfo";
+ else return "http://download.zerotier.com/ZeroTierOneInstaller-linux-x86-LATEST.nfo";
+#endif
+*/
+
+#if defined(__APPLE__) && ( defined(__i386__) || defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(__i386) )
+ return "http://download.zerotier.com/update/mac_intel/";
+#endif
+
+#ifdef __WINDOWS__
+ return "http://download.zerotier.com/update/win_intel/";
+#endif
+
+#endif // ZT_AUTO_UPDATE
+ return std::string();
+}
+
+OneService *OneService::newInstance(const char *hp,unsigned int port,const char *overrideRootTopology) { return new OneServiceImpl(hp,port,overrideRootTopology); }
OneService::~OneService() {}
} // namespace ZeroTier
diff --git a/service/OneService.hpp b/service/OneService.hpp
index 9df65179..aea314f5 100644
--- a/service/OneService.hpp
+++ b/service/OneService.hpp
@@ -32,10 +32,17 @@
namespace ZeroTier {
-class NetworkController;
-
/**
* Local service for ZeroTier One as system VPN/NFV provider
+ *
+ * If built with ZT_ENABLE_NETWORK_CONTROLLER defined, this includes and
+ * runs controller/SqliteNetworkController with a database called
+ * controller.db in the specified home directory.
+ *
+ * If built with ZT_AUTO_UPDATE, an official ZeroTier update URL is
+ * periodically checked and updates are automatically downloaded, verified
+ * against a built-in list of update signing keys, and installed. This is
+ * only supported for certain platforms.
*/
class OneService
{
@@ -72,6 +79,11 @@ public:
static std::string platformDefaultHomePath();
/**
+ * @return Auto-update URL or empty string if auto-updates unsupported or not enabled
+ */
+ static std::string autoUpdateUrl();
+
+ /**
* Create a new instance of the service
*
* Once created, you must call the run() method to actually start
@@ -79,13 +91,11 @@ public:
*
* @param hp Home path
* @param port TCP and UDP port for packets and HTTP control
- * @param master Instance of network config master if this instance is to act as one (default: NULL)
* @param overrideRootTopology String-serialized root topology (for testing, default: NULL)
*/
static OneService *newInstance(
const char *hp,
unsigned int port,
- NetworkController *master = (NetworkController *)0,
const char *overrideRootTopology = (const char *)0);
virtual ~OneService();
diff --git a/service/README.md b/service/README.md
index ecab6e75..1900a612 100644
--- a/service/README.md
+++ b/service/README.md
@@ -59,7 +59,7 @@ Getting /network returns an array of all networks that this node has joined. See
* Methods: GET, POST, DELETE
* Returns: { object }
-To join a network, POST to it. POST data is optional and may be omitted. Example: POST to /network/8056c2e21c000001 to join the public "Earth" network. To leave a network, DELETE it e.g. DELETE /network/8056c2e21c000001.
+To join a network, POST to it. Since networks have no mandatory writable parameters, POST data is optional and may be omitted. Example: POST to /network/8056c2e21c000001 to join the public "Earth" network. To leave a network, DELETE it e.g. DELETE /network/8056c2e21c000001.
Most network settings are not writable, as they are defined by the network controller.
@@ -151,7 +151,13 @@ This returns an array of 16-digit hexadecimal network IDs. Unlike /network under
* Methods: GET, POST, DELETE
* Returns: { object }
-DELETE for networks is final. Don't do this unless you really mean it!
+By making queries to this path you can create, configure, and delete networks. DELETE is final, so don't do it unless you really mean it.
+
+It's important to understand how network IDs work. The first ten digits (most significant 40 bits) of a network ID are the ZeroTier address of the controller. This is how clients find it. The last six digits (least significant 24 bits) are arbitrary and serve to identify the network uniquely on the controller.
+
+Thus a network's first ten digits *must* be the controller's address. If your controller is *deadbeef01*, then the networks it controls must have IDs like *deadbeef01feed02* or *deadbeef01beef03*. This API however *does not* enforce this requirement. It will allow you to add arbitrary network IDs, but they won't work since clients will never be able to find them.
+
+To create a new network with a random last six digits safely and atomically, you can POST to */controller/network/##########\_\_\_\_\_\_* where ########## is the controller's address and the underscores are as shown. This will pick a random unallocated network ID, which will be returned in the 'nwid' field of the returned JSON object.
<table>
<tr><td><b>Field</b></td><td><b>Type</b></td><td><b>Description</b></td><td><b>Writable</b></td></tr>