mirror of
https://github.com/zerotier/ZeroTierOne.git
synced 2024-12-20 05:28:01 +00:00
Merge branch 'dev' of http://git.int.zerotier.com/ZeroTier/ZeroTierOne into dev
This commit is contained in:
commit
6e1823ac81
525
attic/JSONDB.cpp
525
attic/JSONDB.cpp
@ -1,525 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#ifndef _WIN32
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/select.h>
|
||||
#endif
|
||||
|
||||
#include "JSONDB.hpp"
|
||||
#include "EmbeddedNetworkController.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
static const nlohmann::json _EMPTY_JSON(nlohmann::json::object());
|
||||
|
||||
JSONDB::JSONDB(const std::string &basePath,EmbeddedNetworkController *parent) :
|
||||
_parent(parent),
|
||||
_basePath(basePath),
|
||||
_rawInput(-1),
|
||||
_rawOutput(-1),
|
||||
_summaryThreadRun(true),
|
||||
_dataReady(false)
|
||||
{
|
||||
#ifndef __WINDOWS__
|
||||
if (_basePath == "-") {
|
||||
// If base path is "-" we run in Central harnessed mode. We read pseudo-http-requests from stdin and write
|
||||
// them to stdout.
|
||||
_rawInput = STDIN_FILENO;
|
||||
_rawOutput = STDOUT_FILENO;
|
||||
fcntl(_rawInput,F_SETFL,O_NONBLOCK);
|
||||
} else {
|
||||
#endif
|
||||
// Default mode of operation is to store files in the filesystem
|
||||
OSUtils::mkdir(_basePath.c_str());
|
||||
OSUtils::lockDownFile(_basePath.c_str(),true); // networks might contain auth tokens, etc., so restrict directory permissions
|
||||
#ifndef __WINDOWS__
|
||||
}
|
||||
#endif
|
||||
|
||||
_networks_m.lock(); // locked until data is loaded, etc.
|
||||
|
||||
if (_rawInput < 0) {
|
||||
_load(basePath);
|
||||
_dataReady = true;
|
||||
_networks_m.unlock();
|
||||
} else {
|
||||
// In harnessed mode we leave the lock locked and wait for our initial DB from Central.
|
||||
_summaryThread = Thread::start(this);
|
||||
}
|
||||
}
|
||||
|
||||
JSONDB::~JSONDB()
|
||||
{
|
||||
Thread t;
|
||||
{
|
||||
Mutex::Lock _l(_summaryThread_m);
|
||||
_summaryThreadRun = false;
|
||||
t = _summaryThread;
|
||||
}
|
||||
if (t)
|
||||
Thread::join(t);
|
||||
}
|
||||
|
||||
bool JSONDB::writeRaw(const std::string &n,const std::string &obj)
|
||||
{
|
||||
if (_rawOutput >= 0) {
|
||||
#ifndef __WINDOWS__
|
||||
if (obj.length() > 0) {
|
||||
Mutex::Lock _l(_rawLock);
|
||||
//fprintf(stderr,"%s\n",obj.c_str());
|
||||
if ((long)write(_rawOutput,obj.data(),obj.length()) == (long)obj.length()) {
|
||||
if (write(_rawOutput,"\n",1) == 1)
|
||||
return true;
|
||||
}
|
||||
} else return true;
|
||||
#endif
|
||||
return false;
|
||||
} else {
|
||||
const std::string path(_genPath(n,true));
|
||||
if (!path.length())
|
||||
return false;
|
||||
return OSUtils::writeFile(path.c_str(),obj);
|
||||
}
|
||||
}
|
||||
|
||||
bool JSONDB::hasNetwork(const uint64_t networkId) const
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
return (_networks.find(networkId) != _networks.end());
|
||||
}
|
||||
|
||||
bool JSONDB::getNetwork(const uint64_t networkId,nlohmann::json &config) const
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
const std::unordered_map<uint64_t,_NW>::const_iterator i(_networks.find(networkId));
|
||||
if (i == _networks.end())
|
||||
return false;
|
||||
config = nlohmann::json::from_msgpack(i->second.config);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JSONDB::getNetworkSummaryInfo(const uint64_t networkId,NetworkSummaryInfo &ns) const
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
const std::unordered_map<uint64_t,_NW>::const_iterator i(_networks.find(networkId));
|
||||
if (i == _networks.end())
|
||||
return false;
|
||||
ns = i->second.summaryInfo;
|
||||
return true;
|
||||
}
|
||||
|
||||
int JSONDB::getNetworkAndMember(const uint64_t networkId,const uint64_t nodeId,nlohmann::json &networkConfig,nlohmann::json &memberConfig,NetworkSummaryInfo &ns) const
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
const std::unordered_map<uint64_t,_NW>::const_iterator i(_networks.find(networkId));
|
||||
if (i == _networks.end())
|
||||
return 0;
|
||||
const std::unordered_map< uint64_t,std::vector<uint8_t> >::const_iterator j(i->second.members.find(nodeId));
|
||||
if (j == i->second.members.end())
|
||||
return 1;
|
||||
networkConfig = nlohmann::json::from_msgpack(i->second.config);
|
||||
memberConfig = nlohmann::json::from_msgpack(j->second);
|
||||
ns = i->second.summaryInfo;
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool JSONDB::getNetworkMember(const uint64_t networkId,const uint64_t nodeId,nlohmann::json &memberConfig) const
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
const std::unordered_map<uint64_t,_NW>::const_iterator i(_networks.find(networkId));
|
||||
if (i == _networks.end())
|
||||
return false;
|
||||
const std::unordered_map< uint64_t,std::vector<uint8_t> >::const_iterator j(i->second.members.find(nodeId));
|
||||
if (j == i->second.members.end())
|
||||
return false;
|
||||
memberConfig = nlohmann::json::from_msgpack(j->second);
|
||||
return true;
|
||||
}
|
||||
|
||||
void JSONDB::saveNetwork(const uint64_t networkId,const nlohmann::json &networkConfig)
|
||||
{
|
||||
char n[64];
|
||||
OSUtils::ztsnprintf(n,sizeof(n),"network/%.16llx",(unsigned long long)networkId);
|
||||
writeRaw(n,OSUtils::jsonDump(networkConfig,-1));
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
_NW &nw = _networks[networkId];
|
||||
nw.config = nlohmann::json::to_msgpack(networkConfig);
|
||||
}
|
||||
_recomputeSummaryInfo(networkId);
|
||||
}
|
||||
|
||||
void JSONDB::saveNetworkMember(const uint64_t networkId,const uint64_t nodeId,const nlohmann::json &memberConfig)
|
||||
{
|
||||
char n[256];
|
||||
OSUtils::ztsnprintf(n,sizeof(n),"network/%.16llx/member/%.10llx",(unsigned long long)networkId,(unsigned long long)nodeId);
|
||||
writeRaw(n,OSUtils::jsonDump(memberConfig,-1));
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
std::vector<uint8_t> &m = _networks[networkId].members[nodeId];
|
||||
m = nlohmann::json::to_msgpack(memberConfig);
|
||||
_members[nodeId].insert(networkId);
|
||||
}
|
||||
_recomputeSummaryInfo(networkId);
|
||||
}
|
||||
|
||||
nlohmann::json JSONDB::eraseNetwork(const uint64_t networkId)
|
||||
{
|
||||
if (_rawOutput >= 0) {
|
||||
// In harnessed mode, DB deletes occur in the Central database and we do
|
||||
// not need to erase files.
|
||||
} else {
|
||||
std::vector<uint64_t> memberIds;
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
const std::unordered_map<uint64_t,_NW>::iterator i(_networks.find(networkId));
|
||||
if (i == _networks.end())
|
||||
return _EMPTY_JSON;
|
||||
for(std::unordered_map< uint64_t,std::vector<uint8_t> >::iterator m(i->second.members.begin());m!=i->second.members.end();++m)
|
||||
memberIds.push_back(m->first);
|
||||
}
|
||||
for(std::vector<uint64_t>::iterator m(memberIds.begin());m!=memberIds.end();++m)
|
||||
eraseNetworkMember(networkId,*m,false);
|
||||
|
||||
char n[256];
|
||||
OSUtils::ztsnprintf(n,sizeof(n),"network/%.16llx",(unsigned long long)networkId);
|
||||
const std::string path(_genPath(n,false));
|
||||
if (path.length())
|
||||
OSUtils::rm(path.c_str());
|
||||
}
|
||||
|
||||
// This also erases all members from the memory cache
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
std::unordered_map<uint64_t,_NW>::iterator i(_networks.find(networkId));
|
||||
if (i == _networks.end())
|
||||
return _EMPTY_JSON; // sanity check, shouldn't happen
|
||||
nlohmann::json tmp(nlohmann::json::from_msgpack(i->second.config));
|
||||
_networks.erase(i);
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json JSONDB::eraseNetworkMember(const uint64_t networkId,const uint64_t nodeId,bool recomputeSummaryInfo)
|
||||
{
|
||||
if (_rawOutput >= 0) {
|
||||
// In harnessed mode, DB deletes occur in Central and we do not remove files.
|
||||
} else {
|
||||
char n[256];
|
||||
OSUtils::ztsnprintf(n,sizeof(n),"network/%.16llx/member/%.10llx",(unsigned long long)networkId,(unsigned long long)nodeId);
|
||||
const std::string path(_genPath(n,false));
|
||||
if (path.length())
|
||||
OSUtils::rm(path.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
_members[nodeId].erase(networkId);
|
||||
std::unordered_map<uint64_t,_NW>::iterator i(_networks.find(networkId));
|
||||
if (i == _networks.end())
|
||||
return _EMPTY_JSON;
|
||||
std::unordered_map< uint64_t,std::vector<uint8_t> >::iterator j(i->second.members.find(nodeId));
|
||||
if (j == i->second.members.end())
|
||||
return _EMPTY_JSON;
|
||||
nlohmann::json tmp(j->second);
|
||||
i->second.members.erase(j);
|
||||
if (recomputeSummaryInfo)
|
||||
_recomputeSummaryInfo(networkId);
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void JSONDB::threadMain()
|
||||
throw()
|
||||
{
|
||||
#ifndef __WINDOWS__
|
||||
fd_set readfds,nullfds;
|
||||
char *const readbuf = (_rawInput >= 0) ? (new char[1048576]) : (char *)0;
|
||||
std::string rawInputBuf;
|
||||
FD_ZERO(&readfds);
|
||||
FD_ZERO(&nullfds);
|
||||
struct timeval tv;
|
||||
#endif
|
||||
|
||||
std::vector<uint64_t> todo;
|
||||
|
||||
while (_summaryThreadRun) {
|
||||
#ifndef __WINDOWS__
|
||||
if (_rawInput < 0) {
|
||||
Thread::sleep(25);
|
||||
} else {
|
||||
// In IPC mode we wait but also select() on STDIN to read database updates
|
||||
FD_SET(_rawInput,&readfds);
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 25000;
|
||||
select(_rawInput+1,&readfds,&nullfds,&nullfds,&tv);
|
||||
if (FD_ISSET(_rawInput,&readfds)) {
|
||||
const long rn = (long)read(_rawInput,readbuf,1048576);
|
||||
bool gotMessage = false;
|
||||
for(long i=0;i<rn;++i) {
|
||||
if ((readbuf[i] != '\n')&&(readbuf[i] != '\r')&&(readbuf[i] != 0)) { // compatible with nodeJS IPC
|
||||
rawInputBuf.push_back(readbuf[i]);
|
||||
} else if (rawInputBuf.length() > 0) {
|
||||
try {
|
||||
const nlohmann::json obj(OSUtils::jsonParse(rawInputBuf));
|
||||
gotMessage = true;
|
||||
|
||||
if (!_dataReady) {
|
||||
_dataReady = true;
|
||||
_networks_m.unlock();
|
||||
}
|
||||
|
||||
if (obj.is_array()) {
|
||||
for(unsigned long i=0;i<obj.size();++i)
|
||||
_addOrUpdate(obj[i]);
|
||||
} else if (obj.is_object()) {
|
||||
_addOrUpdate(obj);
|
||||
}
|
||||
} catch ( ... ) {} // ignore malformed JSON
|
||||
|
||||
rawInputBuf.clear();
|
||||
}
|
||||
}
|
||||
if (!gotMessage) // select() again immediately until we get at least one full message
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#else
|
||||
Thread::sleep(25);
|
||||
#endif
|
||||
|
||||
{
|
||||
Mutex::Lock _l(_summaryThread_m);
|
||||
if (_summaryThreadToDo.empty())
|
||||
continue;
|
||||
else _summaryThreadToDo.swap(todo);
|
||||
}
|
||||
|
||||
if (!_dataReady) { // sanity check
|
||||
_dataReady = true;
|
||||
_networks_m.unlock();
|
||||
}
|
||||
|
||||
const int64_t now = OSUtils::now();
|
||||
try {
|
||||
Mutex::Lock _l(_networks_m);
|
||||
for(std::vector<uint64_t>::iterator ii(todo.begin());ii!=todo.end();++ii) {
|
||||
const uint64_t networkId = *ii;
|
||||
std::unordered_map<uint64_t,_NW>::iterator n(_networks.find(networkId));
|
||||
if (n != _networks.end()) {
|
||||
NetworkSummaryInfo &ns = n->second.summaryInfo;
|
||||
ns.activeBridges.clear();
|
||||
ns.allocatedIps.clear();
|
||||
ns.authorizedMemberCount = 0;
|
||||
ns.activeMemberCount = 0;
|
||||
ns.totalMemberCount = 0;
|
||||
ns.mostRecentDeauthTime = 0;
|
||||
|
||||
for(std::unordered_map< uint64_t,std::vector<uint8_t> >::const_iterator m(n->second.members.begin());m!=n->second.members.end();++m) {
|
||||
try {
|
||||
nlohmann::json member(nlohmann::json::from_msgpack(m->second));
|
||||
|
||||
if (OSUtils::jsonBool(member["authorized"],false)) {
|
||||
++ns.authorizedMemberCount;
|
||||
|
||||
try {
|
||||
const nlohmann::json &mlog = member["recentLog"];
|
||||
if ((mlog.is_array())&&(mlog.size() > 0)) {
|
||||
const nlohmann::json &mlog1 = mlog[0];
|
||||
if (mlog1.is_object()) {
|
||||
if ((now - OSUtils::jsonInt(mlog1["ts"],0ULL)) < (ZT_NETWORK_AUTOCONF_DELAY * 2))
|
||||
++ns.activeMemberCount;
|
||||
}
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
|
||||
try {
|
||||
if (OSUtils::jsonBool(member["activeBridge"],false))
|
||||
ns.activeBridges.push_back(Address(m->first));
|
||||
} catch ( ... ) {}
|
||||
|
||||
try {
|
||||
const nlohmann::json &mips = member["ipAssignments"];
|
||||
if (mips.is_array()) {
|
||||
for(unsigned long i=0;i<mips.size();++i) {
|
||||
InetAddress mip(OSUtils::jsonString(mips[i],"").c_str());
|
||||
if ((mip.ss_family == AF_INET)||(mip.ss_family == AF_INET6))
|
||||
ns.allocatedIps.push_back(mip);
|
||||
}
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
} else {
|
||||
try {
|
||||
ns.mostRecentDeauthTime = std::max(ns.mostRecentDeauthTime,(int64_t)OSUtils::jsonInt(member["lastDeauthorizedTime"],0LL));
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
++ns.totalMemberCount;
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
|
||||
std::sort(ns.activeBridges.begin(),ns.activeBridges.end());
|
||||
std::sort(ns.allocatedIps.begin(),ns.allocatedIps.end());
|
||||
|
||||
n->second.summaryInfoLastComputed = now;
|
||||
}
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
|
||||
todo.clear();
|
||||
}
|
||||
|
||||
if (!_dataReady) // sanity check
|
||||
_networks_m.unlock();
|
||||
|
||||
#ifndef __WINDOWS__
|
||||
delete [] readbuf;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool JSONDB::_addOrUpdate(const nlohmann::json &j)
|
||||
{
|
||||
try {
|
||||
if (j.is_object()) {
|
||||
std::string id(OSUtils::jsonString(j["id"],"0"));
|
||||
const std::string objtype(OSUtils::jsonString(j["objtype"],""));
|
||||
if ((id.length() == 16)&&(objtype == "network")) {
|
||||
|
||||
const uint64_t nwid = Utils::hexStrToU64(id.c_str());
|
||||
if (nwid) {
|
||||
bool update;
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
_NW &nw = _networks[nwid];
|
||||
update = !nw.config.empty();
|
||||
nw.config = nlohmann::json::to_msgpack(j);
|
||||
}
|
||||
if (update)
|
||||
_parent->onNetworkUpdate(nwid);
|
||||
_recomputeSummaryInfo(nwid);
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if ((id.length() == 10)&&(objtype == "member")) {
|
||||
|
||||
const uint64_t mid = Utils::hexStrToU64(id.c_str());
|
||||
const uint64_t nwid = Utils::hexStrToU64(OSUtils::jsonString(j["nwid"],"0").c_str());
|
||||
if ((mid)&&(nwid)) {
|
||||
bool update = false;
|
||||
bool deauth = false;
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
std::vector<uint8_t> &m = _networks[nwid].members[mid];
|
||||
if (!m.empty()) {
|
||||
update = true;
|
||||
nlohmann::json oldm(nlohmann::json::from_msgpack(m));
|
||||
deauth = ((OSUtils::jsonBool(oldm["authorized"],false))&&(!OSUtils::jsonBool(j["authorized"],false)));
|
||||
}
|
||||
m = nlohmann::json::to_msgpack(j);
|
||||
_members[mid].insert(nwid);
|
||||
}
|
||||
if (update) {
|
||||
_parent->onNetworkMemberUpdate(nwid,mid);
|
||||
if (deauth)
|
||||
_parent->onNetworkMemberDeauthorize(nwid,mid);
|
||||
}
|
||||
_recomputeSummaryInfo(nwid);
|
||||
return true;
|
||||
}
|
||||
|
||||
} else if (objtype == "_delete") { // pseudo-object-type, only used in Central harnessed mode
|
||||
|
||||
const std::string deleteType(OSUtils::jsonString(j["deleteType"],""));
|
||||
id = OSUtils::jsonString(j["deleteId"],"");
|
||||
if ((deleteType == "network")&&(id.length() == 16)) {
|
||||
eraseNetwork(Utils::hexStrToU64(id.c_str()));
|
||||
} else if ((deleteType == "member")&&(id.length() == 10)) {
|
||||
const std::string networkId(OSUtils::jsonString(j["deleteNetworkId"],""));
|
||||
const uint64_t nwid = Utils::hexStrToU64(networkId.c_str());
|
||||
const uint64_t mid = Utils::hexStrToU64(id.c_str());
|
||||
if (networkId.length() == 16)
|
||||
eraseNetworkMember(nwid,mid,true);
|
||||
_parent->onNetworkMemberDeauthorize(nwid,mid);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool JSONDB::_load(const std::string &p)
|
||||
{
|
||||
// This is not used in stdin/stdout mode. Instead data is populated by
|
||||
// sending it all to stdin.
|
||||
|
||||
std::vector<std::string> dl(OSUtils::listDirectory(p.c_str(),true));
|
||||
for(std::vector<std::string>::const_iterator di(dl.begin());di!=dl.end();++di) {
|
||||
if ((di->length() > 5)&&(di->substr(di->length() - 5) == ".json")) {
|
||||
std::string buf;
|
||||
if (OSUtils::readFile((p + ZT_PATH_SEPARATOR_S + *di).c_str(),buf)) {
|
||||
try {
|
||||
_addOrUpdate(OSUtils::jsonParse(buf));
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
} else {
|
||||
this->_load((p + ZT_PATH_SEPARATOR_S + *di));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void JSONDB::_recomputeSummaryInfo(const uint64_t networkId)
|
||||
{
|
||||
Mutex::Lock _l(_summaryThread_m);
|
||||
if (std::find(_summaryThreadToDo.begin(),_summaryThreadToDo.end(),networkId) == _summaryThreadToDo.end())
|
||||
_summaryThreadToDo.push_back(networkId);
|
||||
if (!_summaryThread)
|
||||
_summaryThread = Thread::start(this);
|
||||
}
|
||||
|
||||
std::string JSONDB::_genPath(const std::string &n,bool create)
|
||||
{
|
||||
std::vector<std::string> pt(OSUtils::split(n.c_str(),"/","",""));
|
||||
if (pt.size() == 0)
|
||||
return std::string();
|
||||
|
||||
std::string p(_basePath);
|
||||
if (create) OSUtils::mkdir(p.c_str());
|
||||
for(unsigned long i=0,j=(unsigned long)(pt.size()-1);i<j;++i) {
|
||||
p.push_back(ZT_PATH_SEPARATOR);
|
||||
p.append(pt[i]);
|
||||
if (create) OSUtils::mkdir(p.c_str());
|
||||
}
|
||||
|
||||
p.push_back(ZT_PATH_SEPARATOR);
|
||||
p.append(pt[pt.size()-1]);
|
||||
p.append(".json");
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
192
attic/JSONDB.hpp
192
attic/JSONDB.hpp
@ -1,192 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ZT_JSONDB_HPP
|
||||
#define ZT_JSONDB_HPP
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include <unordered_set>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
#include "../node/Utils.hpp"
|
||||
#include "../node/InetAddress.hpp"
|
||||
#include "../node/Mutex.hpp"
|
||||
#include "../ext/json/json.hpp"
|
||||
#include "../osdep/OSUtils.hpp"
|
||||
#include "../osdep/Thread.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class EmbeddedNetworkController;
|
||||
|
||||
/**
|
||||
* Hierarchical JSON store that persists into the filesystem or via HTTP
|
||||
*/
|
||||
class JSONDB
|
||||
{
|
||||
public:
|
||||
struct NetworkSummaryInfo
|
||||
{
|
||||
NetworkSummaryInfo() : authorizedMemberCount(0),activeMemberCount(0),totalMemberCount(0),mostRecentDeauthTime(0) {}
|
||||
std::vector<Address> activeBridges;
|
||||
std::vector<InetAddress> allocatedIps;
|
||||
unsigned long authorizedMemberCount;
|
||||
unsigned long activeMemberCount;
|
||||
unsigned long totalMemberCount;
|
||||
int64_t mostRecentDeauthTime;
|
||||
};
|
||||
|
||||
JSONDB(const std::string &basePath,EmbeddedNetworkController *parent);
|
||||
~JSONDB();
|
||||
|
||||
/**
|
||||
* Write a JSON object to the data store
|
||||
*
|
||||
* It's important that obj contain a valid JSON object with no newlines (jsonDump with -1
|
||||
* for indentation), since newline-delimited JSON is what nodeJS's IPC speaks and this
|
||||
* is important in Central-harnessed mode.
|
||||
*
|
||||
* @param n Path name of object
|
||||
* @param obj Object in single-line no-CRs JSON object format (OSUtils::jsonDump(obj,-1))
|
||||
* @return True if write appears successful
|
||||
*/
|
||||
bool writeRaw(const std::string &n,const std::string &obj);
|
||||
|
||||
bool hasNetwork(const uint64_t networkId) const;
|
||||
|
||||
bool getNetwork(const uint64_t networkId,nlohmann::json &config) const;
|
||||
|
||||
bool getNetworkSummaryInfo(const uint64_t networkId,NetworkSummaryInfo &ns) const;
|
||||
|
||||
/**
|
||||
* @return Bit mask: 0 == none, 1 == network only, 3 == network and member
|
||||
*/
|
||||
int getNetworkAndMember(const uint64_t networkId,const uint64_t nodeId,nlohmann::json &networkConfig,nlohmann::json &memberConfig,NetworkSummaryInfo &ns) const;
|
||||
|
||||
bool getNetworkMember(const uint64_t networkId,const uint64_t nodeId,nlohmann::json &memberConfig) const;
|
||||
|
||||
void saveNetwork(const uint64_t networkId,const nlohmann::json &networkConfig);
|
||||
|
||||
void saveNetworkMember(const uint64_t networkId,const uint64_t nodeId,const nlohmann::json &memberConfig);
|
||||
|
||||
nlohmann::json eraseNetwork(const uint64_t networkId);
|
||||
|
||||
nlohmann::json eraseNetworkMember(const uint64_t networkId,const uint64_t nodeId,bool recomputeSummaryInfo = true);
|
||||
|
||||
std::vector<uint64_t> networkIds() const
|
||||
{
|
||||
std::vector<uint64_t> r;
|
||||
Mutex::Lock _l(_networks_m);
|
||||
for(std::unordered_map<uint64_t,_NW>::const_iterator n(_networks.begin());n!=_networks.end();++n)
|
||||
r.push_back(n->first);
|
||||
return r;
|
||||
}
|
||||
|
||||
inline unsigned long memberCount(const uint64_t networkId)
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
std::unordered_map<uint64_t,_NW>::const_iterator i(_networks.find(networkId));
|
||||
if (i != _networks.end())
|
||||
return (unsigned long)i->second.members.size();
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline void eachMember(const uint64_t networkId,F func)
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
std::unordered_map<uint64_t,_NW>::const_iterator i(_networks.find(networkId));
|
||||
if (i != _networks.end()) {
|
||||
for(std::unordered_map< uint64_t,std::vector<uint8_t> >::const_iterator m(i->second.members.begin());m!=i->second.members.end();++m) {
|
||||
try {
|
||||
func(networkId,m->first,nlohmann::json::from_msgpack(m->second));
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline void eachId(F func)
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
for(std::unordered_map<uint64_t,_NW>::const_iterator i(_networks.begin());i!=_networks.end();++i) {
|
||||
for(std::unordered_map< uint64_t,std::vector<uint8_t> >::const_iterator m(i->second.members.begin());m!=i->second.members.end();++m) {
|
||||
try {
|
||||
func(i->first,m->first);
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline std::vector<uint64_t> networksForMember(const uint64_t nodeId)
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
std::unordered_map< uint64_t,std::unordered_set< uint64_t > >::const_iterator m(_members.find(nodeId));
|
||||
if (m != _members.end()) {
|
||||
return std::vector<uint64_t>(m->second.begin(),m->second.end());
|
||||
} else {
|
||||
return std::vector<uint64_t>();
|
||||
}
|
||||
}
|
||||
|
||||
void threadMain()
|
||||
throw();
|
||||
|
||||
private:
|
||||
bool _addOrUpdate(const nlohmann::json &j);
|
||||
bool _load(const std::string &p);
|
||||
void _recomputeSummaryInfo(const uint64_t networkId);
|
||||
std::string _genPath(const std::string &n,bool create);
|
||||
|
||||
EmbeddedNetworkController *const _parent;
|
||||
std::string _basePath;
|
||||
int _rawInput,_rawOutput;
|
||||
Mutex _rawLock;
|
||||
|
||||
Thread _summaryThread;
|
||||
std::vector<uint64_t> _summaryThreadToDo;
|
||||
volatile bool _summaryThreadRun;
|
||||
Mutex _summaryThread_m;
|
||||
|
||||
struct _NW
|
||||
{
|
||||
_NW() : summaryInfoLastComputed(0) {}
|
||||
std::vector<uint8_t> config;
|
||||
NetworkSummaryInfo summaryInfo;
|
||||
uint64_t summaryInfoLastComputed;
|
||||
std::unordered_map< uint64_t,std::vector<uint8_t> > members;
|
||||
};
|
||||
|
||||
std::unordered_map< uint64_t,_NW > _networks;
|
||||
std::unordered_map< uint64_t,std::unordered_set< uint64_t > > _members;
|
||||
bool _dataReady;
|
||||
Mutex _networks_m;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
@ -1,57 +0,0 @@
|
||||
The new ZeroTier CLI!
|
||||
====
|
||||
|
||||
With this update we've expanded upon the previous CLI's functionality, so things should seem pretty familiar. Here are some of the new features we've introduced:
|
||||
|
||||
- Create and administer networks on ZeroTier Central directly from the console.
|
||||
- Service configurations, allows you to control local/remote instances of ZeroTier One
|
||||
- Identity generation and management is now part of the same CLI tool
|
||||
|
||||
***
|
||||
## Configurations
|
||||
|
||||
Configurations are a way for you to nickname and logically organize the control of ZeroTier services running locally or remotely (this includes ZeroTier Central!). They're merely groupings of service API url's and auth tokens. The CLI's settings data is contained within `.zerotierCliSettings`.
|
||||
|
||||
For instance, you can control your local instance of ZeroTier One via the `@local` config. By default it is represented as follows:
|
||||
|
||||
```
|
||||
"local": {
|
||||
"auth": "7tyqRoFytajf21j2l2t9QPm5",
|
||||
"type": "one",
|
||||
"url": "http://127.0.0.1:9993/"
|
||||
}
|
||||
```
|
||||
|
||||
As an example, if you issue the command `zerotier ls` is it implicitly stating `zerotier @local ls`.
|
||||
|
||||
With the same line of thinking, you could create a `@my.zerotier.com` which would allow for something like `zerotier @my.zerotier.com net-create` which talks to our hosted ZeroTier Central to create a new network.
|
||||
|
||||
|
||||
|
||||
## Command families
|
||||
|
||||
- `cli-` is for configuring the settings data for the CLI itself, such as adding/removing `@thing` configurations, variables, etc.
|
||||
- `net-` is for operating on a *ZeroTier Central* service such as `https://my.zerotier.com`
|
||||
- `id-` is for handling ZeroTier identities.
|
||||
|
||||
And those commands with no prefix are there to allow you to operate ZeroTier One instances either local or remote.
|
||||
|
||||
***
|
||||
## Useful command examples
|
||||
|
||||
*Add a ZeroTier One configuration:*
|
||||
|
||||
- `zerotier cli-add-zt MyLocalConfigName https://127.0.0.1:9993/ <authtoken>`
|
||||
|
||||
*Add a ZeroTier Central configuration:*
|
||||
|
||||
- `zerotier cli-add-central MyZTCentralConfigName https://my.zerotier.com/ <centralAPIAuthtoken>`
|
||||
|
||||
*Set a default ZeroTier One instance:*
|
||||
|
||||
- `zerotier cli-set defaultOne MyLocalConfigName`
|
||||
|
||||
*Set a default ZeroTier Central:*
|
||||
|
||||
- `zerotier cli-set defaultCentral MyZTCentralConfigName`
|
||||
|
@ -1,957 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// Note: unlike the rest of ZT's code base, this requires C++11 due to
|
||||
// the JSON library it uses and other things.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
#include "../node/Identity.hpp"
|
||||
#include "../version.h"
|
||||
#include "../osdep/OSUtils.hpp"
|
||||
#include "../ext/offbase/json/json.hpp"
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
#include <WinSock2.h>
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
#include <wchar.h>
|
||||
#else
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <tuple>
|
||||
#include <regex>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
using json = nlohmann::json;
|
||||
using namespace ZeroTier;
|
||||
|
||||
#define ZT_CLI_FLAG_VERBOSE 'v'
|
||||
#define ZT_CLI_FLAG_UNSAFE_SSL 'X'
|
||||
|
||||
#define REQ_GET 0
|
||||
#define REQ_POST 1
|
||||
#define REQ_DEL 2
|
||||
|
||||
#define OK_STR "[OK ]: "
|
||||
#define FAIL_STR "[FAIL]: "
|
||||
#define WARN_STR "[WARN]: "
|
||||
#define INVALID_ARGS_STR "Invalid args. Usage: "
|
||||
|
||||
struct CLIState
|
||||
{
|
||||
std::string atname;
|
||||
std::string command;
|
||||
std::string url;
|
||||
std::map<std::string,std::string> reqHeaders;
|
||||
std::vector<std::string> args;
|
||||
std::map<char,std::string> opts;
|
||||
json settings;
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
static Identity getIdFromArg(char *arg)
|
||||
{
|
||||
Identity id;
|
||||
if ((strlen(arg) > 32)&&(arg[10] == ':')) { // identity is a literal on the command line
|
||||
if (id.fromString(arg))
|
||||
return id;
|
||||
} else { // identity is to be read from a file
|
||||
std::string idser;
|
||||
if (OSUtils::readFile(arg,idser)) {
|
||||
if (id.fromString(idser))
|
||||
return id;
|
||||
}
|
||||
}
|
||||
return Identity();
|
||||
}
|
||||
|
||||
static std::string trimString(const std::string &s)
|
||||
{
|
||||
unsigned long end = (unsigned long)s.length();
|
||||
while (end) {
|
||||
char c = s[end - 1];
|
||||
if ((c == ' ')||(c == '\r')||(c == '\n')||(!c)||(c == '\t'))
|
||||
--end;
|
||||
else break;
|
||||
}
|
||||
unsigned long start = 0;
|
||||
while (start < end) {
|
||||
char c = s[start];
|
||||
if ((c == ' ')||(c == '\r')||(c == '\n')||(!c)||(c == '\t'))
|
||||
++start;
|
||||
else break;
|
||||
}
|
||||
return s.substr(start,end - start);
|
||||
}
|
||||
|
||||
static inline std::string getSettingsFilePath()
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
#else
|
||||
const char *home = getenv("HOME");
|
||||
if (!home)
|
||||
home = "/";
|
||||
return (std::string(home) + "/.zerotierCliSettings");
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool saveSettingsBackup(CLIState &state)
|
||||
{
|
||||
std::string sfp(getSettingsFilePath().c_str());
|
||||
if(state.settings.find("generateBackupConfig") != state.settings.end()
|
||||
&& state.settings["generateBackupConfig"].get<std::string>() == "true") {
|
||||
std::string backup_file = getSettingsFilePath() + ".bak";
|
||||
if(!OSUtils::writeFile(sfp.c_str(), state.settings.dump(2))) {
|
||||
OSUtils::lockDownFile(sfp.c_str(),false);
|
||||
std::cout << WARN_STR << "unable to write backup config file" << std::endl;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool saveSettings(CLIState &state)
|
||||
{
|
||||
std::string sfp(getSettingsFilePath().c_str());
|
||||
if(OSUtils::writeFile(sfp.c_str(), state.settings.dump(2))) {
|
||||
OSUtils::lockDownFile(sfp.c_str(),false);
|
||||
std::cout << OK_STR << "changes saved." << std::endl;
|
||||
return true;
|
||||
}
|
||||
std::cout << FAIL_STR << "unable to write to " << sfp << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
static void dumpHelp()
|
||||
{
|
||||
std::cout << "ZeroTier Newer-Spiffier CLI " << ZEROTIER_ONE_VERSION_MAJOR << "." << ZEROTIER_ONE_VERSION_MINOR << "." << ZEROTIER_ONE_VERSION_REVISION << std::endl;
|
||||
std::cout << "(c)2016 ZeroTier, Inc. / Licensed under the GNU GPL v3" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Configuration path: " << getSettingsFilePath() << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Usage: zerotier [-option] [@name] <command> [<command options>]" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Options:" << std::endl;
|
||||
std::cout << " -verbose - Verbose JSON output" << std::endl;
|
||||
std::cout << " -X - Do not check SSL certs (CAUTION!)" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "CLI Configuration Commands:" << std::endl;
|
||||
std::cout << " cli-set <setting> <value> - Set a CLI option ('cli-set help')" << std::endl;
|
||||
std::cout << " cli-unset <setting> <value> - Un-sets a CLI option ('cli-unset help')" << std::endl;
|
||||
std::cout << " cli-ls - List configured @things" << std::endl;
|
||||
std::cout << " cli-rm @name - Remove a configured @thing" << std::endl;
|
||||
std::cout << " cli-add-zt @name <url> <auth> - Add a ZeroTier service" << std::endl;
|
||||
std::cout << " cli-add-central @name <url> <auth> - Add ZeroTier Central instance" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "ZeroTier One Service Commands:" << std::endl;
|
||||
std::cout << " -v / -version - Displays default local instance's version'" << std::endl;
|
||||
std::cout << " ls - List currently joined networks" << std::endl;
|
||||
std::cout << " join <network> [opt=value ...] - Join a network" << std::endl;
|
||||
std::cout << " leave <network> - Leave a network" << std::endl;
|
||||
std::cout << " peers - List ZeroTier VL1 peers" << std::endl;
|
||||
std::cout << " show [<network/peer address>] - Get info about self or object" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Network Controller Commands:" << std::endl;
|
||||
std::cout << " net-create - Create a new network" << std::endl;
|
||||
std::cout << " net-rm <network> - Delete a network (CAUTION!)" << std::endl;
|
||||
std::cout << " net-ls - List administered networks" << std::endl;
|
||||
std::cout << " net-members <network> - List members of a network" << std::endl;
|
||||
std::cout << " net-show <network> [<address>] - Get network or member info" << std::endl;
|
||||
std::cout << " net-auth <network> <address> - Authorize a member" << std::endl;
|
||||
std::cout << " net-unauth <network> <address> - De-authorize a member" << std::endl;
|
||||
std::cout << " net-set <path> <value> - See 'net-set help'" << std::endl;
|
||||
std::cout << std::endl;
|
||||
std::cout << "Identity Commands:" << std::endl;
|
||||
std::cout << " id-generate [<vanity prefix>] - Generate a ZeroTier identity" << std::endl;
|
||||
std::cout << " id-validate <identity> - Locally validate an identity" << std::endl;
|
||||
std::cout << " id-sign <identity> <file> - Sign a file" << std::endl;
|
||||
std::cout << " id-verify <secret> <file> <sig> - Verify a file's signature" << std::endl;
|
||||
std::cout << " id-getpublic <secret> - Get full identity's public portion" << std::endl;
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
static size_t _curlStringAppendCallback(void *contents,size_t size,size_t nmemb,void *stdstring)
|
||||
{
|
||||
size_t totalSize = size * nmemb;
|
||||
reinterpret_cast<std::string *>(stdstring)->append((const char *)contents,totalSize);
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
static std::tuple<int,std::string> REQUEST(int requestType, CLIState &state, const std::map<std::string,std::string> &headers, const std::string &postfield, const std::string &url)
|
||||
{
|
||||
std::string body;
|
||||
char errbuf[CURL_ERROR_SIZE];
|
||||
char urlbuf[4096];
|
||||
|
||||
CURL *curl;
|
||||
curl = curl_easy_init();
|
||||
if (!curl) {
|
||||
std::cerr << "FATAL: curl_easy_init() failed" << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
Utils::scopy(urlbuf,sizeof(urlbuf),url.c_str());
|
||||
curl_easy_setopt(curl,CURLOPT_URL,urlbuf);
|
||||
|
||||
struct curl_slist *hdrs = (struct curl_slist *)0;
|
||||
for(std::map<std::string,std::string>::const_iterator i(headers.begin());i!=headers.end();++i) {
|
||||
std::string htmp(i->first);
|
||||
htmp.append(": ");
|
||||
htmp.append(i->second);
|
||||
hdrs = curl_slist_append(hdrs,htmp.c_str());
|
||||
}
|
||||
if (hdrs)
|
||||
curl_easy_setopt(curl,CURLOPT_HTTPHEADER,hdrs);
|
||||
|
||||
//curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
|
||||
curl_easy_setopt(curl,CURLOPT_WRITEDATA,(void *)&body);
|
||||
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,_curlStringAppendCallback);
|
||||
|
||||
if(std::find(state.args.begin(), state.args.end(), "-X") == state.args.end())
|
||||
curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,(state.opts.count(ZT_CLI_FLAG_UNSAFE_SSL) > 0) ? 0L : 1L);
|
||||
|
||||
if(requestType == REQ_POST) {
|
||||
curl_easy_setopt(curl, CURLOPT_POST, 1);
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postfield.c_str());
|
||||
}
|
||||
if(requestType == REQ_DEL)
|
||||
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "DELETE");
|
||||
if(requestType == REQ_GET) {
|
||||
curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,errbuf);
|
||||
curl_easy_setopt(curl,CURLOPT_FOLLOWLOCATION,0L);
|
||||
}
|
||||
|
||||
curl_easy_setopt(curl,CURLOPT_USERAGENT,"ZeroTier-CLI");
|
||||
CURLcode res = curl_easy_perform(curl);
|
||||
|
||||
errbuf[CURL_ERROR_SIZE-1] = (char)0; // sanity check
|
||||
|
||||
if (res != CURLE_OK)
|
||||
return std::make_tuple(-1,std::string(errbuf));
|
||||
|
||||
long response_code;
|
||||
int rc = (int)curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE, &response_code);
|
||||
|
||||
if(response_code == 401) { std::cout << FAIL_STR << response_code << "Unauthorized." << std::endl; exit(0); }
|
||||
else if(response_code == 403) { std::cout << FAIL_STR << response_code << "Forbidden." << std::endl; exit(0); }
|
||||
else if(response_code == 404) { std::cout << FAIL_STR << response_code << "Not found." << std::endl; exit(0); }
|
||||
else if(response_code == 408) { std::cout << FAIL_STR << response_code << "Request timed out." << std::endl; exit(0); }
|
||||
else if(response_code != 200) { std::cout << FAIL_STR << response_code << "Unable to process request." << std::endl; exit(0); }
|
||||
|
||||
curl_easy_cleanup(curl);
|
||||
if (hdrs)
|
||||
curl_slist_free_all(hdrs);
|
||||
return std::make_tuple(response_code,body);
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Check for user-specified @thing config
|
||||
// Make sure it @thing makes sense
|
||||
// Apply appropriate request headers
|
||||
static void checkForThing(CLIState &state, std::string thingType, bool warnNoThingProvided)
|
||||
{
|
||||
std::string configName;
|
||||
if(state.atname.length()) {
|
||||
configName = state.atname.erase(0,1);
|
||||
// make sure specified @thing makes sense in the context of the command
|
||||
if(thingType == "one" && state.settings["things"][configName]["type"].get<std::string>() != "one") {
|
||||
std::cout << FAIL_STR << "A ZeroTier Central config was specified for a ZeroTier One command." << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
if(thingType == "central" && state.settings["things"][configName]["type"].get<std::string>() != "central") {
|
||||
std::cout << FAIL_STR << "A ZeroTier One config was specified for a ZeroTier Central command." << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
else { // no @thing specified, check for defaults depending on type
|
||||
if(thingType == "one") {
|
||||
if(state.settings.find("defaultOne") != state.settings.end()) {
|
||||
if(warnNoThingProvided)
|
||||
std::cout << WARN_STR << "No @thing specified, assuming default for ZeroTier One command: " << state.settings["defaultOne"].get<std::string>().c_str() << std::endl;
|
||||
configName = state.settings["defaultOne"].get<std::string>().erase(0,1); // get default
|
||||
}
|
||||
else {
|
||||
std::cout << WARN_STR << "No @thing specified, and no default is known." << std::endl;
|
||||
std::cout << "HELP: To set a default: zerotier cli-set defaultOne @my_default_thing" << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
if(thingType == "central") {
|
||||
if(state.settings.find("defaultCentral") != state.settings.end()) {
|
||||
if(warnNoThingProvided)
|
||||
std::cout << WARN_STR << "No @thing specified, assuming default for ZeroTier Central command: " << state.settings["defaultCentral"].get<std::string>().c_str() << std::endl;
|
||||
configName = state.settings["defaultCentral"].get<std::string>().erase(0,1); // get default
|
||||
}
|
||||
else {
|
||||
std::cout << WARN_STR << "No @thing specified, and no default is known." << std::endl;
|
||||
std::cout << "HELP: To set a default: zerotier cli-set defaultCentral @my_default_thing" << std::endl;
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Apply headers
|
||||
if(thingType == "one") {
|
||||
state.reqHeaders["X-ZT1-Auth"] = state.settings["things"][configName]["auth"];
|
||||
}
|
||||
if(thingType == "central"){
|
||||
state.reqHeaders["Content-Type"] = "application/json";
|
||||
state.reqHeaders["Authorization"] = "Bearer " + state.settings["things"][configName]["auth"].get<std::string>();
|
||||
state.reqHeaders["Accept"] = "application/json";
|
||||
}
|
||||
state.url = state.settings["things"][configName]["url"];
|
||||
}
|
||||
|
||||
static bool checkURL(std::string url)
|
||||
{
|
||||
// TODO
|
||||
return true;
|
||||
}
|
||||
|
||||
static std::string getLocalVersion(CLIState &state)
|
||||
{
|
||||
json result;
|
||||
std::tuple<int,std::string> res;
|
||||
checkForThing(state,"one",false);
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "/status");
|
||||
if(std::get<0>(res) == 200) {
|
||||
result = json::parse(std::get<1>(res));
|
||||
return result["version"].get<std::string>();
|
||||
}
|
||||
return "---";
|
||||
}
|
||||
|
||||
#ifdef __WINDOWS__
|
||||
int _tmain(int argc, _TCHAR* argv[])
|
||||
#else
|
||||
int main(int argc,char **argv)
|
||||
#endif
|
||||
{
|
||||
#ifdef __WINDOWS__
|
||||
{
|
||||
WSADATA wsaData;
|
||||
WSAStartup(MAKEWORD(2,2),&wsaData);
|
||||
}
|
||||
#endif
|
||||
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
CLIState state;
|
||||
std::string arg1, arg2, authToken;
|
||||
|
||||
for(int i=1;i<argc;++i) {
|
||||
if (argv[i][0] == '@') {
|
||||
state.atname = argv[i];
|
||||
}
|
||||
else if (state.command.length() == 0) {
|
||||
if (argv[i][0] == '-') {
|
||||
if (!argv[i][1]) {
|
||||
dumpHelp();
|
||||
return -1;
|
||||
} else if (argv[i][2]) {
|
||||
state.opts[argv[i][1]] = argv[i] + 2;
|
||||
} else {
|
||||
state.opts[argv[i][1]] = "";
|
||||
}
|
||||
} else {
|
||||
state.command = argv[i];
|
||||
}
|
||||
}
|
||||
else {
|
||||
state.args.push_back(std::string(argv[i]));
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
std::string buf;
|
||||
if (OSUtils::readFile(getSettingsFilePath().c_str(),buf))
|
||||
state.settings = json::parse(buf);
|
||||
|
||||
if (state.settings.empty()) {
|
||||
// Default settings
|
||||
state.settings = {
|
||||
{ "configVersion", 1 },
|
||||
{ "things", {
|
||||
{ "my.zerotier.com", {
|
||||
{ "type", "central" },
|
||||
{ "url", "https://my.zerotier.com/" },
|
||||
{ "auth", "" }
|
||||
}},
|
||||
{ "local", {
|
||||
{ "type", "one" },
|
||||
{ "url", "" },
|
||||
{ "auth", "" }
|
||||
}}
|
||||
}},
|
||||
{ "defaultController", "@my.zerotier.com" },
|
||||
{ "defaultOne", "@local" }
|
||||
};
|
||||
|
||||
std::string oneHome(OSUtils::platformDefaultHomePath());
|
||||
std::string portStr;
|
||||
bool initSuccess = false;
|
||||
std::string path = oneHome + ZT_PATH_SEPARATOR_S ;
|
||||
if (OSUtils::readFile((oneHome + ZT_PATH_SEPARATOR_S + "authtoken.secret").c_str(),authToken)&&OSUtils::readFile((oneHome + ZT_PATH_SEPARATOR_S + "zerotier-one.port").c_str(),portStr)) {
|
||||
portStr = trimString(portStr);
|
||||
authToken = trimString(authToken);
|
||||
int port = Utils::strToInt(portStr.c_str());
|
||||
if (((port > 0)&&(port < 65536))&&(authToken.length() > 0)) {
|
||||
state.settings["things"]["local"]["url"] = (std::string("http://127.0.0.1:") + portStr + "/");
|
||||
state.settings["things"]["local"]["auth"] = authToken;
|
||||
initSuccess = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!saveSettings(state)) {
|
||||
std::cerr << "FATAL: unable to write " << getSettingsFilePath() << std::endl;
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
if (initSuccess) {
|
||||
std::cerr << "INFO: initialized new config at " << getSettingsFilePath() << std::endl;
|
||||
} else {
|
||||
std::cerr << "INFO: initialized new config at " << getSettingsFilePath() << " but could not auto-init local ZeroTier One service config from " << oneHome << " -- you will need to set local service URL and port manually if you want to control a local instance of ZeroTier One. (This happens if you are not root/administrator.)" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// PRE-REQUEST SETUP
|
||||
|
||||
json result;
|
||||
std::tuple<int,std::string> res;
|
||||
std::string url = "";
|
||||
|
||||
// META
|
||||
|
||||
if ((state.command.length() == 0)||(state.command == "help")) {
|
||||
dumpHelp();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// zerotier version
|
||||
else if (state.command == "v" || state.command == "version") {
|
||||
std::cout << getLocalVersion(state) << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// zerotier cli-set <setting> <value>
|
||||
else if (state.command == "cli-set") {
|
||||
if(argc != 4) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier cli-set <setting> <value>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string settingName, settingValue;
|
||||
if(state.atname.length()) { // User provided @thing erroneously, we will ignore it and adjust argument indices
|
||||
settingName = argv[3];
|
||||
settingValue = argv[4];
|
||||
}
|
||||
else {
|
||||
settingName = argv[2];
|
||||
settingValue = argv[3];
|
||||
}
|
||||
saveSettingsBackup(state);
|
||||
state.settings[settingName] = settingValue; // changes
|
||||
saveSettings(state);
|
||||
}
|
||||
|
||||
// zerotier cli-unset <setting>
|
||||
else if (state.command == "cli-unset") {
|
||||
if(argc != 3) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier cli-unset <setting>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string settingName;
|
||||
if(state.atname.length()) // User provided @thing erroneously, we will ignore it and adjust argument indices
|
||||
settingName = argv[3];
|
||||
else
|
||||
settingName = argv[2];
|
||||
saveSettingsBackup(state);
|
||||
state.settings.erase(settingName); // changes
|
||||
saveSettings(state);
|
||||
}
|
||||
|
||||
// zerotier @thing_to_remove cli-rm --- removes the configuration
|
||||
else if (state.command == "cli-rm") {
|
||||
if(argc != 3) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier cli-rm <@thing>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if(state.settings["things"].find(state.atname) != state.settings["things"].end()) {
|
||||
if(state.settings["defaultOne"] == state.atname) {
|
||||
std::cout << "WARNING: The config you're trying to remove is currently set as your default. Set a new default first!" << std::endl;
|
||||
std::cout << " | Usage: zerotier set defaultOne @your_other_thing" << std::endl;
|
||||
}
|
||||
else {
|
||||
state.settings["things"].erase(state.atname.c_str());
|
||||
saveSettings(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier cli-add-zt <shortname> <url> <auth>
|
||||
// TODO: Check for malformed urls/auth
|
||||
else if (state.command == "cli-add-zt") {
|
||||
if(argc != 5) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier cli-add-zt <shortname> <url> <authToken>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string thing_name = argv[2], url = argv[3], auth = argv[4];
|
||||
if(!checkURL(url)) {
|
||||
std::cout << FAIL_STR << "Malformed URL" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if(state.settings.find(thing_name) != state.settings.end()) {
|
||||
std::cout << "WARNING: A @thing with the shortname " << thing_name.c_str()
|
||||
<< " already exists. Choose another name or rename the old @thing" << std::endl;
|
||||
std::cout << " | Usage: To rename a @thing: zerotier cli-rename @old_thing_name @new_thing_name" << std::endl;
|
||||
}
|
||||
else {
|
||||
result = json::parse("{ \"auth\": \"" + auth + "\", \"type\": \"" + "one" + "\", \"url\": \"" + url + "\" }");
|
||||
saveSettingsBackup(state);
|
||||
// TODO: Handle cases where user may or may not prepend an @
|
||||
state.settings["things"][thing_name] = result; // changes
|
||||
saveSettings(state);
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier cli-add-central <shortname> <url> <auth>
|
||||
// TODO: Check for malformed urls/auth
|
||||
else if (state.command == "cli-add-central") {
|
||||
if(argc != 5) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier cli-add-central <shortname> <url> <authToken>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string thing_name = argv[2], url = argv[3], auth = argv[4];
|
||||
if(!checkURL(url)) {
|
||||
std::cout << FAIL_STR << "Malformed URL" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if(state.settings.find(thing_name) != state.settings.end()) {
|
||||
std::cout << "WARNING: A @thing with the shortname " << thing_name.c_str()
|
||||
<< " already exists. Choose another name or rename the old @thing" << std::endl;
|
||||
std::cout << " | Usage: To rename a @thing: zerotier cli-rename @old_thing_name @new_thing_name" << std::endl;
|
||||
}
|
||||
else {
|
||||
result = json::parse("{ \"auth\": \"" + auth + "\", \"type\": \"" + "central" + "\", \"url\": \"" + url + "\" }");
|
||||
saveSettingsBackup(state);
|
||||
// TODO: Handle cases where user may or may not prepend an @
|
||||
state.settings["things"]["@" + thing_name] = result; // changes
|
||||
saveSettings(state);
|
||||
}
|
||||
}
|
||||
|
||||
// ONE SERVICE
|
||||
|
||||
// zerotier ls --- display all networks currently joined
|
||||
else if (state.command == "ls" || state.command == "listnetworks") {
|
||||
if(argc != 2) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier ls" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"one",true);
|
||||
url = state.url + "network";
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",(const std::string)url);
|
||||
if(std::get<0>(res) == 200) {
|
||||
std::cout << "listnetworks <nwid> <name> <mac> <status> <type> <dev> <ZT assigned ips>" << std::endl;
|
||||
auto j = json::parse(std::get<1>(res).c_str());
|
||||
if (j.type() == json::value_t::array) {
|
||||
for(int i=0;i<j.size();i++){
|
||||
std::string nwid = j[i]["nwid"].get<std::string>();
|
||||
std::string name = j[i]["name"].get<std::string>();
|
||||
std::string mac = j[i]["mac"].get<std::string>();
|
||||
std::string status = j[i]["status"].get<std::string>();
|
||||
std::string type = j[i]["type"].get<std::string>();
|
||||
std::string addrs;
|
||||
for(int m=0; m<j[i]["assignedAddresses"].size(); m++) {
|
||||
addrs += j[i]["assignedAddresses"][m].get<std::string>() + " ";
|
||||
}
|
||||
std::string dev = j[i]["portDeviceName"].get<std::string>();
|
||||
std::cout << "listnetworks " << nwid << " " << name << " " << mac << " " << status << " " << type << " " << dev << " " << addrs << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier join <nwid> --- joins a network
|
||||
else if (state.command == "join") {
|
||||
if(argc != 3) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier join <nwid>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"one",true);
|
||||
res = REQUEST(REQ_POST,state,state.reqHeaders,"{}",state.url + "/network/" + state.args[0]);
|
||||
if(std::get<0>(res) == 200) {
|
||||
std::cout << OK_STR << "connected to " << state.args[0] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier leave <nwid> --- leaves a network
|
||||
else if (state.command == "leave") {
|
||||
if(argc != 3) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier leave <nwid>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"one",true);
|
||||
res = REQUEST(REQ_DEL,state,state.reqHeaders,"{}",state.url + "/network/" + state.args[0]);
|
||||
if(std::get<0>(res) == 200) {
|
||||
std::cout << OK_STR << "disconnected from " << state.args[0] << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier peers --- display address and role of all peers
|
||||
else if (state.command == "peers") {
|
||||
if(argc != 2) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier peers" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"one",true);
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "/peer");
|
||||
if(std::get<0>(res) == 200) {
|
||||
json result = json::parse(std::get<1>(res));
|
||||
for(int i=0; i<result.size(); i++) {
|
||||
std::cout << result[i]["address"] << " " << result[i]["role"] << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier show --- display status of local instance
|
||||
else if (state.command == "show" || state.command == "status") {
|
||||
if(argc != 2) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier show" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"one",true);
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "/status");
|
||||
if(std::get<0>(res) == 200) {
|
||||
result = json::parse(std::get<1>(res));
|
||||
std::string status_str = result["online"].get<bool>() ? "ONLINE" : "OFFLINE";
|
||||
std::cout << "info " << result["address"].get<std::string>()
|
||||
<< " " << status_str << " " << result["version"].get<std::string>() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// REMOTE
|
||||
|
||||
// zerotier @thing net-create --- creates a new network
|
||||
else if (state.command == "net-create") {
|
||||
if(argc > 3 || (argc == 3 && !state.atname.length())) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-create" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"central",true);
|
||||
res = REQUEST(REQ_POST,state,state.reqHeaders,"",state.url + "api/network");
|
||||
if(std::get<0>(res) == 200) {
|
||||
json result = json::parse(std::get<1>(res));
|
||||
std::cout << OK_STR << "created network " << result["config"]["nwid"].get<std::string>() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier @thing net-rm <nwid> --- deletes a network
|
||||
else if (state.command == "net-rm") {
|
||||
if(argc > 4 || (argc == 4 && !state.atname.length())) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-rm <nwid>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"central",true);
|
||||
if(!state.args.size()) {
|
||||
std::cout << "Argument error: No network specified." << std::endl;
|
||||
std::cout << " | Usage: zerotier net-rm <nwid>" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::string nwid = state.args[0];
|
||||
res = REQUEST(REQ_DEL,state,state.reqHeaders,"",state.url + "api/network/" + nwid);
|
||||
if(std::get<0>(res) == 200) {
|
||||
std::cout << "deleted network " << nwid << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier @thing net-ls --- lists all networks
|
||||
else if (state.command == "net-ls") {
|
||||
if(argc > 3 || (argc == 3 && !state.atname.length())) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-ls" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"central",true);
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "api/network");
|
||||
if(std::get<0>(res) == 200) {
|
||||
json result = json::parse(std::get<1>(res));
|
||||
for(int m=0;m<result.size(); m++) {
|
||||
std::cout << "network " << result[m]["id"].get<std::string>() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier @thing net-members <nwid> --- show all members of a network
|
||||
else if (state.command == "net-members") {
|
||||
if(argc > 4 || (argc == 4 && !state.atname.length())) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-members <nwid>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"central",true);
|
||||
if(!state.args.size()) {
|
||||
std::cout << FAIL_STR << "Argument error: No network specified." << std::endl;
|
||||
std::cout << " | Usage: zerotier net-members <nwid>" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::string nwid = state.args[0];
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "api/network/" + nwid + "/member");
|
||||
json result = json::parse(std::get<1>(res));
|
||||
std::cout << "Members of " << nwid << ":" << std::endl;
|
||||
for (json::iterator it = result.begin(); it != result.end(); ++it) {
|
||||
std::cout << it.key() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier @thing net-show <nwid> <devID> --- show info about a device on a specific network
|
||||
else if (state.command == "net-show") {
|
||||
if(argc > 5 || (argc == 5 && !state.atname.length())) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-show <nwid> <devID>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"central",true);
|
||||
if(state.args.size() < 2) {
|
||||
std::cout << FAIL_STR << "Argument error: Too few arguments." << std::endl;
|
||||
std::cout << " | Usage: zerotier net-show <nwid> <devID>" << std::endl;
|
||||
}
|
||||
else {
|
||||
std::string nwid = state.args[0];
|
||||
std::string devid = state.args[1];
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "api/network/" + nwid + "/member/" + devid);
|
||||
// TODO: More info, what would we like to show exactly?
|
||||
if(std::get<0>(res) == 200) {
|
||||
json result = json::parse(std::get<1>(res));
|
||||
std::cout << "Assigned IP: " << std::endl;
|
||||
for(int m=0; m<result["config"]["ipAssignments"].size();m++) {
|
||||
std::cout << "\t" << result["config"]["ipAssignments"][m].get<std::string>() << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier @thing net-auth <nwid> <devID> --- authorize a device on a network
|
||||
else if (state.command == "net-auth") {
|
||||
if(argc > 5 || (argc == 5 && !state.atname.length())) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-auth <nwid> <devID>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"central",true);
|
||||
if(state.args.size() != 2) {
|
||||
std::cout << FAIL_STR << "Argument error: Network and/or device ID not specified." << std::endl;
|
||||
std::cout << " | Usage: zerotier net-auth <nwid> <devID>" << std::endl;
|
||||
}
|
||||
std::string nwid = state.args[0];
|
||||
std::string devid = state.args[1];
|
||||
url = state.url + "api/network/" + nwid + "/member/" + devid;
|
||||
// Add device to network
|
||||
res = REQUEST(REQ_POST,state,state.reqHeaders,"",(const std::string)url);
|
||||
if(std::get<0>(res) == 200) {
|
||||
result = json::parse(std::get<1>(res));
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",(const std::string)url);
|
||||
result = json::parse(std::get<1>(res));
|
||||
result["config"]["authorized"] = "true";
|
||||
std::string newconfig = result.dump();
|
||||
res = REQUEST(REQ_POST,state,state.reqHeaders,newconfig,(const std::string)url);
|
||||
if(std::get<0>(res) == 200)
|
||||
std::cout << OK_STR << devid << " authorized on " << nwid << std::endl;
|
||||
else
|
||||
std::cout << FAIL_STR << "There was a problem authorizing that device." << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier @thing net-unauth <nwid> <devID>
|
||||
else if (state.command == "net-unauth") {
|
||||
if(argc > 5 || (argc == 5 && !state.atname.length())) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier <@thing> net-unauth <nwid> <devID>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
checkForThing(state,"central",true);
|
||||
if(state.args.size() != 2) {
|
||||
std::cout << FAIL_STR << "Bad argument. No network and/or device ID specified." << std::endl;
|
||||
std::cout << " | Usage: zerotier net-unauth <nwid> <devID>" << std::endl;
|
||||
}
|
||||
std::string nwid = state.args[0];
|
||||
std::string devid = state.args[1];
|
||||
// If successful, get member config
|
||||
res = REQUEST(REQ_GET,state,state.reqHeaders,"",state.url + "api/network/" + nwid + "/member/" + devid);
|
||||
result = json::parse(std::get<1>(res));
|
||||
// modify auth field and re-POST
|
||||
result["config"]["authorized"] = "false";
|
||||
std::string newconfig = result.dump();
|
||||
res = REQUEST(REQ_POST,state,state.reqHeaders,newconfig,state.url + "api/network/" + nwid + "/member/" + devid);
|
||||
if(std::get<0>(res) == 200)
|
||||
std::cout << OK_STR << devid << " de-authorized from " << nwid << std::endl;
|
||||
else
|
||||
std::cout << FAIL_STR << "There was a problem de-authorizing that device." << std::endl;
|
||||
}
|
||||
|
||||
// zerotier @thing net-set
|
||||
else if (state.command == "net-set") {
|
||||
}
|
||||
|
||||
// ID
|
||||
|
||||
// zerotier id-generate [<vanity prefix>]
|
||||
else if (state.command == "id-generate") {
|
||||
if(argc != 3) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier id-generate [<vanity prefix>]" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
uint64_t vanity = 0;
|
||||
int vanityBits = 0;
|
||||
if (argc >= 5) {
|
||||
vanity = Utils::hexStrToU64(argv[4]) & 0xffffffffffULL;
|
||||
vanityBits = 4 * strlen(argv[4]);
|
||||
if (vanityBits > 40)
|
||||
vanityBits = 40;
|
||||
}
|
||||
|
||||
ZeroTier::Identity id;
|
||||
for(;;) {
|
||||
id.generate();
|
||||
if ((id.address().toInt() >> (40 - vanityBits)) == vanity) {
|
||||
if (vanityBits > 0) {
|
||||
fprintf(stderr,"vanity address: found %.10llx !\n",(unsigned long long)id.address().toInt());
|
||||
}
|
||||
break;
|
||||
} else {
|
||||
fprintf(stderr,"vanity address: tried %.10llx looking for first %d bits of %.10llx\n",(unsigned long long)id.address().toInt(),vanityBits,(unsigned long long)(vanity << (40 - vanityBits)));
|
||||
}
|
||||
}
|
||||
|
||||
std::string idser = id.toString(true);
|
||||
if (argc >= 3) {
|
||||
if (!OSUtils::writeFile(argv[2],idser)) {
|
||||
std::cerr << "Error writing to " << argv[2] << std::endl;
|
||||
return 1;
|
||||
} else std::cout << argv[2] << " written" << std::endl;
|
||||
if (argc >= 4) {
|
||||
idser = id.toString(false);
|
||||
if (!OSUtils::writeFile(argv[3],idser)) {
|
||||
std::cerr << "Error writing to " << argv[3] << std::endl;
|
||||
return 1;
|
||||
} else std::cout << argv[3] << " written" << std::endl;
|
||||
}
|
||||
} else std::cout << idser << std::endl;
|
||||
}
|
||||
|
||||
// zerotier id-validate <identity>
|
||||
else if (state.command == "id-validate") {
|
||||
if(argc != 3) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier id-validate <identity>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
Identity id = getIdFromArg(argv[2]);
|
||||
if (!id) {
|
||||
std::cerr << "Identity argument invalid or file unreadable: " << argv[2] << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (!id.locallyValidate()) {
|
||||
std::cerr << argv[2] << " FAILED validation." << std::endl;
|
||||
return 1;
|
||||
} else std::cout << argv[2] << "is a valid identity" << std::endl;
|
||||
}
|
||||
|
||||
// zerotier id-sign <identity> <file>
|
||||
else if (state.command == "id-sign") {
|
||||
if(argc != 4) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier id-sign <identity> <file>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
Identity id = getIdFromArg(argv[2]);
|
||||
if (!id) {
|
||||
std::cerr << "Identity argument invalid or file unreadable: " << argv[2] << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (!id.hasPrivate()) {
|
||||
std::cerr << argv[2] << " does not contain a private key (must use private to sign)" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string inf;
|
||||
if (!OSUtils::readFile(argv[3],inf)) {
|
||||
std::cerr << argv[3] << " is not readable" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
C25519::Signature signature = id.sign(inf.data(),(unsigned int)inf.length());
|
||||
std::cout << Utils::hex(signature.data,(unsigned int)signature.size()) << std::endl;
|
||||
}
|
||||
|
||||
// zerotier id-verify <secret> <file> <sig>
|
||||
else if (state.command == "id-verify") {
|
||||
if(argc != 4) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier id-verify <secret> <file> <sig>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
Identity id = getIdFromArg(argv[2]);
|
||||
if (!id) {
|
||||
std::cerr << "Identity argument invalid or file unreadable: " << argv[2] << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string inf;
|
||||
if (!OSUtils::readFile(argv[3],inf)) {
|
||||
std::cerr << argv[3] << " is not readable" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::string signature(Utils::unhex(argv[4]));
|
||||
if ((signature.length() > ZT_ADDRESS_LENGTH)&&(id.verify(inf.data(),(unsigned int)inf.length(),signature.data(),(unsigned int)signature.length()))) {
|
||||
std::cout << argv[3] << " signature valid" << std::endl;
|
||||
} else {
|
||||
std::cerr << argv[3] << " signature check FAILED" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// zerotier id-getpublic <secret>
|
||||
else if (state.command == "id-getpublic") {
|
||||
if(argc != 3) {
|
||||
std::cerr << INVALID_ARGS_STR << "zerotier id-getpublic <secret>" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
Identity id = getIdFromArg(argv[2]);
|
||||
if (!id) {
|
||||
std::cerr << "Identity argument invalid or file unreadable: " << argv[2] << std::endl;
|
||||
return 1;
|
||||
}
|
||||
std::cerr << id.toString(false) << std::endl;
|
||||
}
|
||||
//
|
||||
else {
|
||||
dumpHelp();
|
||||
return -1;
|
||||
}
|
||||
if(std::find(state.args.begin(), state.args.end(), "-verbose") != state.args.end())
|
||||
std::cout << "\n\nAPI response = " << std::get<1>(res) << std::endl;
|
||||
curl_global_cleanup();
|
||||
return 0;
|
||||
}
|
@ -1,8 +0,0 @@
|
||||
Dockerized Linux Build Farm
|
||||
======
|
||||
|
||||
This subfolder contains Dockerfiles and a script to build Linux packages for a variety of Linux distributions. It's also an excellent way to test your CPU fans and stress test your disk.
|
||||
|
||||
Running `build.sh` with no arguments builds everything. You can run `build.sh` with the name of a distro (e.g. centos-7) to only build that. Both 32 and 64 bit packages are built except where no 32-bit version of the distribution exists.
|
||||
|
||||
The `make-apt-repos.sh` and `make-rpm-repos.sh` scripts build repositories. They may require some editing for outside-of-ZeroTier use, and be careful with the apt one if you have an existing *aptly* configuration.
|
@ -1,13 +0,0 @@
|
||||
#FROM ambakshi/amazon-linux:2016.03
|
||||
#MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
#RUN yum update -y
|
||||
#RUN yum install -y epel-release
|
||||
#RUN yum install -y make development-tools rpmdevtools clang gcc-c++ ruby ruby-devel
|
||||
|
||||
#RUN gem install ronn
|
||||
|
||||
FROM zerotier/zt1-build-amazon-2016.03-x64-base
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
ADD zt1-src.tar.gz /
|
@ -1,69 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export PATH=/bin:/usr/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/sbin
|
||||
|
||||
subdirs=$*
|
||||
if [ ! -n "$subdirs" ]; then
|
||||
subdirs=`find . -type d -name '*-*' -printf '%f '`
|
||||
fi
|
||||
|
||||
if [ ! -d ./ubuntu-trusty ]; then
|
||||
echo 'Must run from linux-build-farm subfolder.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -f zt1-src.tar.gz
|
||||
cd ..
|
||||
git archive --format=tar.gz --prefix=ZeroTierOne/ -o linux-build-farm/zt1-src.tar.gz HEAD
|
||||
cd linux-build-farm
|
||||
|
||||
# Note that --privileged is used so we can bind mount VM shares when building in a VM.
|
||||
# It has no other impact or purpose, but probably doesn't matter here in any case.
|
||||
|
||||
for distro in $subdirs; do
|
||||
echo
|
||||
echo "--- BUILDING FOR $distro ---"
|
||||
echo
|
||||
|
||||
cd $distro
|
||||
|
||||
if [ -d x64 ]; then
|
||||
cd x64
|
||||
mv ../../zt1-src.tar.gz .
|
||||
docker build -t zt1-build-${distro}-x64 .
|
||||
mv zt1-src.tar.gz ../..
|
||||
cd ..
|
||||
fi
|
||||
|
||||
if [ -d x86 ]; then
|
||||
cd x86
|
||||
mv ../../zt1-src.tar.gz .
|
||||
docker build -t zt1-build-${distro}-x86 .
|
||||
mv zt1-src.tar.gz ../..
|
||||
cd ..
|
||||
fi
|
||||
|
||||
rm -f *.deb *.rpm
|
||||
|
||||
# exit 0
|
||||
|
||||
if [ ! -n "`echo $distro | grep -F debian`" -a ! -n "`echo $distro | grep -F ubuntu`" ]; then
|
||||
if [ -d x64 ]; then
|
||||
docker run --rm -v `pwd`:/artifacts --privileged -it zt1-build-${distro}-x64 /bin/bash -c 'cd /ZeroTierOne ; make redhat ; cd .. ; cp `find /root/rpmbuild -type f -name *.rpm` /artifacts ; ls -l /artifacts'
|
||||
fi
|
||||
if [ -d x86 ]; then
|
||||
docker run --rm -v `pwd`:/artifacts --privileged -it zt1-build-${distro}-x86 /bin/bash -c 'cd /ZeroTierOne ; make redhat ; cd .. ; cp `find /root/rpmbuild -type f -name *.rpm` /artifacts ; ls -l /artifacts'
|
||||
fi
|
||||
else
|
||||
if [ -d x64 ]; then
|
||||
docker run --rm -v `pwd`:/artifacts --privileged -it zt1-build-${distro}-x64 /bin/bash -c 'cd /ZeroTierOne ; make debian ; cd .. ; cp *.deb /artifacts ; ls -l /artifacts'
|
||||
fi
|
||||
if [ -d x86 ]; then
|
||||
docker run --rm -v `pwd`:/artifacts --privileged -it zt1-build-${distro}-x86 /bin/bash -c 'cd /ZeroTierOne ; make debian ; cd .. ; cp *.deb /artifacts ; ls -l /artifacts'
|
||||
fi
|
||||
fi
|
||||
|
||||
cd ..
|
||||
done
|
||||
|
||||
rm -f zt1-src.tar.gz
|
@ -1,13 +0,0 @@
|
||||
FROM centos:6
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN yum update -y
|
||||
RUN yum install -y epel-release
|
||||
RUN yum install -y make development-tools rpmdevtools clang gcc-c++ tar
|
||||
|
||||
RUN yum install -y nodejs npm
|
||||
|
||||
# Stop use of http-parser-devel which is installed by nodejs/npm
|
||||
RUN rm -f /usr/include/http_parser.h
|
||||
|
||||
ADD zt1-src.tar.gz /
|
@ -1,13 +0,0 @@
|
||||
FROM toopher/centos-i386:centos6
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN yum update -y
|
||||
RUN yum install -y epel-release
|
||||
RUN yum install -y make development-tools rpmdevtools clang gcc-c++ tar
|
||||
|
||||
RUN yum install -y nodejs npm
|
||||
|
||||
# Stop use of http-parser-devel which is installed by nodejs/npm
|
||||
RUN rm -f /usr/include/http_parser.h
|
||||
|
||||
ADD zt1-src.tar.gz /
|
@ -1,10 +0,0 @@
|
||||
FROM centos:7
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN yum update -y
|
||||
RUN yum install -y epel-release
|
||||
RUN yum install -y make development-tools rpmdevtools clang gcc-c++ ruby ruby-devel
|
||||
|
||||
RUN gem install ronn
|
||||
|
||||
ADD zt1-src.tar.gz /
|
@ -1,22 +0,0 @@
|
||||
#FROM zerotier/centos7-32bit
|
||||
#MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
#RUN echo 'i686-redhat-linux' >/etc/rpm/platform
|
||||
|
||||
#RUN yum update -y
|
||||
#RUN yum install -y make development-tools rpmdevtools http-parser-devel lz4-devel libnatpmp-devel
|
||||
|
||||
#RUN yum install -y gcc-c++
|
||||
#RUN rpm --install --force https://dl.fedoraproject.org/pub/epel/epel-release-latest-6.noarch.rpm
|
||||
#RUN rpm --install --force ftp://rpmfind.net/linux/centos/6.8/os/i386/Packages/libffi-3.0.5-3.2.el6.i686.rpm
|
||||
#RUN yum install -y clang
|
||||
|
||||
FROM zerotier/zt1-build-centos-7-x86-base
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN yum install -y ruby ruby-devel
|
||||
RUN gem install ronn
|
||||
|
||||
#RUN rpm --erase http-parser-devel lz4-devel libnatpmp-devel
|
||||
|
||||
ADD zt1-src.tar.gz /
|
@ -1,12 +0,0 @@
|
||||
FROM debian:jessie
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang-3.5
|
||||
|
||||
RUN ln -sf /usr/bin/clang++-3.5 /usr/bin/clang++
|
||||
RUN ln -sf /usr/bin/clang-3.5 /usr/bin/clang
|
||||
|
||||
RUN dpkg --purge libhttp-parser-dev
|
||||
|
||||
ADD zt1-src.tar.gz /
|
@ -1,12 +0,0 @@
|
||||
FROM 32bit/debian:jessie
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang-3.5
|
||||
|
||||
RUN ln -sf /usr/bin/clang++-3.5 /usr/bin/clang++
|
||||
RUN ln -sf /usr/bin/clang-3.5 /usr/bin/clang
|
||||
|
||||
RUN dpkg --purge libhttp-parser-dev
|
||||
|
||||
ADD zt1-src.tar.gz /
|
@ -1,12 +0,0 @@
|
||||
FROM debian:stretch
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang
|
||||
|
||||
#RUN ln -sf /usr/bin/clang++-3.5 /usr/bin/clang++
|
||||
#RUN ln -sf /usr/bin/clang-3.5 /usr/bin/clang
|
||||
|
||||
RUN dpkg --purge libhttp-parser-dev
|
||||
|
||||
ADD zt1-src.tar.gz /
|
@ -1,12 +0,0 @@
|
||||
FROM mcandre/docker-debian-32bit:stretch
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang
|
||||
|
||||
#RUN ln -sf /usr/bin/clang++-3.5 /usr/bin/clang++
|
||||
#RUN ln -sf /usr/bin/clang-3.5 /usr/bin/clang
|
||||
|
||||
RUN dpkg --purge libhttp-parser-dev
|
||||
|
||||
ADD zt1-src.tar.gz /
|
@ -1,12 +0,0 @@
|
||||
FROM debian:wheezy
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential debhelper ruby-ronn g++ make devscripts
|
||||
|
||||
RUN dpkg --purge libhttp-parser-dev
|
||||
|
||||
ADD zt1-src.tar.gz /
|
||||
|
||||
RUN mv -f /ZeroTierOne/debian/control.wheezy /ZeroTierOne/debian/control
|
||||
RUN mv -f /ZeroTierOne/debian/rules.wheezy /ZeroTierOne/debian/rules
|
@ -1,15 +0,0 @@
|
||||
#FROM tubia/debian:wheezy
|
||||
#MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
#RUN apt-get update
|
||||
#RUN apt-get install -y build-essential debhelper ruby-ronn g++ make devscripts
|
||||
|
||||
FROM zerotier/zt1-build-debian-wheezy-x86-base
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN dpkg --purge libhttp-parser-dev
|
||||
|
||||
ADD zt1-src.tar.gz /
|
||||
|
||||
RUN mv -f /ZeroTierOne/debian/control.wheezy /ZeroTierOne/debian/control
|
||||
RUN mv -f /ZeroTierOne/debian/rules.wheezy /ZeroTierOne/debian/rules
|
@ -1,10 +0,0 @@
|
||||
FROM fedora:22
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN yum update -y
|
||||
RUN yum install -y make rpmdevtools gcc-c++ rubygem-ronn json-parser-devel lz4-devel http-parser-devel libnatpmp-devel
|
||||
|
||||
RUN rpm --erase http-parser-devel
|
||||
RUN yum install -y rubygem-ronn ruby
|
||||
|
||||
ADD zt1-src.tar.gz /
|
@ -1,19 +0,0 @@
|
||||
#FROM nickcis/fedora-32:22
|
||||
#MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
#RUN mkdir -p /etc/dnf/vars
|
||||
#RUN echo 'i386' >/etc/dnf/vars/basearch
|
||||
#RUN echo 'i386' >/etc/dnf/vars/arch
|
||||
|
||||
#RUN yum update -y
|
||||
#RUN yum install -y make rpmdevtools gcc-c++ rubygem-ronn json-parser-devel lz4-devel http-parser-devel libnatpmp-devel
|
||||
|
||||
FROM zerotier/zt1-build-fedora-22-x86-base
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN echo 'i686-redhat-linux' >/etc/rpm/platform
|
||||
|
||||
RUN rpm --erase http-parser-devel
|
||||
RUN yum install -y rubygem-ronn ruby
|
||||
|
||||
ADD zt1-src.tar.gz /
|
@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This builds a series of Debian repositories for each distribution.
|
||||
|
||||
export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin
|
||||
|
||||
for distro in debian-* ubuntu-*; do
|
||||
if [ -n "`find ${distro} -name '*.deb' -type f`" ]; then
|
||||
arches=`ls ${distro}/*.deb | cut -d _ -f 3 | cut -d . -f 1 | xargs | sed 's/ /,/g'`
|
||||
distro_name=`echo $distro | cut -d '-' -f 2`
|
||||
echo '---' $distro / $distro_name / $arches
|
||||
aptly repo create -architectures=${arches} -comment="ZeroTier, Inc. Debian Packages" -component="main" -distribution=${distro_name} zt-release-${distro_name}
|
||||
aptly repo add zt-release-${distro_name} ${distro}/*.deb
|
||||
aptly publish repo zt-release-${distro_name} $distro_name
|
||||
fi
|
||||
done
|
@ -1,64 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin
|
||||
|
||||
GPG_KEY=contact@zerotier.com
|
||||
|
||||
rm -rf /tmp/zt-rpm-repo
|
||||
mkdir /tmp/zt-rpm-repo
|
||||
|
||||
for distro in centos-* fedora-* amazon-*; do
|
||||
dname=`echo $distro | cut -d '-' -f 1`
|
||||
if [ "$dname" = "centos" ]; then
|
||||
dname=el
|
||||
fi
|
||||
if [ "$dname" = "fedora" ]; then
|
||||
dname=fc
|
||||
fi
|
||||
if [ "$dname" = "amazon" ]; then
|
||||
dname=amzn1
|
||||
fi
|
||||
dvers=`echo $distro | cut -d '-' -f 2`
|
||||
|
||||
mkdir -p /tmp/zt-rpm-repo/$dname/$dvers
|
||||
|
||||
cp -v $distro/*.rpm /tmp/zt-rpm-repo/$dname/$dvers
|
||||
done
|
||||
|
||||
rpmsign --resign --key-id=$GPG_KEY --digest-algo=sha256 `find /tmp/zt-rpm-repo -type f -name '*.rpm'`
|
||||
|
||||
for db in `find /tmp/zt-rpm-repo -mindepth 2 -maxdepth 2 -type d`; do
|
||||
createrepo --database $db
|
||||
done
|
||||
|
||||
# Stupid RHEL stuff
|
||||
cd /tmp/zt-rpm-repo/el
|
||||
ln -sf 6 6Client
|
||||
ln -sf 6 6Workstation
|
||||
ln -sf 6 6Server
|
||||
ln -sf 6 6.0
|
||||
ln -sf 6 6.1
|
||||
ln -sf 6 6.2
|
||||
ln -sf 6 6.3
|
||||
ln -sf 6 6.4
|
||||
ln -sf 6 6.5
|
||||
ln -sf 6 6.6
|
||||
ln -sf 6 6.7
|
||||
ln -sf 6 6.8
|
||||
ln -sf 6 6.9
|
||||
ln -sf 7 7Client
|
||||
ln -sf 7 7Workstation
|
||||
ln -sf 7 7Server
|
||||
ln -sf 7 7.0
|
||||
ln -sf 7 7.1
|
||||
ln -sf 7 7.2
|
||||
ln -sf 7 7.3
|
||||
ln -sf 7 7.4
|
||||
ln -sf 7 7.5
|
||||
ln -sf 7 7.6
|
||||
ln -sf 7 7.7
|
||||
ln -sf 7 7.8
|
||||
ln -sf 7 7.9
|
||||
|
||||
echo
|
||||
echo Repo created in /tmp/zt-rpm-repo
|
@ -1,12 +0,0 @@
|
||||
FROM ubuntu:14.04
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang-3.6
|
||||
|
||||
RUN ln -sf /usr/bin/clang++-3.6 /usr/bin/clang++
|
||||
RUN ln -sf /usr/bin/clang-3.6 /usr/bin/clang
|
||||
|
||||
RUN dpkg --purge libhttp-parser-dev
|
||||
|
||||
ADD zt1-src.tar.gz /
|
@ -1,12 +0,0 @@
|
||||
FROM 32bit/ubuntu:14.04
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang-3.6
|
||||
|
||||
RUN ln -sf /usr/bin/clang++-3.6 /usr/bin/clang++
|
||||
RUN ln -sf /usr/bin/clang-3.6 /usr/bin/clang
|
||||
|
||||
RUN dpkg --purge libhttp-parser-dev
|
||||
|
||||
ADD zt1-src.tar.gz /
|
@ -1,12 +0,0 @@
|
||||
FROM ubuntu:wily
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang-3.7
|
||||
|
||||
RUN ln -sf /usr/bin/clang++-3.7 /usr/bin/clang++
|
||||
RUN ln -sf /usr/bin/clang-3.7 /usr/bin/clang
|
||||
|
||||
RUN dpkg --purge libhttp-parser-dev
|
||||
|
||||
ADD zt1-src.tar.gz /
|
@ -1,12 +0,0 @@
|
||||
FROM daald/ubuntu32:wily
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang-3.7
|
||||
|
||||
RUN ln -sf /usr/bin/clang++-3.7 /usr/bin/clang++
|
||||
RUN ln -sf /usr/bin/clang-3.7 /usr/bin/clang
|
||||
|
||||
RUN dpkg --purge libhttp-parser-dev
|
||||
|
||||
ADD zt1-src.tar.gz /
|
@ -1,14 +0,0 @@
|
||||
FROM ubuntu:xenial
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang-3.8
|
||||
|
||||
#RUN ln -sf /usr/bin/clang++-3.8 /usr/bin/clang++
|
||||
#RUN ln -sf /usr/bin/clang-3.8 /usr/bin/clang
|
||||
|
||||
RUN rm -f /usr/bin/clang++ /usr/bin/clang
|
||||
|
||||
RUN dpkg --purge libhttp-parser-dev
|
||||
|
||||
ADD zt1-src.tar.gz /
|
@ -1,14 +0,0 @@
|
||||
FROM f69m/ubuntu32:xenial
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y build-essential debhelper libhttp-parser-dev liblz4-dev libnatpmp-dev dh-systemd ruby-ronn g++ make devscripts clang-3.8
|
||||
|
||||
#RUN ln -sf /usr/bin/clang++-3.8 /usr/bin/clang++
|
||||
#RUN ln -sf /usr/bin/clang-3.8 /usr/bin/clang
|
||||
|
||||
RUN rm -f /usr/bin/clang++ /usr/bin/clang
|
||||
|
||||
RUN dpkg --purge libhttp-parser-dev
|
||||
|
||||
ADD zt1-src.tar.gz /
|
@ -1,112 +0,0 @@
|
||||
CREATE TABLE Config (
|
||||
k varchar(16) PRIMARY KEY NOT NULL,
|
||||
v varchar(1024) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE Network (
|
||||
id char(16) PRIMARY KEY NOT NULL,
|
||||
name varchar(128) NOT NULL,
|
||||
private integer NOT NULL DEFAULT(1),
|
||||
enableBroadcast integer NOT NULL DEFAULT(1),
|
||||
allowPassiveBridging integer NOT NULL DEFAULT(0),
|
||||
multicastLimit integer NOT NULL DEFAULT(32),
|
||||
creationTime integer NOT NULL DEFAULT(0),
|
||||
revision integer NOT NULL DEFAULT(1),
|
||||
memberRevisionCounter integer NOT NULL DEFAULT(1),
|
||||
flags integer NOT NULL DEFAULT(0)
|
||||
);
|
||||
|
||||
CREATE TABLE AuthToken (
|
||||
id integer PRIMARY KEY NOT NULL,
|
||||
networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
|
||||
authMode integer NOT NULL DEFAULT(1),
|
||||
useCount integer NOT NULL DEFAULT(0),
|
||||
maxUses integer NOT NULL DEFAULT(0),
|
||||
expiresAt integer NOT NULL DEFAULT(0),
|
||||
token varchar(256) NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX AuthToken_networkId_token ON AuthToken(networkId,token);
|
||||
|
||||
CREATE TABLE Node (
|
||||
id char(10) PRIMARY KEY NOT NULL,
|
||||
identity varchar(4096) NOT NULL
|
||||
);
|
||||
|
||||
CREATE TABLE IpAssignment (
|
||||
networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
|
||||
nodeId char(10) REFERENCES Node(id) ON DELETE CASCADE,
|
||||
type integer NOT NULL DEFAULT(0),
|
||||
ip blob(16) NOT NULL,
|
||||
ipNetmaskBits integer NOT NULL DEFAULT(0),
|
||||
ipVersion integer NOT NULL DEFAULT(4)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IpAssignment_networkId_ip ON IpAssignment (networkId, ip);
|
||||
|
||||
CREATE INDEX IpAssignment_networkId_nodeId ON IpAssignment (networkId, nodeId);
|
||||
|
||||
CREATE TABLE IpAssignmentPool (
|
||||
networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
|
||||
ipRangeStart blob(16) NOT NULL,
|
||||
ipRangeEnd blob(16) NOT NULL,
|
||||
ipVersion integer NOT NULL DEFAULT(4)
|
||||
);
|
||||
|
||||
CREATE UNIQUE INDEX IpAssignmentPool_networkId_ipRangeStart ON IpAssignmentPool (networkId,ipRangeStart);
|
||||
|
||||
CREATE TABLE Member (
|
||||
networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
|
||||
nodeId char(10) NOT NULL REFERENCES Node(id) ON DELETE CASCADE,
|
||||
authorized integer NOT NULL DEFAULT(0),
|
||||
activeBridge integer NOT NULL DEFAULT(0),
|
||||
memberRevision integer NOT NULL DEFAULT(0),
|
||||
flags integer NOT NULL DEFAULT(0),
|
||||
lastRequestTime integer NOT NULL DEFAULT(0),
|
||||
lastPowDifficulty integer NOT NULL DEFAULT(0),
|
||||
lastPowTime integer NOT NULL DEFAULT(0),
|
||||
recentHistory blob,
|
||||
PRIMARY KEY (networkId, nodeId)
|
||||
);
|
||||
|
||||
CREATE INDEX Member_networkId_nodeId ON Member(networkId,nodeId);
|
||||
CREATE INDEX Member_networkId_activeBridge ON Member(networkId, activeBridge);
|
||||
CREATE INDEX Member_networkId_memberRevision ON Member(networkId, memberRevision);
|
||||
CREATE INDEX Member_networkId_lastRequestTime ON Member(networkId, lastRequestTime);
|
||||
|
||||
CREATE TABLE Route (
|
||||
networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
|
||||
target blob(16) NOT NULL,
|
||||
via blob(16),
|
||||
targetNetmaskBits integer NOT NULL,
|
||||
ipVersion integer NOT NULL,
|
||||
flags integer NOT NULL,
|
||||
metric integer NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX Route_networkId ON Route (networkId);
|
||||
|
||||
CREATE TABLE Rule (
|
||||
networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
|
||||
capId integer,
|
||||
ruleNo integer NOT NULL,
|
||||
ruleType integer NOT NULL DEFAULT(0),
|
||||
"addr" blob(16),
|
||||
"int1" integer,
|
||||
"int2" integer,
|
||||
"int3" integer,
|
||||
"int4" integer
|
||||
);
|
||||
|
||||
CREATE INDEX Rule_networkId_capId ON Rule (networkId,capId);
|
||||
|
||||
CREATE TABLE MemberTC (
|
||||
networkId char(16) NOT NULL REFERENCES Network(id) ON DELETE CASCADE,
|
||||
nodeId char(10) NOT NULL REFERENCES Node(id) ON DELETE CASCADE,
|
||||
tagId integer,
|
||||
tagValue integer,
|
||||
capId integer,
|
||||
capMaxCustodyChainLength integer NOT NULL DEFAULT(1)
|
||||
);
|
||||
|
||||
CREATE INDEX MemberTC_networkId_nodeId ON MemberTC (networkId,nodeId);
|
@ -1,134 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# This script builds the installer for *nix systems. Windows must do everything
|
||||
# completely differently, as usual.
|
||||
|
||||
export PATH=/bin:/usr/bin:/sbin:/usr/sbin
|
||||
|
||||
if [ ! -f zerotier-one ]; then
|
||||
echo "Could not find 'zerotier-one' binary, please build before running this script."
|
||||
exit 2
|
||||
fi
|
||||
|
||||
machine=`uname -m`
|
||||
system=`uname -s`
|
||||
|
||||
vmajor=`cat version.h | grep -F ZEROTIER_ONE_VERSION_MAJOR | cut -d ' ' -f 3`
|
||||
vminor=`cat version.h | grep -F ZEROTIER_ONE_VERSION_MINOR | cut -d ' ' -f 3`
|
||||
revision=`cat version.h | grep -F ZEROTIER_ONE_VERSION_REVISION | cut -d ' ' -f 3`
|
||||
|
||||
if [ -z "$vmajor" -o -z "$vminor" -o -z "$revision" ]; then
|
||||
echo "Unable to extract version info from version.h, aborting installer build."
|
||||
exit 2
|
||||
fi
|
||||
|
||||
rm -rf build-installer
|
||||
mkdir build-installer
|
||||
|
||||
case "$system" in
|
||||
|
||||
Linux)
|
||||
# Canonicalize $machine for some architectures... we use x86
|
||||
# and x64 for Intel stuff. ARM and others should be fine if
|
||||
# we ever ship officially for those.
|
||||
debian_arch=$machine
|
||||
case "$machine" in
|
||||
i386|i486|i586|i686)
|
||||
machine="x86"
|
||||
debian_arch="i386"
|
||||
;;
|
||||
x86_64|amd64|x64)
|
||||
machine="x64"
|
||||
debian_arch="amd64"
|
||||
;;
|
||||
armv6l|arm|armhf|arm7l|armv7l)
|
||||
machine="armv6l"
|
||||
debian_arch="armhf"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "Assembling Linux installer for $machine and version $vmajor.$vminor.$revision"
|
||||
|
||||
mkdir -p 'build-installer/var/lib/zerotier-one/ui'
|
||||
cp -fp 'ext/installfiles/linux/uninstall.sh' 'build-installer/var/lib/zerotier-one'
|
||||
cp -fp 'zerotier-one' 'build-installer/var/lib/zerotier-one'
|
||||
for f in ui/*.html ui/*.js ui/*.css ui/*.jsx ; do
|
||||
cp -fp "$f" 'build-installer/var/lib/zerotier-one/ui'
|
||||
done
|
||||
mkdir -p 'build-installer/tmp'
|
||||
cp -fp 'ext/installfiles/linux/init.d/zerotier-one' 'build-installer/tmp/init.d_zerotier-one'
|
||||
cp -fp 'ext/installfiles/linux/systemd/zerotier-one.service' 'build-installer/tmp/systemd_zerotier-one.service'
|
||||
|
||||
targ="ZeroTierOneInstaller-linux-${machine}-${vmajor}_${vminor}_${revision}"
|
||||
# Use gzip in Linux since some minimal Linux systems do not have bunzip2
|
||||
rm -f build-installer-tmp.tar.gz
|
||||
cd build-installer
|
||||
tar -cf - * | gzip -9 >../build-installer-tmp.tar.gz
|
||||
cd ..
|
||||
rm -f $targ
|
||||
cat ext/installfiles/linux/install.tmpl.sh build-installer-tmp.tar.gz >$targ
|
||||
chmod 0755 $targ
|
||||
rm -f build-installer-tmp.tar.gz
|
||||
ls -l $targ
|
||||
|
||||
if [ -f /usr/bin/dpkg-deb -a "$UID" -eq 0 ]; then
|
||||
echo
|
||||
echo Found dpkg-deb and you are root, trying to build Debian package.
|
||||
|
||||
rm -rf build-installer-deb
|
||||
|
||||
debbase="build-installer-deb/zerotier-one_${vmajor}.${vminor}.${revision}_$debian_arch"
|
||||
debfolder="${debbase}/DEBIAN"
|
||||
mkdir -p $debfolder
|
||||
|
||||
cat 'ext/installfiles/linux/DEBIAN/control.in' | sed "s/__VERSION__/${vmajor}.${vminor}.${revision}/" | sed "s/__ARCH__/${debian_arch}/" >$debfolder/control
|
||||
cat $debfolder/control
|
||||
cp -f 'ext/installfiles/linux/DEBIAN/conffiles' "${debfolder}/conffiles"
|
||||
|
||||
mkdir -p "${debbase}/var/lib/zerotier-one/updates.d"
|
||||
cp -f $targ "${debbase}/var/lib/zerotier-one/updates.d"
|
||||
|
||||
rm -f "${debfolder}/postinst" "${debfolder}/prerm"
|
||||
|
||||
echo '#!/bin/bash' >${debfolder}/postinst
|
||||
echo "/var/lib/zerotier-one/updates.d/${targ} >>/dev/null 2>&1" >>${debfolder}/postinst
|
||||
echo "/bin/rm -f /var/lib/zerotier-one/updates.d/*" >>${debfolder}/postinst
|
||||
chmod a+x ${debfolder}/postinst
|
||||
|
||||
echo '#!/bin/bash' >${debfolder}/prerm
|
||||
echo 'export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin' >>${debfolder}/prerm
|
||||
echo 'if [ "$1" != "upgrade" ]; then' >>${debfolder}/prerm
|
||||
echo ' /var/lib/zerotier-one/uninstall.sh >>/dev/null 2>&1' >>${debfolder}/prerm
|
||||
echo 'fi' >>${debfolder}/prerm
|
||||
chmod a+x ${debfolder}/prerm
|
||||
|
||||
dpkg-deb --build $debbase
|
||||
|
||||
mv -f build-installer-deb/*.deb .
|
||||
rm -rf build-installer-deb
|
||||
fi
|
||||
|
||||
if [ -f /usr/bin/rpmbuild ]; then
|
||||
echo
|
||||
echo Found rpmbuild, trying to build RedHat/CentOS package.
|
||||
|
||||
rm -f /tmp/zerotier-one.spec
|
||||
curr_dir=`pwd`
|
||||
cat ext/installfiles/linux/RPM/zerotier-one.spec.in | sed "s/__VERSION__/${vmajor}.${vminor}.${revision}/g" | sed "s/__INSTALLER__/${targ}/g" >/tmp/zerotier-one.spec
|
||||
|
||||
rpmbuild -ba /tmp/zerotier-one.spec
|
||||
|
||||
rm -f /tmp/zerotier-one.spec
|
||||
fi
|
||||
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "Unsupported platform: $system"
|
||||
exit 2
|
||||
|
||||
esac
|
||||
|
||||
rm -rf build-installer
|
||||
|
||||
exit 0
|
@ -1,182 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin
|
||||
shopt -s expand_aliases
|
||||
|
||||
dryRun=0
|
||||
|
||||
echo "*** ZeroTier One install/update ***"
|
||||
echo
|
||||
|
||||
if [ "$UID" -ne 0 ]; then
|
||||
echo "Not running as root so doing dry run (no modifications to system)..."
|
||||
dryRun=1
|
||||
fi
|
||||
|
||||
if [ $dryRun -gt 0 ]; then
|
||||
alias ln="echo '>> ln'"
|
||||
alias rm="echo '>> rm'"
|
||||
alias mv="echo '>> mv'"
|
||||
alias cp="echo '>> cp'"
|
||||
alias chown="echo '>> chown'"
|
||||
alias chgrp="echo '>> chgrp'"
|
||||
alias chmod="echo '>> chmod'"
|
||||
alias chkconfig="echo '>> chkconfig'"
|
||||
alias zerotier-cli="echo '>> zerotier-cli'"
|
||||
alias service="echo '>> service'"
|
||||
alias systemctl="echo '>> systemctl'"
|
||||
fi
|
||||
|
||||
scriptPath="`dirname "$0"`/`basename "$0"`"
|
||||
if [ ! -r "$scriptPath" ]; then
|
||||
scriptPath="$0"
|
||||
if [ ! -r "$scriptPath" ]; then
|
||||
echo "Installer cannot determine its own path; $scriptPath is not readable."
|
||||
exit 2
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check for systemd vs. old school SysV init
|
||||
SYSTEMDUNITDIR=
|
||||
if [ -e /bin/systemctl -o -e /usr/bin/systemctl -o -e /usr/local/bin/systemctl -o -e /sbin/systemctl -o -e /usr/sbin/systemctl ]; then
|
||||
# Second check: test if systemd appears to actually be running. Apparently Ubuntu
|
||||
# thought it was a good idea to ship with systemd installed but not used. Issue #133
|
||||
if [ -d /var/run/systemd/system -o -d /run/systemd/system ]; then
|
||||
if [ -e /usr/bin/pkg-config ]; then
|
||||
SYSTEMDUNITDIR=`/usr/bin/pkg-config systemd --variable=systemdsystemunitdir`
|
||||
fi
|
||||
if [ -z "$SYSTEMDUNITDIR" -o ! -d "$SYSTEMDUNITDIR" ]; then
|
||||
if [ -d /usr/lib/systemd/system ]; then
|
||||
SYSTEMDUNITDIR=/usr/lib/systemd/system
|
||||
fi
|
||||
if [ -d /etc/systemd/system ]; then
|
||||
SYSTEMDUNITDIR=/etc/systemd/system
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Find the end of this script, which is where we have appended binary data.
|
||||
endMarkerIndex=`grep -a -b -E '^################' "$scriptPath" | head -c 16 | cut -d : -f 1`
|
||||
if [ "$endMarkerIndex" -le 100 ]; then
|
||||
echo 'Internal error: unable to find end of script / start of binary data marker.'
|
||||
exit 2
|
||||
fi
|
||||
blobStart=`expr $endMarkerIndex + 17`
|
||||
if [ "$blobStart" -le "$endMarkerIndex" ]; then
|
||||
echo 'Internal error: unable to find end of script / start of binary data marker.'
|
||||
exit 2
|
||||
fi
|
||||
|
||||
echo -n 'Getting version of existing install... '
|
||||
origVersion=NONE
|
||||
if [ -x /var/lib/zerotier-one/zerotier-one ]; then
|
||||
origVersion=`/var/lib/zerotier-one/zerotier-one -v`
|
||||
fi
|
||||
echo $origVersion
|
||||
|
||||
echo 'Extracting files...'
|
||||
if [ $dryRun -gt 0 ]; then
|
||||
echo ">> tail -c +$blobStart \"$scriptPath\" | gunzip -c | tar -xvop -C / -f -"
|
||||
tail -c +$blobStart "$scriptPath" | gunzip -c | tar -t -f - | sed 's/^/>> /'
|
||||
else
|
||||
tail -c +$blobStart "$scriptPath" | gunzip -c | tar -xvop --no-overwrite-dir -C / -f -
|
||||
fi
|
||||
|
||||
if [ $dryRun -eq 0 -a ! -x "/var/lib/zerotier-one/zerotier-one" ]; then
|
||||
echo 'Archive extraction failed, cannot find zerotier-one binary in "/var/lib/zerotier-one".'
|
||||
exit 2
|
||||
fi
|
||||
|
||||
echo -n 'Getting version of new install... '
|
||||
newVersion=`/var/lib/zerotier-one/zerotier-one -v`
|
||||
echo $newVersion
|
||||
|
||||
echo 'Creating symlinks...'
|
||||
|
||||
rm -f /usr/bin/zerotier-cli /usr/bin/zerotier-idtool
|
||||
ln -sf /var/lib/zerotier-one/zerotier-one /usr/bin/zerotier-cli
|
||||
ln -sf /var/lib/zerotier-one/zerotier-one /usr/bin/zerotier-idtool
|
||||
|
||||
echo 'Installing zerotier-one service...'
|
||||
|
||||
if [ -n "$SYSTEMDUNITDIR" -a -d "$SYSTEMDUNITDIR" ]; then
|
||||
# SYSTEMD
|
||||
|
||||
# If this was updated or upgraded from an init.d based system, clean up the old
|
||||
# init.d stuff before installing directly via systemd.
|
||||
if [ -f /etc/init.d/zerotier-one ]; then
|
||||
if [ -e /sbin/chkconfig -o -e /usr/sbin/chkconfig -o -e /bin/chkconfig -o -e /usr/bin/chkconfig ]; then
|
||||
chkconfig zerotier-one off
|
||||
fi
|
||||
rm -f /etc/init.d/zerotier-one
|
||||
fi
|
||||
|
||||
cp -f /tmp/systemd_zerotier-one.service "$SYSTEMDUNITDIR/zerotier-one.service"
|
||||
chown 0 "$SYSTEMDUNITDIR/zerotier-one.service"
|
||||
chgrp 0 "$SYSTEMDUNITDIR/zerotier-one.service"
|
||||
chmod 0644 "$SYSTEMDUNITDIR/zerotier-one.service"
|
||||
rm -f /tmp/systemd_zerotier-one.service /tmp/init.d_zerotier-one
|
||||
|
||||
systemctl enable zerotier-one.service
|
||||
|
||||
echo
|
||||
echo 'Done! Installed and service configured to start at system boot.'
|
||||
echo
|
||||
echo "To start now or restart the service if it's already running:"
|
||||
echo ' sudo systemctl restart zerotier-one.service'
|
||||
else
|
||||
# SYSV INIT -- also covers upstart which supports SysVinit backward compatibility
|
||||
|
||||
cp -f /tmp/init.d_zerotier-one /etc/init.d/zerotier-one
|
||||
chmod 0755 /etc/init.d/zerotier-one
|
||||
rm -f /tmp/systemd_zerotier-one.service /tmp/init.d_zerotier-one
|
||||
|
||||
if [ -f /sbin/chkconfig -o -f /usr/sbin/chkconfig -o -f /usr/bin/chkconfig -o -f /bin/chkconfig ]; then
|
||||
chkconfig zerotier-one on
|
||||
else
|
||||
# Yes Virginia, some systems lack chkconfig.
|
||||
if [ -d /etc/rc0.d ]; then
|
||||
rm -f /etc/rc0.d/???zerotier-one
|
||||
ln -sf /etc/init.d/zerotier-one /etc/rc0.d/K89zerotier-one
|
||||
fi
|
||||
if [ -d /etc/rc1.d ]; then
|
||||
rm -f /etc/rc1.d/???zerotier-one
|
||||
ln -sf /etc/init.d/zerotier-one /etc/rc1.d/K89zerotier-one
|
||||
fi
|
||||
if [ -d /etc/rc2.d ]; then
|
||||
rm -f /etc/rc2.d/???zerotier-one
|
||||
ln -sf /etc/init.d/zerotier-one /etc/rc2.d/S11zerotier-one
|
||||
fi
|
||||
if [ -d /etc/rc3.d ]; then
|
||||
rm -f /etc/rc3.d/???zerotier-one
|
||||
ln -sf /etc/init.d/zerotier-one /etc/rc3.d/S11zerotier-one
|
||||
fi
|
||||
if [ -d /etc/rc4.d ]; then
|
||||
rm -f /etc/rc4.d/???zerotier-one
|
||||
ln -sf /etc/init.d/zerotier-one /etc/rc4.d/S11zerotier-one
|
||||
fi
|
||||
if [ -d /etc/rc5.d ]; then
|
||||
rm -f /etc/rc5.d/???zerotier-one
|
||||
ln -sf /etc/init.d/zerotier-one /etc/rc5.d/S11zerotier-one
|
||||
fi
|
||||
if [ -d /etc/rc6.d ]; then
|
||||
rm -f /etc/rc6.d/???zerotier-one
|
||||
ln -sf /etc/init.d/zerotier-one /etc/rc6.d/K89zerotier-one
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
echo 'Done! Installed and service configured to start at system boot.'
|
||||
echo
|
||||
echo "To start now or restart the service if it's already running:"
|
||||
echo ' sudo service zerotier-one restart'
|
||||
fi
|
||||
|
||||
exit 0
|
||||
|
||||
# Do not remove the last line or add a carriage return to it! The installer
|
||||
# looks for an unterminated line beginning with 16 #'s in itself to find
|
||||
# the binary blob data, which is appended after it.
|
||||
|
||||
################
|
@ -1,76 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
export PATH=/bin:/usr/bin:/sbin:/usr/sbin:/usr/local/bin:/usr/local/sbin
|
||||
|
||||
if [ "$UID" -ne 0 ]; then
|
||||
echo "Must be run as root; try: sudo $0"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Detect systemd vs. regular init
|
||||
SYSTEMDUNITDIR=
|
||||
if [ -e /bin/systemctl -o -e /usr/bin/systemctl -o -e /usr/local/bin/systemctl -o -e /sbin/systemctl -o -e /usr/sbin/systemctl ]; then
|
||||
if [ -e /usr/bin/pkg-config ]; then
|
||||
SYSTEMDUNITDIR=`/usr/bin/pkg-config systemd --variable=systemdsystemunitdir`
|
||||
fi
|
||||
if [ -z "$SYSTEMDUNITDIR" -o ! -d "$SYSTEMDUNITDIR" ]; then
|
||||
if [ -d /usr/lib/systemd/system ]; then
|
||||
SYSTEMDUNITDIR=/usr/lib/systemd/system
|
||||
fi
|
||||
if [ -d /etc/systemd/system ]; then
|
||||
SYSTEMDUNITDIR=/etc/systemd/system
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Killing any running zerotier-one service..."
|
||||
if [ -n "$SYSTEMDUNITDIR" -a -d "$SYSTEMDUNITDIR" ]; then
|
||||
systemctl stop zerotier-one.service
|
||||
systemctl disable zerotier-one.service
|
||||
else
|
||||
if [ -f /sbin/service -o -f /usr/sbin/service -o -f /bin/service -o -f /usr/bin/service ]; then
|
||||
service zerotier-one stop
|
||||
fi
|
||||
fi
|
||||
|
||||
sleep 1
|
||||
if [ -f /var/lib/zerotier-one/zerotier-one.pid ]; then
|
||||
kill -TERM `cat /var/lib/zerotier-one/zerotier-one.pid`
|
||||
sleep 1
|
||||
fi
|
||||
if [ -f /var/lib/zerotier-one/zerotier-one.pid ]; then
|
||||
kill -KILL `cat /var/lib/zerotier-one/zerotier-one.pid`
|
||||
fi
|
||||
|
||||
if [ -f /etc/init.d/zerotier-one ]; then
|
||||
echo "Removing SysV init items..."
|
||||
if [ -f /sbin/chkconfig -o -f /usr/sbin/chkconfig -o -f /bin/chkconfig -o -f /usr/bin/chkconfig ]; then
|
||||
chkconfig zerotier-one off
|
||||
fi
|
||||
rm -f /etc/init.d/zerotier-one
|
||||
find /etc/rc*.d -type f -name '???zerotier-one' -print0 | xargs -0 rm -f
|
||||
fi
|
||||
|
||||
if [ -n "$SYSTEMDUNITDIR" -a -d "$SYSTEMDUNITDIR" -a -f "$SYSTEMDUNITDIR/zerotier-one.service" ]; then
|
||||
echo "Removing systemd service..."
|
||||
rm -f "$SYSTEMDUNITDIR/zerotier-one.service"
|
||||
fi
|
||||
|
||||
echo "Erasing binary and support files..."
|
||||
if [ -d /var/lib/zerotier-one ]; then
|
||||
cd /var/lib/zerotier-one
|
||||
rm -rf zerotier-one *.persist identity.public *.log *.pid *.sh updates.d networks.d iddb.d root-topology ui
|
||||
fi
|
||||
|
||||
echo "Erasing anything installed into system bin directories..."
|
||||
rm -f /usr/local/bin/zerotier-cli /usr/bin/zerotier-cli /usr/local/bin/zerotier-idtool /usr/bin/zerotier-idtool
|
||||
|
||||
echo "Done."
|
||||
echo
|
||||
echo "Your ZeroTier One identity is still preserved in /var/lib/zerotier-one"
|
||||
echo "as identity.secret and can be manually deleted if you wish. Save it if"
|
||||
echo "you wish to re-use the address of this node, as it cannot be regenerated."
|
||||
|
||||
echo
|
||||
|
||||
exit 0
|
@ -1,8 +0,0 @@
|
||||
Root Server Watcher
|
||||
======
|
||||
|
||||
This is a small daemon written in NodeJS that watches a set of root servers and records peer status information into a Postgres database.
|
||||
|
||||
To use type `npm install` to install modules. Then edit `config.json.example` and rename to `config.json`. For each of your roots you will need to configure a way for this script to reach it. You will also need to use `schema.sql` to initialize a Postgres database to contain your logs and set it up in `config.json` as well.
|
||||
|
||||
This doesn't (yet) include any software for reading the log database and doing anything useful with the information inside, though given that it's a simple SQL database it should not be hard to compose queries to show interesting statistics.
|
@ -1,30 +0,0 @@
|
||||
{
|
||||
"interval": 30000,
|
||||
"dbSaveInterval": 60000,
|
||||
"peerTimeout": 600000,
|
||||
"db": {
|
||||
"database": "ztr",
|
||||
"user": "postgres",
|
||||
"password": "s00p3rs3kr3t",
|
||||
"host": "127.0.0.1",
|
||||
"port": 5432,
|
||||
"max": 16,
|
||||
"idleTimeoutMillis": 30000
|
||||
},
|
||||
"roots": {
|
||||
"my-root-01": {
|
||||
"id": 1,
|
||||
"ip": "10.0.0.1",
|
||||
"port": 9993,
|
||||
"authToken": "foobarbaz",
|
||||
"peers": "/peer"
|
||||
},
|
||||
"my-root-02": {
|
||||
"id": 2,
|
||||
"ip": "10.0.0.2",
|
||||
"port": 9993,
|
||||
"authToken": "lalafoo",
|
||||
"peers": "/peer"
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
{
|
||||
"name": "zerotier-root-watcher",
|
||||
"version": "1.0.0",
|
||||
"description": "Simple background service to watch a cluster of roots and record peer info into a database",
|
||||
"main": "zerotier-root-watcher.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"author": "ZeroTier, Inc. <contact@zerotier.com>",
|
||||
"license": "GPL-3.0",
|
||||
"dependencies": {
|
||||
"async": "^2.3.0",
|
||||
"pg": "^6.1.5",
|
||||
"zlib": "^1.0.5"
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
/* Schema for ZeroTier root watcher log database */
|
||||
|
||||
CREATE TABLE "Peer"
|
||||
(
|
||||
"ztAddress" BIGINT NOT NULL,
|
||||
"timestamp" BIGINT NOT NULL,
|
||||
"versionMajor" INTEGER NOT NULL,
|
||||
"versionMinor" INTEGER NOT NULL,
|
||||
"versionRev" INTEGER NOT NULL,
|
||||
"rootId" INTEGER NOT NULL,
|
||||
"phyPort" INTEGER NOT NULL,
|
||||
"phyLinkQuality" REAL NOT NULL,
|
||||
"phyLastReceive" BIGINT NOT NULL,
|
||||
"phyAddress" INET NOT NULL
|
||||
);
|
||||
|
||||
CREATE INDEX "Peer_ztAddress" ON "Peer" ("ztAddress");
|
||||
CREATE INDEX "Peer_timestamp" ON "Peer" ("timestamp");
|
||||
CREATE INDEX "Peer_rootId" ON "Peer" ("rootId");
|
||||
CREATE INDEX "Peer_phyAddress" ON "Peer" ("phyAddress");
|
@ -1,235 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
const pg = require('pg');
|
||||
const zlib = require('zlib');
|
||||
const http = require('http');
|
||||
const fs = require('fs');
|
||||
const async = require('async');
|
||||
|
||||
const config = JSON.parse(fs.readFileSync('./config.json'));
|
||||
const roots = config.roots||{};
|
||||
|
||||
const db = new pg.Pool(config.db);
|
||||
|
||||
process.on('uncaughtException',function(err) {
|
||||
console.error('ERROR: uncaught exception: '+err);
|
||||
if (err.stack)
|
||||
console.error(err.stack);
|
||||
});
|
||||
|
||||
function httpRequest(host,port,authToken,method,path,args,callback)
|
||||
{
|
||||
var responseBody = [];
|
||||
var postData = (args) ? JSON.stringify(args) : null;
|
||||
|
||||
var req = http.request({
|
||||
host: host,
|
||||
port: port,
|
||||
path: path,
|
||||
method: method,
|
||||
headers: {
|
||||
'X-ZT1-Auth': (authToken||''),
|
||||
'Content-Length': (postData) ? postData.length : 0
|
||||
}
|
||||
},function(res) {
|
||||
res.on('data',function(chunk) {
|
||||
if ((chunk)&&(chunk.length > 0))
|
||||
responseBody.push(chunk);
|
||||
});
|
||||
res.on('timeout',function() {
|
||||
try {
|
||||
if (typeof callback === 'function') {
|
||||
var cb = callback;
|
||||
callback = null;
|
||||
cb(new Error('connection timed out'),null);
|
||||
}
|
||||
req.abort();
|
||||
} catch (e) {}
|
||||
});
|
||||
res.on('error',function(e) {
|
||||
try {
|
||||
if (typeof callback === 'function') {
|
||||
var cb = callback;
|
||||
callback = null;
|
||||
cb(new Error('connection timed out'),null);
|
||||
}
|
||||
req.abort();
|
||||
} catch (e) {}
|
||||
});
|
||||
res.on('end',function() {
|
||||
if (typeof callback === 'function') {
|
||||
var cb = callback;
|
||||
callback = null;
|
||||
if (responseBody.length === 0) {
|
||||
return cb(null,{});
|
||||
} else {
|
||||
responseBody = Buffer.concat(responseBody);
|
||||
|
||||
if (responseBody.length < 2) {
|
||||
return cb(null,{});
|
||||
}
|
||||
|
||||
if ((responseBody.readUInt8(0,true) === 0x1f)&&(responseBody.readUInt8(1,true) === 0x8b)) {
|
||||
try {
|
||||
responseBody = zlib.gunzipSync(responseBody);
|
||||
} catch (e) {
|
||||
return cb(e,null);
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return cb(null,JSON.parse(responseBody));
|
||||
} catch (e) {
|
||||
return cb(e,null);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}).on('error',function(e) {
|
||||
try {
|
||||
if (typeof callback === 'function') {
|
||||
var cb = callback;
|
||||
callback = null;
|
||||
cb(e,null);
|
||||
}
|
||||
req.abort();
|
||||
} catch (e) {}
|
||||
}).on('timeout',function() {
|
||||
try {
|
||||
if (typeof callback === 'function') {
|
||||
var cb = callback;
|
||||
callback = null;
|
||||
cb(new Error('connection timed out'),null);
|
||||
}
|
||||
req.abort();
|
||||
} catch (e) {}
|
||||
});
|
||||
|
||||
req.setTimeout(30000);
|
||||
req.setNoDelay(true);
|
||||
|
||||
if (postData !== null)
|
||||
req.end(postData);
|
||||
else req.end();
|
||||
};
|
||||
|
||||
var peerStatus = {};
|
||||
|
||||
function saveToDb()
|
||||
{
|
||||
db.connect(function(err,client,clientDone) {
|
||||
if (err) {
|
||||
console.log('WARNING: database error writing peers: '+err.toString());
|
||||
clientDone();
|
||||
return setTimeout(saveToDb,config.dbSaveInterval||60000);
|
||||
}
|
||||
client.query('BEGIN',function(err) {
|
||||
if (err) {
|
||||
console.log('WARNING: database error writing peers: '+err.toString());
|
||||
clientDone();
|
||||
return setTimeout(saveToDb,config.dbSaveInterval||60000);
|
||||
}
|
||||
let timeout = Date.now() - (config.peerTimeout||600000);
|
||||
let wtotal = 0;
|
||||
async.eachSeries(Object.keys(peerStatus),function(address,nextAddress) {
|
||||
let s = peerStatus[address];
|
||||
if (s[1] <= timeout) {
|
||||
delete peerStatus[address];
|
||||
return process.nextTick(nextAddress);
|
||||
} else {
|
||||
++wtotal;
|
||||
client.query('INSERT INTO "Peer" ("ztAddress","timestamp","versionMajor","versionMinor","versionRev","rootId","phyPort","phyLinkQuality","phyLastReceive","phyAddress") VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10)',s,nextAddress);
|
||||
}
|
||||
},function(err) {
|
||||
if (err)
|
||||
console.log('WARNING database error writing peers: '+err.toString());
|
||||
console.log(Date.now().toString()+' '+wtotal);
|
||||
client.query('COMMIT',function(err,result) {
|
||||
clientDone();
|
||||
return setTimeout(saveToDb,config.dbSaveInterval||60000);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
function doRootUpdate(name,id,ip,port,peersPath,authToken,interval)
|
||||
{
|
||||
httpRequest(ip,port,authToken,"GET",peersPath,null,function(err,res) {
|
||||
if (err) {
|
||||
console.log('WARNING: cannot reach '+name+peersPath+' (will try again in 1s): '+err.toString());
|
||||
return setTimeout(function() { doRootUpdate(name,id,ip,port,peersPath,authToken,interval); },1000);
|
||||
}
|
||||
if (!Array.isArray(res)) {
|
||||
console.log('WARNING: cannot reach '+name+peersPath+' (will try again in 1s): response is not an array of peers');
|
||||
return setTimeout(function() { doRootUpdate(name,id,ip,port,peersPath,authToken,interval); },1000);
|
||||
}
|
||||
|
||||
//console.log(name+': '+res.length+' peer entries.');
|
||||
let now = Date.now();
|
||||
let count = 0;
|
||||
for(let pi=0;pi<res.length;++pi) {
|
||||
let peer = res[pi];
|
||||
let address = peer.address;
|
||||
let ztAddress = parseInt(address,16)||0;
|
||||
if (!ztAddress)
|
||||
continue;
|
||||
|
||||
let paths = peer.paths;
|
||||
if ((Array.isArray(paths))&&(paths.length > 0)) {
|
||||
let bestPath = null;
|
||||
for(let i=0;i<paths.length;++i) {
|
||||
if (paths[i].active) {
|
||||
let lr = paths[i].lastReceive;
|
||||
if ((lr > 0)&&((!bestPath)||(bestPath.lastReceive < lr)))
|
||||
bestPath = paths[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (bestPath) {
|
||||
let a = bestPath.address;
|
||||
if (typeof a === 'string') {
|
||||
let a2 = a.split('/');
|
||||
if (a2.length === 2) {
|
||||
let vmaj = peer.versionMajor;
|
||||
if ((typeof vmaj === 'undefined')||(vmaj === null)) vmaj = -1;
|
||||
let vmin = peer.versionMinor;
|
||||
if ((typeof vmin === 'undefined')||(vmin === null)) vmin = -1;
|
||||
let vrev = peer.versionRev;
|
||||
if ((typeof vrev === 'undefined')||(vrev === null)) vrev = -1;
|
||||
let lr = parseInt(bestPath.lastReceive)||0;
|
||||
|
||||
let s = peerStatus[address];
|
||||
if ((!s)||(s[8] < lr)) {
|
||||
peerStatus[address] = [
|
||||
ztAddress,
|
||||
now,
|
||||
vmaj,
|
||||
vmin,
|
||||
vrev,
|
||||
id,
|
||||
parseInt(a2[1])||0,
|
||||
parseFloat(bestPath.linkQuality)||1.0,
|
||||
lr,
|
||||
a2[0]
|
||||
];
|
||||
}
|
||||
++count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(name+': '+count+' peers with active direct paths.');
|
||||
return setTimeout(function() { doRootUpdate(name,id,ip,port,peersPath,authToken,interval); },interval);
|
||||
});
|
||||
};
|
||||
|
||||
for(var r in roots) {
|
||||
var rr = roots[r];
|
||||
if (rr.peers)
|
||||
doRootUpdate(r,rr.id,rr.ip,rr.port,rr.peers,rr.authToken||null,config.interval||60000);
|
||||
}
|
||||
|
||||
return setTimeout(saveToDb,config.dbSaveInterval||60000);
|
@ -1,7 +0,0 @@
|
||||
CXX=$(shell which clang++ g++ c++ 2>/dev/null | head -n 1)
|
||||
|
||||
all:
|
||||
$(CXX) -O3 -fno-rtti -o tcp-proxy tcp-proxy.cpp
|
||||
|
||||
clean:
|
||||
rm -f *.o tcp-proxy *.dSYM
|
@ -1,4 +0,0 @@
|
||||
TCP Proxy Server
|
||||
======
|
||||
|
||||
This is the TCP proxy server we run for TCP tunneling from peers behind fascist NATs. Regular users won't have much use for this.
|
@ -1,317 +0,0 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// HACK! Will eventually use epoll() or something in Phy<> instead of select().
|
||||
// Also be sure to change ulimit -n and fs.file-max in /etc/sysctl.conf on relays.
|
||||
#if defined(__linux__) || defined(__LINUX__) || defined(__LINUX) || defined(LINUX)
|
||||
#include <linux/posix_types.h>
|
||||
#include <bits/types.h>
|
||||
#undef __FD_SETSIZE
|
||||
#define __FD_SETSIZE 1048576
|
||||
#undef FD_SETSIZE
|
||||
#define FD_SETSIZE 1048576
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "../osdep/Phy.hpp"
|
||||
|
||||
#define ZT_TCP_PROXY_CONNECTION_TIMEOUT_SECONDS 300
|
||||
#define ZT_TCP_PROXY_TCP_PORT 443
|
||||
|
||||
using namespace ZeroTier;
|
||||
|
||||
/*
|
||||
* ZeroTier TCP Proxy Server
|
||||
*
|
||||
* This implements a simple packet encapsulation that is designed to look like
|
||||
* a TLS connection. It's not a TLS connection, but it sends TLS format record
|
||||
* headers. It could be extended in the future to implement a fake TLS
|
||||
* handshake.
|
||||
*
|
||||
* At the moment, each packet is just made to look like TLS application data:
|
||||
* <[1] TLS content type> - currently 0x17 for "application data"
|
||||
* <[1] TLS major version> - currently 0x03 for TLS 1.2
|
||||
* <[1] TLS minor version> - currently 0x03 for TLS 1.2
|
||||
* <[2] payload length> - 16-bit length of payload in bytes
|
||||
* <[...] payload> - Message payload
|
||||
*
|
||||
* TCP is inherently inefficient for encapsulating Ethernet, since TCP and TCP
|
||||
* like protocols over TCP lead to double-ACKs. So this transport is only used
|
||||
* to enable access when UDP or other datagram protocols are not available.
|
||||
*
|
||||
* Clients send a greeting, which is a four-byte message that contains:
|
||||
* <[1] ZeroTier major version>
|
||||
* <[1] minor version>
|
||||
* <[2] revision>
|
||||
*
|
||||
* If a client has sent a greeting, it uses the new version of this protocol
|
||||
* in which every encapsulated ZT packet is prepended by an IP address where
|
||||
* it should be forwarded (or where it came from for replies). This causes
|
||||
* this proxy to act as a remote UDP socket similar to a socks proxy, which
|
||||
* will allow us to move this function off the rootservers and onto dedicated
|
||||
* proxy nodes.
|
||||
*
|
||||
* Older ZT clients that do not send this message get their packets relayed
|
||||
* to/from 127.0.0.1:9993, which will allow them to talk to and relay via
|
||||
* the ZT node on the same machine as the proxy. We'll only support this for
|
||||
* as long as such nodes appear to be in the wild.
|
||||
*/
|
||||
|
||||
struct TcpProxyService;
|
||||
struct TcpProxyService
|
||||
{
|
||||
Phy<TcpProxyService *> *phy;
|
||||
int udpPortCounter;
|
||||
struct Client
|
||||
{
|
||||
char tcpReadBuf[131072];
|
||||
char tcpWriteBuf[131072];
|
||||
unsigned long tcpWritePtr;
|
||||
unsigned long tcpReadPtr;
|
||||
PhySocket *tcp;
|
||||
PhySocket *udp;
|
||||
time_t lastActivity;
|
||||
bool newVersion;
|
||||
};
|
||||
std::map< PhySocket *,Client > clients;
|
||||
|
||||
PhySocket *getUnusedUdp(void *uptr)
|
||||
{
|
||||
for(int i=0;i<65535;++i) {
|
||||
++udpPortCounter;
|
||||
if (udpPortCounter > 0xfffe)
|
||||
udpPortCounter = 1024;
|
||||
struct sockaddr_in laddr;
|
||||
memset(&laddr,0,sizeof(struct sockaddr_in));
|
||||
laddr.sin_family = AF_INET;
|
||||
laddr.sin_port = htons((uint16_t)udpPortCounter);
|
||||
PhySocket *udp = phy->udpBind(reinterpret_cast<struct sockaddr *>(&laddr),uptr);
|
||||
if (udp)
|
||||
return udp;
|
||||
}
|
||||
return (PhySocket *)0;
|
||||
}
|
||||
|
||||
void phyOnDatagram(PhySocket *sock,void **uptr,const struct sockaddr *localAddr,const struct sockaddr *from,void *data,unsigned long len)
|
||||
{
|
||||
if (!*uptr)
|
||||
return;
|
||||
if ((from->sa_family == AF_INET)&&(len >= 16)&&(len < 2048)) {
|
||||
Client &c = *((Client *)*uptr);
|
||||
c.lastActivity = time((time_t *)0);
|
||||
|
||||
unsigned long mlen = len;
|
||||
if (c.newVersion)
|
||||
mlen += 7; // new clients get IP info
|
||||
|
||||
if ((c.tcpWritePtr + 5 + mlen) <= sizeof(c.tcpWriteBuf)) {
|
||||
if (!c.tcpWritePtr)
|
||||
phy->setNotifyWritable(c.tcp,true);
|
||||
|
||||
c.tcpWriteBuf[c.tcpWritePtr++] = 0x17; // look like TLS data
|
||||
c.tcpWriteBuf[c.tcpWritePtr++] = 0x03; // look like TLS 1.2
|
||||
c.tcpWriteBuf[c.tcpWritePtr++] = 0x03; // look like TLS 1.2
|
||||
|
||||
c.tcpWriteBuf[c.tcpWritePtr++] = (char)((mlen >> 8) & 0xff);
|
||||
c.tcpWriteBuf[c.tcpWritePtr++] = (char)(mlen & 0xff);
|
||||
|
||||
if (c.newVersion) {
|
||||
c.tcpWriteBuf[c.tcpWritePtr++] = (char)4; // IPv4
|
||||
*((uint32_t *)(c.tcpWriteBuf + c.tcpWritePtr)) = ((const struct sockaddr_in *)from)->sin_addr.s_addr;
|
||||
c.tcpWritePtr += 4;
|
||||
*((uint16_t *)(c.tcpWriteBuf + c.tcpWritePtr)) = ((const struct sockaddr_in *)from)->sin_port;
|
||||
c.tcpWritePtr += 2;
|
||||
}
|
||||
|
||||
for(unsigned long i=0;i<len;++i)
|
||||
c.tcpWriteBuf[c.tcpWritePtr++] = ((const char *)data)[i];
|
||||
}
|
||||
|
||||
//printf("<< UDP %s:%d -> %.16llx\n",inet_ntoa(reinterpret_cast<const struct sockaddr_in *>(from)->sin_addr),(int)ntohs(reinterpret_cast<const struct sockaddr_in *>(from)->sin_port),(unsigned long long)&c);
|
||||
}
|
||||
}
|
||||
|
||||
void phyOnTcpConnect(PhySocket *sock,void **uptr,bool success)
|
||||
{
|
||||
// unused, we don't initiate outbound connections
|
||||
}
|
||||
|
||||
void phyOnTcpAccept(PhySocket *sockL,PhySocket *sockN,void **uptrL,void **uptrN,const struct sockaddr *from)
|
||||
{
|
||||
Client &c = clients[sockN];
|
||||
PhySocket *udp = getUnusedUdp((void *)&c);
|
||||
if (!udp) {
|
||||
phy->close(sockN);
|
||||
clients.erase(sockN);
|
||||
//printf("** TCP rejected, no more UDP ports to assign\n");
|
||||
return;
|
||||
}
|
||||
c.tcpWritePtr = 0;
|
||||
c.tcpReadPtr = 0;
|
||||
c.tcp = sockN;
|
||||
c.udp = udp;
|
||||
c.lastActivity = time((time_t *)0);
|
||||
c.newVersion = false;
|
||||
*uptrN = (void *)&c;
|
||||
//printf("<< TCP from %s -> %.16llx\n",inet_ntoa(reinterpret_cast<const struct sockaddr_in *>(from)->sin_addr),(unsigned long long)&c);
|
||||
}
|
||||
|
||||
void phyOnTcpClose(PhySocket *sock,void **uptr)
|
||||
{
|
||||
if (!*uptr)
|
||||
return;
|
||||
Client &c = *((Client *)*uptr);
|
||||
phy->close(c.udp);
|
||||
clients.erase(sock);
|
||||
//printf("** TCP %.16llx closed\n",(unsigned long long)*uptr);
|
||||
}
|
||||
|
||||
void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len)
|
||||
{
|
||||
Client &c = *((Client *)*uptr);
|
||||
c.lastActivity = time((time_t *)0);
|
||||
|
||||
for(unsigned long i=0;i<len;++i) {
|
||||
if (c.tcpReadPtr >= sizeof(c.tcpReadBuf)) {
|
||||
phy->close(sock);
|
||||
return;
|
||||
}
|
||||
c.tcpReadBuf[c.tcpReadPtr++] = ((const char *)data)[i];
|
||||
|
||||
if (c.tcpReadPtr >= 5) {
|
||||
unsigned long mlen = ( ((((unsigned long)c.tcpReadBuf[3]) & 0xff) << 8) | (((unsigned long)c.tcpReadBuf[4]) & 0xff) );
|
||||
if (c.tcpReadPtr >= (mlen + 5)) {
|
||||
if (mlen == 4) {
|
||||
// Right now just sending this means the client is 'new enough' for the IP header
|
||||
c.newVersion = true;
|
||||
//printf("<< TCP %.16llx HELLO\n",(unsigned long long)*uptr);
|
||||
} else if (mlen >= 7) {
|
||||
char *payload = c.tcpReadBuf + 5;
|
||||
unsigned long payloadLen = mlen;
|
||||
|
||||
struct sockaddr_in dest;
|
||||
memset(&dest,0,sizeof(dest));
|
||||
if (c.newVersion) {
|
||||
if (*payload == (char)4) {
|
||||
// New clients tell us where their packets go.
|
||||
++payload;
|
||||
dest.sin_family = AF_INET;
|
||||
dest.sin_addr.s_addr = *((uint32_t *)payload);
|
||||
payload += 4;
|
||||
dest.sin_port = *((uint16_t *)payload); // will be in network byte order already
|
||||
payload += 2;
|
||||
payloadLen -= 7;
|
||||
}
|
||||
} else {
|
||||
// For old clients we will just proxy everything to a local ZT instance. The
|
||||
// fact that this will come from 127.0.0.1 will in turn prevent that instance
|
||||
// from doing unite() with us. It'll just forward. There will not be many of
|
||||
// these.
|
||||
dest.sin_family = AF_INET;
|
||||
dest.sin_addr.s_addr = htonl(0x7f000001); // 127.0.0.1
|
||||
dest.sin_port = htons(9993);
|
||||
}
|
||||
|
||||
// Note: we do not relay to privileged ports... just an abuse prevention rule.
|
||||
if ((ntohs(dest.sin_port) > 1024)&&(payloadLen >= 16)) {
|
||||
phy->udpSend(c.udp,(const struct sockaddr *)&dest,payload,payloadLen);
|
||||
//printf(">> TCP %.16llx to %s:%d\n",(unsigned long long)*uptr,inet_ntoa(dest.sin_addr),(int)ntohs(dest.sin_port));
|
||||
}
|
||||
}
|
||||
|
||||
memmove(c.tcpReadBuf,c.tcpReadBuf + (mlen + 5),c.tcpReadPtr -= (mlen + 5));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void phyOnTcpWritable(PhySocket *sock,void **uptr)
|
||||
{
|
||||
Client &c = *((Client *)*uptr);
|
||||
if (c.tcpWritePtr) {
|
||||
long n = phy->streamSend(sock,c.tcpWriteBuf,c.tcpWritePtr);
|
||||
if (n > 0) {
|
||||
memmove(c.tcpWriteBuf,c.tcpWriteBuf + n,c.tcpWritePtr -= (unsigned long)n);
|
||||
if (!c.tcpWritePtr)
|
||||
phy->setNotifyWritable(sock,false);
|
||||
}
|
||||
} else phy->setNotifyWritable(sock,false);
|
||||
}
|
||||
|
||||
void doHousekeeping()
|
||||
{
|
||||
std::vector<PhySocket *> toClose;
|
||||
time_t now = time((time_t *)0);
|
||||
for(std::map< PhySocket *,Client >::iterator c(clients.begin());c!=clients.end();++c) {
|
||||
if ((now - c->second.lastActivity) >= ZT_TCP_PROXY_CONNECTION_TIMEOUT_SECONDS) {
|
||||
toClose.push_back(c->first);
|
||||
toClose.push_back(c->second.udp);
|
||||
}
|
||||
}
|
||||
for(std::vector<PhySocket *>::iterator s(toClose.begin());s!=toClose.end();++s)
|
||||
phy->close(*s);
|
||||
}
|
||||
};
|
||||
|
||||
int main(int argc,char **argv)
|
||||
{
|
||||
signal(SIGPIPE,SIG_IGN);
|
||||
signal(SIGHUP,SIG_IGN);
|
||||
srand(time((time_t *)0));
|
||||
|
||||
TcpProxyService svc;
|
||||
Phy<TcpProxyService *> phy(&svc,false,true);
|
||||
svc.phy = &phy;
|
||||
svc.udpPortCounter = 1023;
|
||||
|
||||
{
|
||||
struct sockaddr_in laddr;
|
||||
memset(&laddr,0,sizeof(laddr));
|
||||
laddr.sin_family = AF_INET;
|
||||
laddr.sin_port = htons(ZT_TCP_PROXY_TCP_PORT);
|
||||
if (!phy.tcpListen((const struct sockaddr *)&laddr)) {
|
||||
fprintf(stderr,"%s: fatal error: unable to bind TCP port %d\n",argv[0],ZT_TCP_PROXY_TCP_PORT);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
time_t lastDidHousekeeping = time((time_t *)0);
|
||||
for(;;) {
|
||||
phy.poll(120000);
|
||||
time_t now = time((time_t *)0);
|
||||
if ((now - lastDidHousekeeping) > 120) {
|
||||
lastDidHousekeeping = now;
|
||||
svc.doHousekeeping();
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -27,6 +27,76 @@ using json = nlohmann::json;
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
void DB::initNetwork(nlohmann::json &network)
|
||||
{
|
||||
if (!network.count("private")) network["private"] = true;
|
||||
if (!network.count("creationTime")) network["creationTime"] = OSUtils::now();
|
||||
if (!network.count("name")) network["name"] = "";
|
||||
if (!network.count("multicastLimit")) network["multicastLimit"] = (uint64_t)32;
|
||||
if (!network.count("enableBroadcast")) network["enableBroadcast"] = true;
|
||||
if (!network.count("v4AssignMode")) network["v4AssignMode"] = {{"zt",false}};
|
||||
if (!network.count("v6AssignMode")) network["v6AssignMode"] = {{"rfc4193",false},{"zt",false},{"6plane",false}};
|
||||
if (!network.count("authTokens")) network["authTokens"] = {{}};
|
||||
if (!network.count("capabilities")) network["capabilities"] = nlohmann::json::array();
|
||||
if (!network.count("tags")) network["tags"] = nlohmann::json::array();
|
||||
if (!network.count("routes")) network["routes"] = nlohmann::json::array();
|
||||
if (!network.count("ipAssignmentPools")) network["ipAssignmentPools"] = nlohmann::json::array();
|
||||
if (!network.count("anchors")) network["anchors"] = nlohmann::json::array();
|
||||
if (!network.count("mtu")) network["mtu"] = ZT_DEFAULT_MTU;
|
||||
if (!network.count("remoteTraceTarget")) network["remoteTraceTarget"] = nlohmann::json();
|
||||
if (!network.count("removeTraceLevel")) network["remoteTraceLevel"] = 0;
|
||||
if (!network.count("rules")) {
|
||||
// If unspecified, rules are set to allow anything and behave like a flat L2 segment
|
||||
network["rules"] = {{
|
||||
{ "not",false },
|
||||
{ "or", false },
|
||||
{ "type","ACTION_ACCEPT" }
|
||||
}};
|
||||
}
|
||||
network["objtype"] = "network";
|
||||
}
|
||||
|
||||
void DB::initMember(nlohmann::json &member)
|
||||
{
|
||||
if (!member.count("authorized")) member["authorized"] = false;
|
||||
if (!member.count("ipAssignments")) member["ipAssignments"] = nlohmann::json::array();
|
||||
if (!member.count("activeBridge")) member["activeBridge"] = false;
|
||||
if (!member.count("tags")) member["tags"] = nlohmann::json::array();
|
||||
if (!member.count("capabilities")) member["capabilities"] = nlohmann::json::array();
|
||||
if (!member.count("creationTime")) member["creationTime"] = OSUtils::now();
|
||||
if (!member.count("noAutoAssignIps")) member["noAutoAssignIps"] = false;
|
||||
if (!member.count("revision")) member["revision"] = 0ULL;
|
||||
if (!member.count("lastDeauthorizedTime")) member["lastDeauthorizedTime"] = 0ULL;
|
||||
if (!member.count("lastAuthorizedTime")) member["lastAuthorizedTime"] = 0ULL;
|
||||
if (!member.count("lastAuthorizedCredentialType")) member["lastAuthorizedCredentialType"] = nlohmann::json();
|
||||
if (!member.count("lastAuthorizedCredential")) member["lastAuthorizedCredential"] = nlohmann::json();
|
||||
if (!member.count("vMajor")) member["vMajor"] = -1;
|
||||
if (!member.count("vMinor")) member["vMinor"] = -1;
|
||||
if (!member.count("vRev")) member["vRev"] = -1;
|
||||
if (!member.count("vProto")) member["vProto"] = -1;
|
||||
if (!member.count("remoteTraceTarget")) member["remoteTraceTarget"] = nlohmann::json();
|
||||
if (!member.count("removeTraceLevel")) member["remoteTraceLevel"] = 0;
|
||||
member["objtype"] = "member";
|
||||
}
|
||||
|
||||
void DB::cleanNetwork(nlohmann::json &network)
|
||||
{
|
||||
network.erase("clock");
|
||||
network.erase("authorizedMemberCount");
|
||||
network.erase("activeMemberCount");
|
||||
network.erase("totalMemberCount");
|
||||
network.erase("lastModified");
|
||||
}
|
||||
|
||||
void DB::cleanMember(nlohmann::json &member)
|
||||
{
|
||||
member.erase("clock");
|
||||
member.erase("physicalAddr");
|
||||
member.erase("recentLog");
|
||||
member.erase("lastModified");
|
||||
member.erase("lastRequestMetaData");
|
||||
}
|
||||
|
||||
DB::DB(EmbeddedNetworkController *const nc,const Identity &myId,const char *path) :
|
||||
_controller(nc),
|
||||
_myId(myId),
|
||||
|
@ -58,6 +58,26 @@ public:
|
||||
int64_t mostRecentDeauthTime;
|
||||
};
|
||||
|
||||
/**
|
||||
* Ensure that all network fields are present
|
||||
*/
|
||||
static void initNetwork(nlohmann::json &network);
|
||||
|
||||
/**
|
||||
* Ensure that all member fields are present
|
||||
*/
|
||||
static void initMember(nlohmann::json &member);
|
||||
|
||||
/**
|
||||
* Remove old and temporary network fields
|
||||
*/
|
||||
static void cleanNetwork(nlohmann::json &network);
|
||||
|
||||
/**
|
||||
* Remove old and temporary member fields
|
||||
*/
|
||||
static void cleanMember(nlohmann::json &member);
|
||||
|
||||
DB(EmbeddedNetworkController *const nc,const Identity &myId,const char *path);
|
||||
virtual ~DB();
|
||||
|
||||
|
@ -648,7 +648,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
|
||||
json member,network;
|
||||
_db->get(nwid,network,address,member);
|
||||
json origMember(member); // for detecting changes
|
||||
_initMember(member);
|
||||
DB::initMember(member);
|
||||
|
||||
try {
|
||||
if (b.count("activeBridge")) member["activeBridge"] = OSUtils::jsonBool(b["activeBridge"],false);
|
||||
@ -734,7 +734,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
|
||||
member["address"] = addrs; // legacy
|
||||
member["nwid"] = nwids;
|
||||
|
||||
_cleanMember(member);
|
||||
DB::cleanMember(member);
|
||||
_db->save(&origMember,member);
|
||||
responseBody = OSUtils::jsonDump(member);
|
||||
responseContentType = "application/json";
|
||||
@ -767,7 +767,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
|
||||
json network;
|
||||
_db->get(nwid,network);
|
||||
json origNetwork(network); // for detecting changes
|
||||
_initNetwork(network);
|
||||
DB::initNetwork(network);
|
||||
|
||||
try {
|
||||
if (b.count("name")) network["name"] = OSUtils::jsonString(b["name"],"");
|
||||
@ -981,7 +981,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
|
||||
network["id"] = nwids;
|
||||
network["nwid"] = nwids; // legacy
|
||||
|
||||
_cleanNetwork(network);
|
||||
DB::cleanNetwork(network);
|
||||
_db->save(&origNetwork,network);
|
||||
|
||||
responseBody = OSUtils::jsonDump(network);
|
||||
@ -1183,7 +1183,7 @@ void EmbeddedNetworkController::_request(
|
||||
}
|
||||
origMember = member;
|
||||
const bool newMember = ((!member.is_object())||(member.size() == 0));
|
||||
_initMember(member);
|
||||
DB::initMember(member);
|
||||
|
||||
{
|
||||
const std::string haveIdStr(OSUtils::jsonString(member["identity"],""));
|
||||
@ -1281,7 +1281,7 @@ void EmbeddedNetworkController::_request(
|
||||
}
|
||||
} else {
|
||||
// If they are not authorized, STOP!
|
||||
_cleanMember(member);
|
||||
DB::cleanMember(member);
|
||||
_db->save(&origMember,member);
|
||||
_sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED);
|
||||
return;
|
||||
@ -1646,7 +1646,7 @@ void EmbeddedNetworkController::_request(
|
||||
return;
|
||||
}
|
||||
|
||||
_cleanMember(member);
|
||||
DB::cleanMember(member);
|
||||
_db->save(&origMember,member);
|
||||
_sender->ncSendConfig(nwid,requestPacketId,identity.address(),*(nc.get()),metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6);
|
||||
}
|
||||
|
@ -105,73 +105,6 @@ private:
|
||||
void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
|
||||
void _startThreads();
|
||||
|
||||
// These init objects with default and static/informational fields
|
||||
inline void _initMember(nlohmann::json &member)
|
||||
{
|
||||
if (!member.count("authorized")) member["authorized"] = false;
|
||||
if (!member.count("ipAssignments")) member["ipAssignments"] = nlohmann::json::array();
|
||||
if (!member.count("activeBridge")) member["activeBridge"] = false;
|
||||
if (!member.count("tags")) member["tags"] = nlohmann::json::array();
|
||||
if (!member.count("capabilities")) member["capabilities"] = nlohmann::json::array();
|
||||
if (!member.count("creationTime")) member["creationTime"] = OSUtils::now();
|
||||
if (!member.count("noAutoAssignIps")) member["noAutoAssignIps"] = false;
|
||||
if (!member.count("revision")) member["revision"] = 0ULL;
|
||||
if (!member.count("lastDeauthorizedTime")) member["lastDeauthorizedTime"] = 0ULL;
|
||||
if (!member.count("lastAuthorizedTime")) member["lastAuthorizedTime"] = 0ULL;
|
||||
if (!member.count("lastAuthorizedCredentialType")) member["lastAuthorizedCredentialType"] = nlohmann::json();
|
||||
if (!member.count("lastAuthorizedCredential")) member["lastAuthorizedCredential"] = nlohmann::json();
|
||||
if (!member.count("vMajor")) member["vMajor"] = -1;
|
||||
if (!member.count("vMinor")) member["vMinor"] = -1;
|
||||
if (!member.count("vRev")) member["vRev"] = -1;
|
||||
if (!member.count("vProto")) member["vProto"] = -1;
|
||||
if (!member.count("remoteTraceTarget")) member["remoteTraceTarget"] = nlohmann::json();
|
||||
if (!member.count("removeTraceLevel")) member["remoteTraceLevel"] = 0;
|
||||
member["objtype"] = "member";
|
||||
}
|
||||
inline void _initNetwork(nlohmann::json &network)
|
||||
{
|
||||
if (!network.count("private")) network["private"] = true;
|
||||
if (!network.count("creationTime")) network["creationTime"] = OSUtils::now();
|
||||
if (!network.count("name")) network["name"] = "";
|
||||
if (!network.count("multicastLimit")) network["multicastLimit"] = (uint64_t)32;
|
||||
if (!network.count("enableBroadcast")) network["enableBroadcast"] = true;
|
||||
if (!network.count("v4AssignMode")) network["v4AssignMode"] = {{"zt",false}};
|
||||
if (!network.count("v6AssignMode")) network["v6AssignMode"] = {{"rfc4193",false},{"zt",false},{"6plane",false}};
|
||||
if (!network.count("authTokens")) network["authTokens"] = {{}};
|
||||
if (!network.count("capabilities")) network["capabilities"] = nlohmann::json::array();
|
||||
if (!network.count("tags")) network["tags"] = nlohmann::json::array();
|
||||
if (!network.count("routes")) network["routes"] = nlohmann::json::array();
|
||||
if (!network.count("ipAssignmentPools")) network["ipAssignmentPools"] = nlohmann::json::array();
|
||||
if (!network.count("mtu")) network["mtu"] = ZT_DEFAULT_MTU;
|
||||
if (!network.count("remoteTraceTarget")) network["remoteTraceTarget"] = nlohmann::json();
|
||||
if (!network.count("removeTraceLevel")) network["remoteTraceLevel"] = 0;
|
||||
if (!network.count("rules")) {
|
||||
// If unspecified, rules are set to allow anything and behave like a flat L2 segment
|
||||
network["rules"] = {{
|
||||
{ "not",false },
|
||||
{ "or", false },
|
||||
{ "type","ACTION_ACCEPT" }
|
||||
}};
|
||||
}
|
||||
network["objtype"] = "network";
|
||||
}
|
||||
inline void _cleanNetwork(nlohmann::json &network)
|
||||
{
|
||||
network.erase("clock");
|
||||
network.erase("authorizedMemberCount");
|
||||
network.erase("activeMemberCount");
|
||||
network.erase("totalMemberCount");
|
||||
network.erase("lastModified");
|
||||
}
|
||||
inline void _cleanMember(nlohmann::json &member)
|
||||
{
|
||||
member.erase("clock");
|
||||
member.erase("physicalAddr");
|
||||
member.erase("recentLog");
|
||||
member.erase("lastModified");
|
||||
member.erase("lastRequestMetaData");
|
||||
}
|
||||
|
||||
struct _RQEntry
|
||||
{
|
||||
uint64_t nwid;
|
||||
|
@ -102,11 +102,6 @@
|
||||
*/
|
||||
#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_ANCHOR 0x0000040000000000ULL
|
||||
|
||||
/**
|
||||
* Device can send CIRCUIT_TESTs for this network
|
||||
*/
|
||||
#define ZT_NETWORKCONFIG_SPECIALIST_TYPE_CIRCUIT_TESTER 0x0000080000000000ULL
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
// Dictionary capacity needed for max size network config
|
||||
@ -344,21 +339,6 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param byPeer Address to check
|
||||
* @return True if this peer is allowed to do circuit tests on this network (controller is always true)
|
||||
*/
|
||||
inline bool circuitTestingAllowed(const Address &byPeer) const
|
||||
{
|
||||
if (byPeer.toInt() == ((networkId >> 24) & 0xffffffffffULL))
|
||||
return true;
|
||||
for(unsigned int i=0;i<specialistCount;++i) {
|
||||
if ((byPeer == specialists[i])&&((specialists[i] & ZT_NETWORKCONFIG_SPECIALIST_TYPE_CIRCUIT_TESTER) != 0))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return True if this network config is non-NULL
|
||||
*/
|
||||
|
@ -40,8 +40,9 @@
|
||||
|
||||
#include "Constants.hpp"
|
||||
|
||||
// So it's 2017 and this still helps on most Linux versions. It shouldn't but it does. Go figure.
|
||||
#if defined(__LINUX__) && ((defined(_MSC_VER) || defined(__GNUC__)) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64)))
|
||||
#ifdef __LINUX__
|
||||
|
||||
#if (defined(_MSC_VER) || defined(__GNUC__)) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
|
||||
#include <emmintrin.h>
|
||||
static inline void ZT_FAST_MEMCPY(void *a,const void *b,unsigned long k)
|
||||
{
|
||||
@ -74,6 +75,10 @@ static inline void ZT_FAST_MEMCPY(void *a,const void *b,unsigned long k)
|
||||
#define ZT_FAST_MEMCPY(a,b,c) memcpy(a,b,c)
|
||||
#endif
|
||||
|
||||
#else
|
||||
#define ZT_FAST_MEMCPY(a,b,c) memcpy(a,b,c)
|
||||
#endif
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
|
@ -43,6 +43,7 @@
|
||||
#include "../node/MulticastGroup.hpp"
|
||||
#include "../node/Mutex.hpp"
|
||||
#include "../node/Utils.hpp"
|
||||
#include "../osdep/OSUtils.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
@ -66,7 +67,7 @@ public:
|
||||
_enabled(true)
|
||||
{
|
||||
char tmp[32];
|
||||
Utils::snprintf(tmp,sizeof(tmp),"%.16llx",(unsigned long long)_nwid);
|
||||
OSUtils::ztsnprintf(tmp,sizeof(tmp),"%.16llx",(unsigned long long)_nwid);
|
||||
_dev.append(tmp);
|
||||
#ifdef ZT_TEST_TAP_REPORT_TO
|
||||
_reportTo.fromString(ZT_TEST_TAP_REPORT_TO);
|
||||
|
Loading…
Reference in New Issue
Block a user