updated ZTO core

This commit is contained in:
Joseph Henry
2017-05-30 13:11:43 -07:00
parent 5cfb4c38ef
commit 673d1b9a09
39 changed files with 426 additions and 1310 deletions

82
zto/Jenkinsfile vendored
View File

@@ -1,82 +0,0 @@
#!/usr/bin/env groovy
node('master') {
def changelog = getChangeLog currentBuild
slackSend "Building ${env.JOB_NAME} #${env.BUILD_NUMBER} \n Change Log: \n ${changelog}"
}
parallel 'centos7': {
node('centos7') {
try {
checkout scm
stage('Build Centos 7') {
sh 'make -f make-linux.mk'
}
}
catch (err) {
currentBuild.result = "FAILURE"
slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on Centos 7 (<${env.BUILD_URL}|Open>)"
throw err
}
}
}, 'android-ndk': {
node('android-ndk') {
try {
checkout scm
stage('Build Android NDK') {
sh "/android/android-ndk-r13b/ndk-build -C $WORKSPACE/java ZT1=${WORKSPACE}"
}
}
catch (err) {
currentBuild.result = "FAILURE"
slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on Android NDK (<${env.BUILD_URL}|Open>)"
throw err
}
}
}, 'macOS': {
node('macOS') {
try {
checkout scm
stage('Build macOS') {
sh 'make -f make-mac.mk'
}
stage('Build macOS UI') {
sh 'cd macui && xcodebuild -target "ZeroTier One" -configuration Debug'
}
}
catch (err) {
currentBuild.result = "FAILURE"
slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on macOS (<${env.BUILD_URL}|Open>)"
throw err
}
}
}, 'windows': {
node('windows') {
try {
checkout scm
stage('Build Windows') {
bat '''CALL "C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\vcvarsall.bat" amd64
git clean -dfx
msbuild windows\\ZeroTierOne.sln
'''
}
}
catch (err) {
currentBuild.result = "FAILURE"
slackSend color: '#ff0000', message: "${env.JOB_NAME} broken on Windows (<${env.BUILD_URL}|Open>)"
throw err
}
}
}
slackSend color: "#00ff00", message: "${env.JOB_NAME} #${env.BUILD_NUMBER} Complete (<${env.BUILD_URL}|Show More...>)"

View File

@@ -5,7 +5,7 @@ ZeroTier is an enterprise Ethernet switch for planet Earth.
It erases the LAN/WAN distinction and makes VPNs, tunnels, proxies, and other kludges arising from the inflexible nature of physical networks obsolete. Everything is encrypted end-to-end and traffic takes the most direct (peer to peer) path available. It erases the LAN/WAN distinction and makes VPNs, tunnels, proxies, and other kludges arising from the inflexible nature of physical networks obsolete. Everything is encrypted end-to-end and traffic takes the most direct (peer to peer) path available.
Visit [ZeroTier's site](https://www.zerotier.com/) for more information and [pre-built binary packages](https://www.zerotier.com/download.shtml). Apps for Android and iOS are available for free in the Google Play and Apple app stores. Visit [ZeroTier's site](https://www.zerotier.com/?pk_campaign=github_ZeroTierOne) for more information and [pre-built binary packages](https://www.zerotier.com/download.shtml?pk_campaign=github_ZeroTierOne). Apps for Android and iOS are available for free in the Google Play and Apple app stores.
### Getting Started ### Getting Started
@@ -23,7 +23,7 @@ Now wait about 30 seconds and check your system with `ip addr list` or `ifconfig
The *zt* interface will disappear. You're no longer on the network. The *zt* interface will disappear. You're no longer on the network.
To create networks of your own, you'll need a network controller. ZeroTier One (for desktops and servers) includes controller functionality in its default build that can be configured via its JSON API (see [README.md in controller/](controller/)). ZeroTier provides a hosted solution with a nice web UI and SaaS add-ons at [my.zerotier.com](https://my.zerotier.com/). Basic controller functionality is free for up to 100 devices. To create networks of your own, you'll need a network controller. ZeroTier One (for desktops and servers) includes controller functionality in its default build that can be configured via its JSON API (see [README.md in controller/](controller/)). ZeroTier provides a hosted solution with a nice web UI and SaaS add-ons at [my.zerotier.com](https://my.zerotier.com/?pk_campaign=github_ZeroTierOne). Basic controller functionality is free for up to 100 devices.
### Project Layout ### Project Layout
@@ -112,7 +112,7 @@ ZeroTier One peers will automatically locate each other and communicate directly
Users behind certain types of firewalls and "symmetric" NAT devices may not able able to connect to external peers directly at all. ZeroTier has limited support for port prediction and will *attempt* to traverse symmetric NATs, but this doesn't always work. If P2P connectivity fails you'll be bouncing UDP packets off our relay servers resulting in slower performance. Some NAT router(s) have a configurable NAT mode, and setting this to "full cone" will eliminate this problem. If you do this you may also see a magical improvement for things like VoIP phones, Skype, BitTorrent, WebRTC, certain games, etc., since all of these use NAT traversal techniques similar to ours. Users behind certain types of firewalls and "symmetric" NAT devices may not able able to connect to external peers directly at all. ZeroTier has limited support for port prediction and will *attempt* to traverse symmetric NATs, but this doesn't always work. If P2P connectivity fails you'll be bouncing UDP packets off our relay servers resulting in slower performance. Some NAT router(s) have a configurable NAT mode, and setting this to "full cone" will eliminate this problem. If you do this you may also see a magical improvement for things like VoIP phones, Skype, BitTorrent, WebRTC, certain games, etc., since all of these use NAT traversal techniques similar to ours.
If you're interested, there's a [technical deep dive about NAT traversal on our blog](https://www.zerotier.com/blog/?p=226). A troubleshooting tool to help you diagnose NAT issues is planned for the future as are uPnP/IGD/NAT-PMP and IPv6 transport. If you're interested, there's a [technical deep dive about NAT traversal on our blog](https://www.zerotier.com/blog/?p=226?pk_campaign=github_ZeroTierOne). A troubleshooting tool to help you diagnose NAT issues is planned for the future as are uPnP/IGD/NAT-PMP and IPv6 transport.
If a firewall between you and the Internet blocks ZeroTier's UDP traffic, you will fall back to last-resort TCP tunneling to rootservers over port 443 (https impersonation). This will work almost anywhere but is *very slow* compared to UDP or direct peer to peer connectivity. If a firewall between you and the Internet blocks ZeroTier's UDP traffic, you will fall back to last-resort TCP tunneling to rootservers over port 443 (https impersonation). This will work almost anywhere but is *very slow* compared to UDP or direct peer to peer connectivity.

View File

@@ -487,9 +487,6 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET(
if ((path.size() >= 2)&&(path[1].length() == 16)) { if ((path.size() >= 2)&&(path[1].length() == 16)) {
const uint64_t nwid = Utils::hexStrToU64(path[1].c_str()); const uint64_t nwid = Utils::hexStrToU64(path[1].c_str());
char nwids[24];
Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid);
json network; json network;
if (!_db.getNetwork(nwid,network)) if (!_db.getNetwork(nwid,network))
return 404; return 404;
@@ -499,6 +496,8 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET(
if (path[2] == "member") { if (path[2] == "member") {
if (path.size() >= 4) { if (path.size() >= 4) {
// Get member
const uint64_t address = Utils::hexStrToU64(path[3].c_str()); const uint64_t address = Utils::hexStrToU64(path[3].c_str());
json member; json member;
if (!_db.getNetworkMember(nwid,address,member)) if (!_db.getNetworkMember(nwid,address,member))
@@ -506,24 +505,29 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET(
_addMemberNonPersistedFields(nwid,address,member,OSUtils::now()); _addMemberNonPersistedFields(nwid,address,member,OSUtils::now());
responseBody = OSUtils::jsonDump(member); responseBody = OSUtils::jsonDump(member);
responseContentType = "application/json"; responseContentType = "application/json";
} else { } else {
// List members and their revisions
responseBody = "{"; responseBody = "{";
responseBody.reserve((_db.memberCount(nwid) + 1) * 32);
_db.eachMember(nwid,[&responseBody](uint64_t networkId,uint64_t nodeId,const json &member) { _db.eachMember(nwid,[&responseBody](uint64_t networkId,uint64_t nodeId,const json &member) {
if ((member.is_object())&&(member.size() > 0)) { if ((member.is_object())&&(member.size() > 0)) {
responseBody.append((responseBody.length() == 1) ? "\"" : ",\""); char tmp[128];
responseBody.append(OSUtils::jsonString(member["id"],"0")); Utils::snprintf(tmp,sizeof(tmp),"%s%.10llx\":%llu",(responseBody.length() > 1) ? ",\"" : "\"",(unsigned long long)nodeId,(unsigned long long)OSUtils::jsonInt(member["revision"],0));
responseBody.append("\":"); responseBody.append(tmp);
responseBody.append(OSUtils::jsonString(member["revision"],"0"));
} }
}); });
responseBody.push_back('}'); responseBody.push_back('}');
responseContentType = "application/json"; responseContentType = "application/json";
} }
return 200; return 200;
} // else 404 } // else 404
} else { } else {
// Get network
const uint64_t now = OSUtils::now(); const uint64_t now = OSUtils::now();
JSONDB::NetworkSummaryInfo ns; JSONDB::NetworkSummaryInfo ns;
@@ -535,12 +539,12 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET(
} }
} else if (path.size() == 1) { } else if (path.size() == 1) {
// List networks
std::vector<uint64_t> networkIds(_db.networkIds()); std::vector<uint64_t> networkIds(_db.networkIds());
std::sort(networkIds.begin(),networkIds.end());
char tmp[64]; char tmp[64];
responseBody.push_back('['); responseBody = "[";
responseBody.reserve((networkIds.size() + 1) * 24);
for(std::vector<uint64_t>::const_iterator i(networkIds.begin());i!=networkIds.end();++i) { for(std::vector<uint64_t>::const_iterator i(networkIds.begin());i!=networkIds.end();++i) {
if (responseBody.length() > 1) if (responseBody.length() > 1)
responseBody.push_back(','); responseBody.push_back(',');
@@ -555,6 +559,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET(
} // else 404 } // else 404
} else { } else {
// Controller status
char tmp[4096]; char tmp[4096];
Utils::snprintf(tmp,sizeof(tmp),"{\n\t\"controller\": true,\n\t\"apiVersion\": %d,\n\t\"clock\": %llu\n}\n",ZT_NETCONF_CONTROLLER_API_VERSION,(unsigned long long)OSUtils::now()); Utils::snprintf(tmp,sizeof(tmp),"{\n\t\"controller\": true,\n\t\"apiVersion\": %d,\n\t\"clock\": %llu\n}\n",ZT_NETCONF_CONTROLLER_API_VERSION,(unsigned long long)OSUtils::now());
@@ -721,59 +726,6 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
responseContentType = "application/json"; responseContentType = "application/json";
return 200; return 200;
} else if ((path.size() == 3)&&(path[2] == "test")) {
Mutex::Lock _l(_tests_m);
_tests.push_back(ZT_CircuitTest());
ZT_CircuitTest *const test = &(_tests.back());
memset(test,0,sizeof(ZT_CircuitTest));
Utils::getSecureRandom(&(test->testId),sizeof(test->testId));
test->credentialNetworkId = nwid;
test->ptr = (void *)this;
json hops = b["hops"];
if (hops.is_array()) {
for(unsigned long i=0;i<hops.size();++i) {
json &hops2 = hops[i];
if (hops2.is_array()) {
for(unsigned long j=0;j<hops2.size();++j) {
std::string s = hops2[j];
test->hops[test->hopCount].addresses[test->hops[test->hopCount].breadth++] = Utils::hexStrToU64(s.c_str()) & 0xffffffffffULL;
}
++test->hopCount;
} else if (hops2.is_string()) {
std::string s = hops2;
test->hops[test->hopCount].addresses[test->hops[test->hopCount].breadth++] = Utils::hexStrToU64(s.c_str()) & 0xffffffffffULL;
++test->hopCount;
}
}
}
test->reportAtEveryHop = (OSUtils::jsonBool(b["reportAtEveryHop"],true) ? 1 : 0);
if (!test->hopCount) {
_tests.pop_back();
responseBody = "{ \"message\": \"a test must contain at least one hop\" }";
responseContentType = "application/json";
return 400;
}
test->timestamp = OSUtils::now();
if (_node) {
_node->circuitTestBegin((void *)0,test,&(EmbeddedNetworkController::_circuitTestCallback));
} else {
_tests.pop_back();
return 500;
}
char json[512];
Utils::snprintf(json,sizeof(json),"{\"testId\":\"%.16llx\",\"timestamp\":%llu}",test->testId,test->timestamp);
responseBody = json;
responseContentType = "application/json";
return 200;
} // else 404 } // else 404
} else { } else {
@@ -809,6 +761,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
if (b.count("enableBroadcast")) network["enableBroadcast"] = OSUtils::jsonBool(b["enableBroadcast"],false); if (b.count("enableBroadcast")) network["enableBroadcast"] = OSUtils::jsonBool(b["enableBroadcast"],false);
if (b.count("allowPassiveBridging")) network["allowPassiveBridging"] = OSUtils::jsonBool(b["allowPassiveBridging"],false); if (b.count("allowPassiveBridging")) network["allowPassiveBridging"] = OSUtils::jsonBool(b["allowPassiveBridging"],false);
if (b.count("multicastLimit")) network["multicastLimit"] = OSUtils::jsonInt(b["multicastLimit"],32ULL); if (b.count("multicastLimit")) network["multicastLimit"] = OSUtils::jsonInt(b["multicastLimit"],32ULL);
if (b.count("mtu")) network["mtu"] = std::max(std::min((unsigned int)OSUtils::jsonInt(b["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU);
if (b.count("v4AssignMode")) { if (b.count("v4AssignMode")) {
json nv4m; json nv4m;
@@ -1112,7 +1065,6 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpDELETE(
void EmbeddedNetworkController::threadMain() void EmbeddedNetworkController::threadMain()
throw() throw()
{ {
uint64_t lastCircuitTestCheck = 0;
_RQEntry *qe = (_RQEntry *)0; _RQEntry *qe = (_RQEntry *)0;
while ((_running)&&(_queue.get(qe))) { while ((_running)&&(_queue.get(qe))) {
try { try {
@@ -1124,7 +1076,7 @@ void EmbeddedNetworkController::threadMain()
std::string pong("{\"memberStatus\":{"); std::string pong("{\"memberStatus\":{");
{ {
Mutex::Lock _l(_memberStatus_m); Mutex::Lock _l(_memberStatus_m);
pong.reserve(64 * _memberStatus.size()); pong.reserve(48 * (_memberStatus.size() + 1));
_db.eachId([this,&pong,&now,&first](uint64_t networkId,uint64_t nodeId) { _db.eachId([this,&pong,&now,&first](uint64_t networkId,uint64_t nodeId) {
char tmp[64]; char tmp[64];
uint64_t lrt = 0ULL; uint64_t lrt = 0ULL;
@@ -1147,80 +1099,9 @@ void EmbeddedNetworkController::threadMain()
} }
} catch ( ... ) {} } catch ( ... ) {}
delete qe; delete qe;
if (_running) {
uint64_t now = OSUtils::now();
if ((now - lastCircuitTestCheck) > ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION) {
lastCircuitTestCheck = now;
Mutex::Lock _l(_tests_m);
for(std::list< ZT_CircuitTest >::iterator i(_tests.begin());i!=_tests.end();) {
if ((now - i->timestamp) > ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION) {
_node->circuitTestEnd(&(*i));
_tests.erase(i++);
} else ++i;
}
}
}
} }
} }
void EmbeddedNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report)
{
char tmp[2048],id[128];
EmbeddedNetworkController *const self = reinterpret_cast<EmbeddedNetworkController *>(test->ptr);
if ((!test)||(!report)||(!test->credentialNetworkId)) return; // sanity check
const uint64_t now = OSUtils::now();
Utils::snprintf(id,sizeof(id),"network/%.16llx/test/%.16llx-%.16llx-%.10llx-%.10llx",test->credentialNetworkId,test->testId,now,report->upstream,report->current);
Utils::snprintf(tmp,sizeof(tmp),
"{\"id\": \"%s\","
"\"objtype\": \"circuit_test\","
"\"timestamp\": %llu,"
"\"networkId\": \"%.16llx\","
"\"testId\": \"%.16llx\","
"\"upstream\": \"%.10llx\","
"\"current\": \"%.10llx\","
"\"receivedTimestamp\": %llu,"
"\"sourcePacketId\": \"%.16llx\","
"\"flags\": %llu,"
"\"sourcePacketHopCount\": %u,"
"\"errorCode\": %u,"
"\"vendor\": %d,"
"\"protocolVersion\": %u,"
"\"majorVersion\": %u,"
"\"minorVersion\": %u,"
"\"revision\": %u,"
"\"platform\": %d,"
"\"architecture\": %d,"
"\"receivedOnLocalAddress\": \"%s\","
"\"receivedFromRemoteAddress\": \"%s\","
"\"receivedFromLinkQuality\": %f}",
id + 30, // last bit only, not leading path
(unsigned long long)test->timestamp,
(unsigned long long)test->credentialNetworkId,
(unsigned long long)test->testId,
(unsigned long long)report->upstream,
(unsigned long long)report->current,
(unsigned long long)now,
(unsigned long long)report->sourcePacketId,
(unsigned long long)report->flags,
report->sourcePacketHopCount,
report->errorCode,
(int)report->vendor,
report->protocolVersion,
report->majorVersion,
report->minorVersion,
report->revision,
(int)report->platform,
(int)report->architecture,
reinterpret_cast<const InetAddress *>(&(report->receivedOnLocalAddress))->toString().c_str(),
reinterpret_cast<const InetAddress *>(&(report->receivedFromRemoteAddress))->toString().c_str(),
((double)report->receivedFromLinkQuality / (double)ZT_PATH_LINK_QUALITY_MAX));
self->_db.writeRaw(id,std::string(tmp));
}
void EmbeddedNetworkController::_request( void EmbeddedNetworkController::_request(
uint64_t nwid, uint64_t nwid,
const InetAddress &fromAddr, const InetAddress &fromAddr,
@@ -1424,6 +1305,7 @@ void EmbeddedNetworkController::_request(
if (OSUtils::jsonBool(network["enableBroadcast"],true)) nc->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST; if (OSUtils::jsonBool(network["enableBroadcast"],true)) nc->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_BROADCAST;
if (OSUtils::jsonBool(network["allowPassiveBridging"],false)) nc->flags |= ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING; if (OSUtils::jsonBool(network["allowPassiveBridging"],false)) nc->flags |= ZT_NETWORKCONFIG_FLAG_ALLOW_PASSIVE_BRIDGING;
Utils::scopy(nc->name,sizeof(nc->name),OSUtils::jsonString(network["name"],"").c_str()); Utils::scopy(nc->name,sizeof(nc->name),OSUtils::jsonString(network["name"],"").c_str());
nc->mtu = std::max(std::min((unsigned int)OSUtils::jsonInt(network["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU);
nc->multicastLimit = (unsigned int)OSUtils::jsonInt(network["multicastLimit"],32ULL); nc->multicastLimit = (unsigned int)OSUtils::jsonInt(network["multicastLimit"],32ULL);
for(std::vector<Address>::const_iterator ab(ns.activeBridges.begin());ab!=ns.activeBridges.end();++ab) for(std::vector<Address>::const_iterator ab(ns.activeBridges.begin());ab!=ns.activeBridges.end();++ab)

View File

@@ -45,9 +45,6 @@
#include "JSONDB.hpp" #include "JSONDB.hpp"
// TTL for circuit tests
#define ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION 120000
namespace ZeroTier { namespace ZeroTier {
class Node; class Node;
@@ -110,7 +107,6 @@ private:
} type; } type;
}; };
static void _circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report);
void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData); void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
inline void _startThreads() inline void _startThreads()
@@ -162,6 +158,7 @@ private:
if (!network.count("tags")) network["tags"] = nlohmann::json::array(); if (!network.count("tags")) network["tags"] = nlohmann::json::array();
if (!network.count("routes")) network["routes"] = nlohmann::json::array(); if (!network.count("routes")) network["routes"] = nlohmann::json::array();
if (!network.count("ipAssignmentPools")) network["ipAssignmentPools"] = nlohmann::json::array(); if (!network.count("ipAssignmentPools")) network["ipAssignmentPools"] = nlohmann::json::array();
if (!network.count("mtu")) network["mtu"] = ZT_DEFAULT_MTU;
if (!network.count("rules")) { if (!network.count("rules")) {
// If unspecified, rules are set to allow anything and behave like a flat L2 segment // If unspecified, rules are set to allow anything and behave like a flat L2 segment
network["rules"] = {{ network["rules"] = {{
@@ -218,9 +215,6 @@ private:
NetworkController::Sender *_sender; NetworkController::Sender *_sender;
Identity _signingId; Identity _signingId;
std::list< ZT_CircuitTest > _tests;
Mutex _tests_m;
struct _MemberStatusKey struct _MemberStatusKey
{ {
_MemberStatusKey() : networkId(0),nodeId(0) {} _MemberStatusKey() : networkId(0),nodeId(0) {}

View File

@@ -392,14 +392,14 @@ bool JSONDB::_load(const std::string &p)
std::string objtype(OSUtils::jsonString(j["objtype"],"")); std::string objtype(OSUtils::jsonString(j["objtype"],""));
if ((id.length() == 16)&&(objtype == "network")) { if ((id.length() == 16)&&(objtype == "network")) {
const uint64_t nwid = Utils::strToU64(id.c_str()); const uint64_t nwid = Utils::hexStrToU64(id.c_str());
if (nwid) { if (nwid) {
Mutex::Lock _l(_networks_m); Mutex::Lock _l(_networks_m);
_networks[nwid].config = nlohmann::json::to_msgpack(j); _networks[nwid].config = nlohmann::json::to_msgpack(j);
} }
} else if ((id.length() == 10)&&(objtype == "member")) { } else if ((id.length() == 10)&&(objtype == "member")) {
const uint64_t mid = Utils::strToU64(id.c_str()); const uint64_t mid = Utils::hexStrToU64(id.c_str());
const uint64_t nwid = Utils::strToU64(OSUtils::jsonString(j["nwid"],"0").c_str()); const uint64_t nwid = Utils::hexStrToU64(OSUtils::jsonString(j["nwid"],"0").c_str());
if ((mid)&&(nwid)) { if ((mid)&&(nwid)) {
Mutex::Lock _l(_networks_m); Mutex::Lock _l(_networks_m);
_networks[nwid].members[mid] = nlohmann::json::to_msgpack(j); _networks[nwid].members[mid] = nlohmann::json::to_msgpack(j);

View File

@@ -93,6 +93,15 @@ public:
return r; 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> template<typename F>
inline void eachMember(const uint64_t networkId,F func) inline void eachMember(const uint64_t networkId,F func)
{ {

View File

@@ -1,7 +1,7 @@
FROM alpine:latest FROM alpine:latest
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com> MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
LABEL version="1.1.14" LABEL version="1.2.4"
LABEL description="Containerized ZeroTier One for use on CoreOS or other Docker-only Linux hosts." LABEL description="Containerized ZeroTier One for use on CoreOS or other Docker-only Linux hosts."
# Uncomment to build in container # Uncomment to build in container

View File

@@ -60,29 +60,14 @@ extern "C" {
#define ZT_DEFAULT_PORT 9993 #define ZT_DEFAULT_PORT 9993
/** /**
* Maximum MTU for ZeroTier virtual networks * Minimum MTU, which is the minimum allowed by IPv6 and several specs
*
* This is pretty much an unchangeable global constant. To make it change
* across nodes would require logic to send ICMP packet too big messages,
* which would complicate things. 1500 has been good enough on most LANs
* for ages, so a larger MTU should be fine for the forseeable future. This
* typically results in two UDP packets per single large frame. Experimental
* results seem to show that this is good. Larger MTUs resulting in more
* fragments seemed too brittle on slow/crummy links for no benefit.
*
* If this does change, also change it in tap.h in the tuntaposx code under
* mac-tap.
*
* Overhead for a normal frame split into two packets:
*
* 1414 = 1444 (typical UDP MTU) - 28 (packet header) - 2 (ethertype)
* 1428 = 1444 (typical UDP MTU) - 16 (fragment header)
* SUM: 2842
*
* We use 2800, which leaves some room for other payload in other types of
* messages such as multicast propagation or future support for bridging.
*/ */
#define ZT_MAX_MTU 2800 #define ZT_MIN_MTU 1280
/**
* Maximum MTU for ZeroTier virtual networks
*/
#define ZT_MAX_MTU 10000
/** /**
* Maximum length of network short name * Maximum length of network short name
@@ -775,7 +760,6 @@ typedef struct
*/ */
uint64_t expiration; uint64_t expiration;
struct { struct {
uint64_t from; uint64_t from;
uint64_t to; uint64_t to;
@@ -1120,197 +1104,6 @@ typedef struct
unsigned long peerCount; unsigned long peerCount;
} ZT_PeerList; } ZT_PeerList;
/**
* ZeroTier circuit test configuration and path
*/
typedef struct {
/**
* Test ID -- an arbitrary 64-bit identifier
*/
uint64_t testId;
/**
* Timestamp -- sent with test and echoed back by each reporter
*/
uint64_t timestamp;
/**
* Originator credential: network ID
*
* If this is nonzero, a network ID will be set for this test and
* the originator must be its primary network controller. This is
* currently the only authorization method available, so it must
* be set to run a test.
*/
uint64_t credentialNetworkId;
/**
* Hops in circuit test (a.k.a. FIFO for graph traversal)
*/
struct {
/**
* Hop flags (currently unused, must be zero)
*/
unsigned int flags;
/**
* Number of addresses in this hop (max: ZT_CIRCUIT_TEST_MAX_HOP_BREADTH)
*/
unsigned int breadth;
/**
* 40-bit ZeroTier addresses (most significant 24 bits ignored)
*/
uint64_t addresses[ZT_CIRCUIT_TEST_MAX_HOP_BREADTH];
} hops[ZT_CIRCUIT_TEST_MAX_HOPS];
/**
* Number of hops (max: ZT_CIRCUIT_TEST_MAX_HOPS)
*/
unsigned int hopCount;
/**
* If non-zero, circuit test will report back at every hop
*/
int reportAtEveryHop;
/**
* An arbitrary user-settable pointer
*/
void *ptr;
/**
* Pointer for internal use -- initialize to zero and do not modify
*/
void *_internalPtr;
} ZT_CircuitTest;
/**
* Circuit test result report
*/
typedef struct {
/**
* Sender of report (current hop)
*/
uint64_t current;
/**
* Previous hop
*/
uint64_t upstream;
/**
* 64-bit test ID
*/
uint64_t testId;
/**
* Timestamp from original test (echoed back at each hop)
*/
uint64_t timestamp;
/**
* 64-bit packet ID of packet received by the reporting device
*/
uint64_t sourcePacketId;
/**
* Flags
*/
uint64_t flags;
/**
* ZeroTier protocol-level hop count of packet received by reporting device (>0 indicates relayed)
*/
unsigned int sourcePacketHopCount;
/**
* Error code (currently unused, will be zero)
*/
unsigned int errorCode;
/**
* Remote device vendor ID
*/
enum ZT_Vendor vendor;
/**
* Remote device protocol compliance version
*/
unsigned int protocolVersion;
/**
* Software major version
*/
unsigned int majorVersion;
/**
* Software minor version
*/
unsigned int minorVersion;
/**
* Software revision
*/
unsigned int revision;
/**
* Platform / OS
*/
enum ZT_Platform platform;
/**
* System architecture
*/
enum ZT_Architecture architecture;
/**
* Local device address on which packet was received by reporting device
*
* This may have ss_family equal to zero (null address) if unspecified.
*/
struct sockaddr_storage receivedOnLocalAddress;
/**
* Remote address from which reporter received the test packet
*
* This may have ss_family set to zero (null address) if unspecified.
*/
struct sockaddr_storage receivedFromRemoteAddress;
/**
* Path link quality of physical path over which test was received
*/
int receivedFromLinkQuality;
/**
* Next hops to which packets are being or will be sent by the reporter
*
* In addition to reporting back, the reporter may send the test on if
* there are more recipients in the FIFO. If it does this, it can report
* back the address(es) that make up the next hop and the physical address
* for each if it has one. The physical address being null/unspecified
* typically indicates that no direct path exists and the next packet
* will be relayed.
*/
struct {
/**
* 40-bit ZeroTier address
*/
uint64_t address;
/**
* Physical address or null address (ss_family == 0) if unspecified or unknown
*/
struct sockaddr_storage physicalAddress;
} nextHops[ZT_CIRCUIT_TEST_MAX_HOP_BREADTH];
/**
* Number of next hops reported in nextHops[]
*/
unsigned int nextHopCount;
} ZT_CircuitTestReport;
/** /**
* A cluster member's status * A cluster member's status
*/ */
@@ -1972,40 +1765,6 @@ int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,uint64_t type
*/ */
void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkConfigMasterInstance); void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkConfigMasterInstance);
/**
* Initiate a VL1 circuit test
*
* This sends an initial VERB_CIRCUIT_TEST and reports results back to the
* supplied callback until circuitTestEnd() is called. The supplied
* ZT_CircuitTest structure should be initially zeroed and then filled
* in with settings and hops.
*
* It is the caller's responsibility to call circuitTestEnd() and then
* to dispose of the test structure. Otherwise this node will listen
* for results forever.
*
* @param node Node instance
* @param tptr Thread pointer to pass to functions/callbacks resulting from this call
* @param test Test configuration
* @param reportCallback Function to call each time a report is received
* @return OK or error if, for example, test is too big for a packet or support isn't compiled in
*/
enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *, ZT_CircuitTest *,const ZT_CircuitTestReport *));
/**
* Stop listening for results to a given circuit test
*
* This does not free the 'test' structure. The caller may do that
* after calling this method to unregister it.
*
* Any reports that are received for a given test ID after it is
* terminated are ignored.
*
* @param node Node instance
* @param test Test configuration to unregister
*/
void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test);
/** /**
* Initialize cluster operation * Initialize cluster operation
* *

View File

@@ -5,7 +5,7 @@ DEFS=
LIBS= LIBS=
include objects.mk include objects.mk
OBJS+=osdep/BSDEthernetTap.o ext/http-parser/http_parser.o ONE_OBJS+=osdep/BSDEthernetTap.o ext/http-parser/http_parser.o
# Build with ZT_ENABLE_CLUSTER=1 to build with cluster support # Build with ZT_ENABLE_CLUSTER=1 to build with cluster support
ifeq ($(ZT_ENABLE_CLUSTER),1) ifeq ($(ZT_ENABLE_CLUSTER),1)
@@ -14,10 +14,10 @@ endif
# "make debug" is a shortcut for this # "make debug" is a shortcut for this
ifeq ($(ZT_DEBUG),1) ifeq ($(ZT_DEBUG),1)
DEFS+=-DZT_TRACE CFLAGS+=-Wall -Werror -g -pthread $(INCLUDES) $(DEFS)
CFLAGS+=-Wall -g -pthread $(INCLUDES) $(DEFS)
LDFLAGS+= LDFLAGS+=
STRIP=echo STRIP=echo
ZT_TRACE=1
# The following line enables optimization for the crypto code, since # The following line enables optimization for the crypto code, since
# C25519 in particular is almost UNUSABLE in heavy testing without it. # C25519 in particular is almost UNUSABLE in heavy testing without it.
node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CFLAGS = -Wall -O2 -g -pthread $(INCLUDES) $(DEFS) node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CFLAGS = -Wall -O2 -g -pthread $(INCLUDES) $(DEFS)
@@ -28,80 +28,84 @@ else
STRIP=strip --strip-all STRIP=strip --strip-all
endif endif
ifeq ($(ZT_TRACE),1)
DEFS+=-DZT_TRACE
endif
# Determine system build architecture from compiler target # Determine system build architecture from compiler target
CC_MACH=$(shell $(CC) -dumpmachine | cut -d '-' -f 1) CC_MACH=$(shell $(CC) -dumpmachine | cut -d '-' -f 1)
ZT_ARCHITECTURE=999 ZT_ARCHITECTURE=999
ifeq ($(CC_MACH),x86_64) ifeq ($(CC_MACH),x86_64)
ZT_ARCHITECTURE=2 ZT_ARCHITECTURE=2
ZT_USE_X64_ASM_SALSA2012=1 ZT_USE_X64_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),amd64) ifeq ($(CC_MACH),amd64)
ZT_ARCHITECTURE=2 ZT_ARCHITECTURE=2
ZT_USE_X64_ASM_SALSA2012=1 ZT_USE_X64_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),i386) ifeq ($(CC_MACH),i386)
ZT_ARCHITECTURE=1 ZT_ARCHITECTURE=1
endif endif
ifeq ($(CC_MACH),i686) ifeq ($(CC_MACH),i686)
ZT_ARCHITECTURE=1 ZT_ARCHITECTURE=1
endif endif
ifeq ($(CC_MACH),arm) ifeq ($(CC_MACH),arm)
ZT_ARCHITECTURE=3 ZT_ARCHITECTURE=3
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
ZT_USE_ARM32_NEON_ASM_SALSA2012=1 ZT_USE_ARM32_NEON_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),armel) ifeq ($(CC_MACH),armel)
ZT_ARCHITECTURE=3 ZT_ARCHITECTURE=3
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
ZT_USE_ARM32_NEON_ASM_SALSA2012=1 ZT_USE_ARM32_NEON_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),armhf) ifeq ($(CC_MACH),armhf)
ZT_ARCHITECTURE=3 ZT_ARCHITECTURE=3
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
ZT_USE_ARM32_NEON_ASM_SALSA2012=1 ZT_USE_ARM32_NEON_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),armv6) ifeq ($(CC_MACH),armv6)
ZT_ARCHITECTURE=3 ZT_ARCHITECTURE=3
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
ZT_USE_ARM32_NEON_ASM_SALSA2012=1 ZT_USE_ARM32_NEON_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),armv6zk) ifeq ($(CC_MACH),armv6zk)
ZT_ARCHITECTURE=3 ZT_ARCHITECTURE=3
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
ZT_USE_ARM32_NEON_ASM_SALSA2012=1 ZT_USE_ARM32_NEON_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),armv6kz) ifeq ($(CC_MACH),armv6kz)
ZT_ARCHITECTURE=3 ZT_ARCHITECTURE=3
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
ZT_USE_ARM32_NEON_ASM_SALSA2012=1 ZT_USE_ARM32_NEON_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),armv7) ifeq ($(CC_MACH),armv7)
ZT_ARCHITECTURE=3 ZT_ARCHITECTURE=3
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
ZT_USE_ARM32_NEON_ASM_SALSA2012=1 ZT_USE_ARM32_NEON_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),arm64) ifeq ($(CC_MACH),arm64)
ZT_ARCHITECTURE=4 ZT_ARCHITECTURE=4
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
endif endif
ifeq ($(CC_MACH),aarch64) ifeq ($(CC_MACH),aarch64)
ZT_ARCHITECTURE=4 ZT_ARCHITECTURE=4
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
endif endif
ifeq ($(CC_MACH),mipsel) ifeq ($(CC_MACH),mipsel)
ZT_ARCHITECTURE=5 ZT_ARCHITECTURE=5
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
endif endif
ifeq ($(CC_MACH),mips) ifeq ($(CC_MACH),mips)
ZT_ARCHITECTURE=5 ZT_ARCHITECTURE=5
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
endif endif
ifeq ($(CC_MACH),mips64) ifeq ($(CC_MACH),mips64)
ZT_ARCHITECTURE=6 ZT_ARCHITECTURE=6
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
endif endif
ifeq ($(CC_MACH),mips64el) ifeq ($(CC_MACH),mips64el)
ZT_ARCHITECTURE=6 ZT_ARCHITECTURE=6
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
endif endif
@@ -115,11 +119,11 @@ endif
# Build faster crypto on some targets # Build faster crypto on some targets
ifeq ($(ZT_USE_X64_ASM_SALSA2012),1) ifeq ($(ZT_USE_X64_ASM_SALSA2012),1)
override DEFS+=-DZT_USE_X64_ASM_SALSA2012 override DEFS+=-DZT_USE_X64_ASM_SALSA2012
override OBJS+=ext/x64-salsa2012-asm/salsa2012.o override CORE_OBJS+=ext/x64-salsa2012-asm/salsa2012.o
endif endif
ifeq ($(ZT_USE_ARM32_NEON_ASM_SALSA2012),1) ifeq ($(ZT_USE_ARM32_NEON_ASM_SALSA2012),1)
override DEFS+=-DZT_USE_ARM32_NEON_ASM_SALSA2012 override DEFS+=-DZT_USE_ARM32_NEON_ASM_SALSA2012
override OBJS+=ext/arm32-neon-salsa2012-asm/salsa2012.o override CORE_OBJS+=ext/arm32-neon-salsa2012-asm/salsa2012.o
endif endif
override DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\"" override DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\""
@@ -128,18 +132,32 @@ CXXFLAGS+=$(CFLAGS) -fno-rtti -std=c++11 #-D_GLIBCXX_USE_C99 -D_GLIBCXX_USE_C99_
all: one all: one
one: $(OBJS) service/OneService.o one.o one: $(CORE_OBJS) $(ONE_OBJS) one.o
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(OBJS) service/OneService.o one.o $(LIBS) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LIBS)
$(STRIP) zerotier-one $(STRIP) zerotier-one
ln -sf zerotier-one zerotier-idtool ln -sf zerotier-one zerotier-idtool
ln -sf zerotier-one zerotier-cli ln -sf zerotier-one zerotier-cli
selftest: $(OBJS) selftest.o zerotier-one: one
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-selftest selftest.o $(OBJS) $(LIBS)
zerotier-idtool: one
zerotier-cli: one
libzerotiercore.a: $(CORE_OBJS)
ar rcs libzerotiercore.a $(CORE_OBJS)
ranlib libzerotiercore.a
core: libzerotiercore.a
selftest: $(CORE_OBJS) $(ONE_OBJS) selftest.o
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-selftest selftest.o $(CORE_OBJS) $(ONE_OBJS) $(LIBS)
$(STRIP) zerotier-selftest $(STRIP) zerotier-selftest
zerotier-selftest: selftest
clean: clean:
rm -rf *.o node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o build-* zerotier-one zerotier-idtool zerotier-selftest zerotier-cli ZeroTierOneInstaller-* $(OBJS) rm -rf *.a *.o node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o build-* zerotier-one zerotier-idtool zerotier-selftest zerotier-cli $(ONE_OBJS) $(CORE_OBJS)
debug: FORCE debug: FORCE
make -j 4 ZT_DEBUG=1 make -j 4 ZT_DEBUG=1

View File

@@ -13,14 +13,11 @@ LDLIBS?=
DESTDIR?= DESTDIR?=
include objects.mk include objects.mk
ONE_OBJS+=osdep/LinuxEthernetTap.o
# Use bundled http-parser since distribution versions are NOT API-stable or compatible!
# Trying to use dynamically linked libhttp-parser causes tons of compatibility problems.
OBJS+=ext/http-parser/http_parser.o
# Auto-detect miniupnpc and nat-pmp as well and use system libs if present, # Auto-detect miniupnpc and nat-pmp as well and use system libs if present,
# otherwise build into binary as done on Mac and Windows. # otherwise build into binary as done on Mac and Windows.
OBJS+=osdep/PortMapper.o ONE_OBJS+=osdep/PortMapper.o
DEFS+=-DZT_USE_MINIUPNPC DEFS+=-DZT_USE_MINIUPNPC
MINIUPNPC_IS_NEW_ENOUGH=$(shell grep -sqr '.*define.*MINIUPNPC_VERSION.*"2.."' /usr/include/miniupnpc/miniupnpc.h && echo 1) MINIUPNPC_IS_NEW_ENOUGH=$(shell grep -sqr '.*define.*MINIUPNPC_VERSION.*"2.."' /usr/include/miniupnpc/miniupnpc.h && echo 1)
ifeq ($(MINIUPNPC_IS_NEW_ENOUGH),1) ifeq ($(MINIUPNPC_IS_NEW_ENOUGH),1)
@@ -28,15 +25,19 @@ ifeq ($(MINIUPNPC_IS_NEW_ENOUGH),1)
LDLIBS+=-lminiupnpc LDLIBS+=-lminiupnpc
else else
DEFS+=-DMINIUPNP_STATICLIB -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DOS_STRING=\"Linux\" -DMINIUPNPC_VERSION_STRING=\"2.0\" -DUPNP_VERSION_STRING=\"UPnP/1.1\" -DENABLE_STRNATPMPERR DEFS+=-DMINIUPNP_STATICLIB -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DOS_STRING=\"Linux\" -DMINIUPNPC_VERSION_STRING=\"2.0\" -DUPNP_VERSION_STRING=\"UPnP/1.1\" -DENABLE_STRNATPMPERR
OBJS+=ext/miniupnpc/connecthostport.o ext/miniupnpc/igd_desc_parse.o ext/miniupnpc/minisoap.o ext/miniupnpc/minissdpc.o ext/miniupnpc/miniupnpc.o ext/miniupnpc/miniwget.o ext/miniupnpc/minixml.o ext/miniupnpc/portlistingparse.o ext/miniupnpc/receivedata.o ext/miniupnpc/upnpcommands.o ext/miniupnpc/upnpdev.o ext/miniupnpc/upnperrors.o ext/miniupnpc/upnpreplyparse.o ONE_OBJS+=ext/miniupnpc/connecthostport.o ext/miniupnpc/igd_desc_parse.o ext/miniupnpc/minisoap.o ext/miniupnpc/minissdpc.o ext/miniupnpc/miniupnpc.o ext/miniupnpc/miniwget.o ext/miniupnpc/minixml.o ext/miniupnpc/portlistingparse.o ext/miniupnpc/receivedata.o ext/miniupnpc/upnpcommands.o ext/miniupnpc/upnpdev.o ext/miniupnpc/upnperrors.o ext/miniupnpc/upnpreplyparse.o
endif endif
ifeq ($(wildcard /usr/include/natpmp.h),) ifeq ($(wildcard /usr/include/natpmp.h),)
OBJS+=ext/libnatpmp/natpmp.o ext/libnatpmp/getgateway.o ONE_OBJS+=ext/libnatpmp/natpmp.o ext/libnatpmp/getgateway.o
else else
LDLIBS+=-lnatpmp LDLIBS+=-lnatpmp
DEFS+=-DZT_USE_SYSTEM_NATPMP DEFS+=-DZT_USE_SYSTEM_NATPMP
endif endif
# Use bundled http-parser since distribution versions are NOT API-stable or compatible!
# Trying to use dynamically linked libhttp-parser causes tons of compatibility problems.
ONE_OBJS+=ext/http-parser/http_parser.o
ifeq ($(ZT_ENABLE_CLUSTER),1) ifeq ($(ZT_ENABLE_CLUSTER),1)
DEFS+=-DZT_ENABLE_CLUSTER DEFS+=-DZT_ENABLE_CLUSTER
endif endif
@@ -54,10 +55,10 @@ ifeq ($(ZT_RULES_ENGINE_DEBUGGING),1)
endif endif
ifeq ($(ZT_DEBUG),1) ifeq ($(ZT_DEBUG),1)
override DEFS+=-DZT_TRACE override CFLAGS+=-Wall -Wno-deprecated -Werror -g -pthread $(INCLUDES) $(DEFS)
override CFLAGS+=-Wall -g -pthread $(INCLUDES) $(DEFS) override CXXFLAGS+=-Wall -Wno-deprecated -Werror -g -std=c++11 -pthread $(INCLUDES) $(DEFS)
override CXXFLAGS+=-Wall -g -std=c++11 -pthread $(INCLUDES) $(DEFS)
override LDFLAGS+= override LDFLAGS+=
ZT_TRACE=1
STRIP?=echo STRIP?=echo
# The following line enables optimization for the crypto code, since # The following line enables optimization for the crypto code, since
# C25519 in particular is almost UNUSABLE in -O0 even on a 3ghz box! # C25519 in particular is almost UNUSABLE in -O0 even on a 3ghz box!
@@ -65,14 +66,18 @@ node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CXXFLAGS=-Wall -O2 -
else else
override DEFS+=-D_FORTIFY_SOURCE=2 override DEFS+=-D_FORTIFY_SOURCE=2
CFLAGS?=-O3 -fstack-protector CFLAGS?=-O3 -fstack-protector
override CFLAGS+=-Wall -fPIE -pthread $(INCLUDES) -DNDEBUG $(DEFS) override CFLAGS+=-Wall -Wno-deprecated -fPIE -pthread $(INCLUDES) -DNDEBUG $(DEFS)
CXXFLAGS?=-O3 -fstack-protector CXXFLAGS?=-O3 -fstack-protector
override CXXFLAGS+=-Wall -Wno-unused-result -Wreorder -fPIE -std=c++11 -pthread $(INCLUDES) -DNDEBUG $(DEFS) override CXXFLAGS+=-Wall -Wno-deprecated -Wno-unused-result -Wreorder -fPIE -std=c++11 -pthread $(INCLUDES) -DNDEBUG $(DEFS)
override LDFLAGS+=-pie -Wl,-z,relro,-z,now override LDFLAGS+=-pie -Wl,-z,relro,-z,now
STRIP?=strip STRIP?=strip
STRIP+=--strip-all STRIP+=--strip-all
endif endif
ifeq ($(ZT_TRACE),1)
override DEFS+=-DZT_TRACE
endif
ifeq ($(ZT_USE_TEST_TAP),1) ifeq ($(ZT_USE_TEST_TAP),1)
override DEFS+=-DZT_USE_TEST_TAP override DEFS+=-DZT_USE_TEST_TAP
endif endif
@@ -87,82 +92,82 @@ endif
CC_MACH=$(shell $(CC) -dumpmachine | cut -d '-' -f 1) CC_MACH=$(shell $(CC) -dumpmachine | cut -d '-' -f 1)
ZT_ARCHITECTURE=999 ZT_ARCHITECTURE=999
ifeq ($(CC_MACH),x86_64) ifeq ($(CC_MACH),x86_64)
ZT_ARCHITECTURE=2 ZT_ARCHITECTURE=2
ZT_USE_X64_ASM_SALSA2012=1 ZT_USE_X64_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),amd64) ifeq ($(CC_MACH),amd64)
ZT_ARCHITECTURE=2 ZT_ARCHITECTURE=2
ZT_USE_X64_ASM_SALSA2012=1 ZT_USE_X64_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),i386) ifeq ($(CC_MACH),i386)
ZT_ARCHITECTURE=1 ZT_ARCHITECTURE=1
endif endif
ifeq ($(CC_MACH),i486) ifeq ($(CC_MACH),i486)
ZT_ARCHITECTURE=1 ZT_ARCHITECTURE=1
endif endif
ifeq ($(CC_MACH),i586) ifeq ($(CC_MACH),i586)
ZT_ARCHITECTURE=1 ZT_ARCHITECTURE=1
endif endif
ifeq ($(CC_MACH),i686) ifeq ($(CC_MACH),i686)
ZT_ARCHITECTURE=1 ZT_ARCHITECTURE=1
endif endif
ifeq ($(CC_MACH),arm) ifeq ($(CC_MACH),arm)
ZT_ARCHITECTURE=3 ZT_ARCHITECTURE=3
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
ZT_USE_ARM32_NEON_ASM_SALSA2012=1 ZT_USE_ARM32_NEON_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),armel) ifeq ($(CC_MACH),armel)
ZT_ARCHITECTURE=3 ZT_ARCHITECTURE=3
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
ZT_USE_ARM32_NEON_ASM_SALSA2012=1 ZT_USE_ARM32_NEON_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),armhf) ifeq ($(CC_MACH),armhf)
ZT_ARCHITECTURE=3 ZT_ARCHITECTURE=3
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
ZT_USE_ARM32_NEON_ASM_SALSA2012=1 ZT_USE_ARM32_NEON_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),armv6) ifeq ($(CC_MACH),armv6)
ZT_ARCHITECTURE=3 ZT_ARCHITECTURE=3
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
ZT_USE_ARM32_NEON_ASM_SALSA2012=1 ZT_USE_ARM32_NEON_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),armv6zk) ifeq ($(CC_MACH),armv6zk)
ZT_ARCHITECTURE=3 ZT_ARCHITECTURE=3
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
ZT_USE_ARM32_NEON_ASM_SALSA2012=1 ZT_USE_ARM32_NEON_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),armv6kz) ifeq ($(CC_MACH),armv6kz)
ZT_ARCHITECTURE=3 ZT_ARCHITECTURE=3
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
ZT_USE_ARM32_NEON_ASM_SALSA2012=1 ZT_USE_ARM32_NEON_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),armv7) ifeq ($(CC_MACH),armv7)
ZT_ARCHITECTURE=3 ZT_ARCHITECTURE=3
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
ZT_USE_ARM32_NEON_ASM_SALSA2012=1 ZT_USE_ARM32_NEON_ASM_SALSA2012=1
endif endif
ifeq ($(CC_MACH),arm64) ifeq ($(CC_MACH),arm64)
ZT_ARCHITECTURE=4 ZT_ARCHITECTURE=4
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
endif endif
ifeq ($(CC_MACH),aarch64) ifeq ($(CC_MACH),aarch64)
ZT_ARCHITECTURE=4 ZT_ARCHITECTURE=4
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
endif endif
ifeq ($(CC_MACH),mipsel) ifeq ($(CC_MACH),mipsel)
ZT_ARCHITECTURE=5 ZT_ARCHITECTURE=5
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
endif endif
ifeq ($(CC_MACH),mips) ifeq ($(CC_MACH),mips)
ZT_ARCHITECTURE=5 ZT_ARCHITECTURE=5
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
endif endif
ifeq ($(CC_MACH),mips64) ifeq ($(CC_MACH),mips64)
ZT_ARCHITECTURE=6 ZT_ARCHITECTURE=6
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
endif endif
ifeq ($(CC_MACH),mips64el) ifeq ($(CC_MACH),mips64el)
ZT_ARCHITECTURE=6 ZT_ARCHITECTURE=6
override DEFS+=-DZT_NO_TYPE_PUNNING override DEFS+=-DZT_NO_TYPE_PUNNING
endif endif
@@ -179,48 +184,69 @@ override DEFS+=-DZT_BUILD_PLATFORM=1 -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE)
# Static builds, which are currently done for a number of Linux targets # Static builds, which are currently done for a number of Linux targets
ifeq ($(ZT_STATIC),1) ifeq ($(ZT_STATIC),1)
override LDFLAGS+=-static override LDFLAGS+=-static
ifeq ($(ZT_ARCHITECTURE),3) endif
ifeq ($(shell if [ -e /usr/bin/dpkg ]; then dpkg --print-architecture; fi),armel)
override CFLAGS+=-march=armv5te -mfloat-abi=soft -msoft-float -mno-unaligned-access -marm # ARM32 hell -- use conservative CFLAGS
override CXXFLAGS+=-march=armv5te -mfloat-abi=soft -msoft-float -mno-unaligned-access -marm ifeq ($(ZT_ARCHITECTURE),3)
ZT_USE_ARM32_NEON_ASM_SALSA2012=0 ifeq ($(shell if [ -e /usr/bin/dpkg ]; then dpkg --print-architecture; fi),armel)
else override CFLAGS+=-march=armv5 -mfloat-abi=soft -msoft-float -mno-unaligned-access -marm
override CFLAGS+=-march=armv6zk -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -mno-unaligned-access -marm override CXXFLAGS+=-march=armv5 -mfloat-abi=soft -msoft-float -mno-unaligned-access -marm
override CXXFLAGS+=-march=armv6zk -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -mno-unaligned-access -marm ZT_USE_ARM32_NEON_ASM_SALSA2012=0
ZT_USE_ARM32_NEON_ASM_SALSA2012=0 else
endif override CFLAGS+=-march=armv5 -mno-unaligned-access -marm
override CXXFLAGS+=-march=armv5 -mno-unaligned-access -marm
endif endif
endif endif
# Build faster crypto on some targets # Build faster crypto on some targets
ifeq ($(ZT_USE_X64_ASM_SALSA2012),1) ifeq ($(ZT_USE_X64_ASM_SALSA2012),1)
override DEFS+=-DZT_USE_X64_ASM_SALSA2012 override DEFS+=-DZT_USE_X64_ASM_SALSA2012
override OBJS+=ext/x64-salsa2012-asm/salsa2012.o override CORE_OBJS+=ext/x64-salsa2012-asm/salsa2012.o
endif endif
ifeq ($(ZT_USE_ARM32_NEON_ASM_SALSA2012),1) ifeq ($(ZT_USE_ARM32_NEON_ASM_SALSA2012),1)
override DEFS+=-DZT_USE_ARM32_NEON_ASM_SALSA2012 override DEFS+=-DZT_USE_ARM32_NEON_ASM_SALSA2012
override OBJS+=ext/arm32-neon-salsa2012-asm/salsa2012.o override CORE_OBJS+=ext/arm32-neon-salsa2012-asm/salsa2012.o
endif endif
all: one all: one
one: $(OBJS) service/OneService.o one.o osdep/LinuxEthernetTap.o #ext/x64-salsa2012-asm/salsa2012.o:
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(OBJS) service/OneService.o one.o osdep/LinuxEthernetTap.o $(LDLIBS) # $(CC) -c ext/x64-salsa2012-asm/salsa2012.s -o ext/x64-salsa2012-asm/salsa2012.o
#ext/arm32-neon-salsa2012-asm/salsa2012.o:
# $(CC) -c ext/arm32-neon-salsa2012-asm/salsa2012.s -o ext/arm32-neon-salsa2012-asm/salsa2012.o
one: $(CORE_OBJS) $(ONE_OBJS) one.o
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LDLIBS)
$(STRIP) zerotier-one $(STRIP) zerotier-one
ln -sf zerotier-one zerotier-idtool ln -sf zerotier-one zerotier-idtool
ln -sf zerotier-one zerotier-cli ln -sf zerotier-one zerotier-cli
selftest: $(OBJS) selftest.o zerotier-one: one
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-selftest selftest.o $(OBJS) $(LDLIBS)
zerotier-idtool: one
zerotier-cli: one
libzerotiercore.a: $(CORE_OBJS)
ar rcs libzerotiercore.a $(CORE_OBJS)
ranlib libzerotiercore.a
core: libzerotiercore.a
selftest: $(CORE_OBJS) $(ONE_OBJS) selftest.o
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-selftest selftest.o $(CORE_OBJS) $(ONE_OBJS $(LDLIBS)
$(STRIP) zerotier-selftest $(STRIP) zerotier-selftest
zerotier-selftest: selftest
manpages: FORCE manpages: FORCE
cd doc ; ./build.sh cd doc ; ./build.sh
doc: manpages doc: manpages
clean: FORCE clean: FORCE
rm -rf *.so *.o node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o ext/miniupnpc/*.o ext/libnatpmp/*.o $(OBJS) zerotier-one zerotier-idtool zerotier-cli zerotier-selftest build-* ZeroTierOneInstaller-* *.deb *.rpm .depend debian/files debian/zerotier-one*.debhelper debian/zerotier-one.substvars debian/*.log debian/zerotier-one doc/node_modules rm -rf *.a *.so *.o node/*.o controller/*.o osdep/*.o service/*.o ext/http-parser/*.o ext/miniupnpc/*.o ext/libnatpmp/*.o $(CORE_OBJS) $(ONE_OBJS) zerotier-one zerotier-idtool zerotier-cli zerotier-selftest build-* ZeroTierOneInstaller-* *.deb *.rpm .depend debian/files debian/zerotier-one*.debhelper debian/zerotier-one.substvars debian/*.log debian/zerotier-one doc/node_modules
distclean: clean distclean: clean

View File

@@ -19,7 +19,7 @@ ZT_VERSION_BUILD=$(shell cat version.h | grep -F VERSION_BUILD | cut -d ' ' -f 3
DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_BUILD_ARCHITECTURE) DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_BUILD_ARCHITECTURE)
include objects.mk include objects.mk
OBJS+=osdep/OSXEthernetTap.o ext/http-parser/http_parser.o ONE_OBJS+=osdep/OSXEthernetTap.o ext/http-parser/http_parser.o
# Official releases are signed with our Apple cert and apply software updates by default # Official releases are signed with our Apple cert and apply software updates by default
ifeq ($(ZT_OFFICIAL_RELEASE),1) ifeq ($(ZT_OFFICIAL_RELEASE),1)
@@ -39,26 +39,30 @@ endif
# Use fast ASM Salsa20/12 for x64 processors # Use fast ASM Salsa20/12 for x64 processors
DEFS+=-DZT_USE_X64_ASM_SALSA2012 DEFS+=-DZT_USE_X64_ASM_SALSA2012
OBJS+=ext/x64-salsa2012-asm/salsa2012.o CORE_OBJS+=ext/x64-salsa2012-asm/salsa2012.o
# Build miniupnpc and nat-pmp as included libraries -- extra defs are required for these sources # Build miniupnpc and nat-pmp as included libraries -- extra defs are required for these sources
DEFS+=-DMACOSX -DZT_USE_MINIUPNPC -DMINIUPNP_STATICLIB -D_DARWIN_C_SOURCE -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -DOS_STRING=\"Darwin/15.0.0\" -DMINIUPNPC_VERSION_STRING=\"2.0\" -DUPNP_VERSION_STRING=\"UPnP/1.1\" -DENABLE_STRNATPMPERR DEFS+=-DMACOSX -DZT_USE_MINIUPNPC -DMINIUPNP_STATICLIB -D_DARWIN_C_SOURCE -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -DOS_STRING=\"Darwin/15.0.0\" -DMINIUPNPC_VERSION_STRING=\"2.0\" -DUPNP_VERSION_STRING=\"UPnP/1.1\" -DENABLE_STRNATPMPERR
OBJS+=ext/libnatpmp/natpmp.o ext/libnatpmp/getgateway.o ext/miniupnpc/connecthostport.o ext/miniupnpc/igd_desc_parse.o ext/miniupnpc/minisoap.o ext/miniupnpc/minissdpc.o ext/miniupnpc/miniupnpc.o ext/miniupnpc/miniwget.o ext/miniupnpc/minixml.o ext/miniupnpc/portlistingparse.o ext/miniupnpc/receivedata.o ext/miniupnpc/upnpcommands.o ext/miniupnpc/upnpdev.o ext/miniupnpc/upnperrors.o ext/miniupnpc/upnpreplyparse.o osdep/PortMapper.o ONE_OBJS+=ext/libnatpmp/natpmp.o ext/libnatpmp/getgateway.o ext/miniupnpc/connecthostport.o ext/miniupnpc/igd_desc_parse.o ext/miniupnpc/minisoap.o ext/miniupnpc/minissdpc.o ext/miniupnpc/miniupnpc.o ext/miniupnpc/miniwget.o ext/miniupnpc/minixml.o ext/miniupnpc/portlistingparse.o ext/miniupnpc/receivedata.o ext/miniupnpc/upnpcommands.o ext/miniupnpc/upnpdev.o ext/miniupnpc/upnperrors.o ext/miniupnpc/upnpreplyparse.o osdep/PortMapper.o
# Debug mode -- dump trace output, build binary with -g # Debug mode -- dump trace output, build binary with -g
ifeq ($(ZT_DEBUG),1) ifeq ($(ZT_DEBUG),1)
DEFS+=-DZT_TRACE ZT_TRACE=1
CFLAGS+=-Wall -g -pthread $(INCLUDES) $(DEFS) CFLAGS+=-Wall -Werror -g $(INCLUDES) $(DEFS)
STRIP=echo STRIP=echo
# The following line enables optimization for the crypto code, since # The following line enables optimization for the crypto code, since
# C25519 in particular is almost UNUSABLE in heavy testing without it. # C25519 in particular is almost UNUSABLE in heavy testing without it.
node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CFLAGS = -Wall -O2 -g -pthread $(INCLUDES) $(DEFS) node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CFLAGS = -Wall -O2 -g $(INCLUDES) $(DEFS)
else else
CFLAGS?=-Ofast -fstack-protector-strong CFLAGS?=-Ofast -fstack-protector-strong
CFLAGS+=$(ARCH_FLAGS) -Wall -flto -fPIE -pthread -mmacosx-version-min=10.7 -DNDEBUG -Wno-unused-private-field $(INCLUDES) $(DEFS) CFLAGS+=$(ARCH_FLAGS) -Wall -Werror -flto -fPIE -mmacosx-version-min=10.7 -DNDEBUG -Wno-unused-private-field $(INCLUDES) $(DEFS)
STRIP=strip STRIP=strip
endif endif
ifeq ($(ZT_TRACE),1)
DEFS+=-DZT_TRACE
endif
CXXFLAGS=$(CFLAGS) -std=c++11 -stdlib=libc++ CXXFLAGS=$(CFLAGS) -std=c++11 -stdlib=libc++
all: one macui all: one macui
@@ -66,13 +70,25 @@ all: one macui
ext/x64-salsa2012-asm/salsa2012.o: ext/x64-salsa2012-asm/salsa2012.o:
$(CC) $(CFLAGS) -c ext/x64-salsa2012-asm/salsa2012.s -o ext/x64-salsa2012-asm/salsa2012.o $(CC) $(CFLAGS) -c ext/x64-salsa2012-asm/salsa2012.s -o ext/x64-salsa2012-asm/salsa2012.o
one: $(OBJS) service/OneService.o one.o one: $(CORE_OBJS) $(ONE_OBJS) one.o
$(CXX) $(CXXFLAGS) -o zerotier-one $(OBJS) service/OneService.o one.o $(LIBS) $(CXX) $(CXXFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LIBS)
$(STRIP) zerotier-one $(STRIP) zerotier-one
ln -sf zerotier-one zerotier-idtool ln -sf zerotier-one zerotier-idtool
ln -sf zerotier-one zerotier-cli ln -sf zerotier-one zerotier-cli
$(CODESIGN) -f -s $(CODESIGN_APP_CERT) zerotier-one $(CODESIGN) -f -s $(CODESIGN_APP_CERT) zerotier-one
zerotier-one: one
zerotier-idtool: one
zerotier-cli: one
libzerotiercore.a: $(CORE_OBJS)
ar rcs libzerotiercore.a $(CORE_OBJS)
ranlib libzerotiercore.a
core: libzerotiercore.a
macui: FORCE macui: FORCE
cd macui && xcodebuild -target "ZeroTier One" -configuration Release cd macui && xcodebuild -target "ZeroTier One" -configuration Release
$(CODESIGN) -f -s $(CODESIGN_APP_CERT) "macui/build/Release/ZeroTier One.app" $(CODESIGN) -f -s $(CODESIGN_APP_CERT) "macui/build/Release/ZeroTier One.app"
@@ -81,10 +97,12 @@ macui: FORCE
# $(CXX) $(CXXFLAGS) -o zerotier cli/zerotier.cpp osdep/OSUtils.cpp node/InetAddress.cpp node/Utils.cpp node/Salsa20.cpp node/Identity.cpp node/SHA512.cpp node/C25519.cpp -lcurl # $(CXX) $(CXXFLAGS) -o zerotier cli/zerotier.cpp osdep/OSUtils.cpp node/InetAddress.cpp node/Utils.cpp node/Salsa20.cpp node/Identity.cpp node/SHA512.cpp node/C25519.cpp -lcurl
# $(STRIP) zerotier # $(STRIP) zerotier
selftest: $(OBJS) selftest.o selftest: $(CORE_OBJS) $(ONE_OBJS) selftest.o
$(CXX) $(CXXFLAGS) -o zerotier-selftest selftest.o $(OBJS) $(LIBS) $(CXX) $(CXXFLAGS) -o zerotier-selftest selftest.o $(CORE_OBJS) $(ONE_OBJS) $(LIBS)
$(STRIP) zerotier-selftest $(STRIP) zerotier-selftest
zerotier-selftest: selftest
# Requires Packages: http://s.sudre.free.fr/Software/Packages/about.html # Requires Packages: http://s.sudre.free.fr/Software/Packages/about.html
mac-dist-pkg: FORCE mac-dist-pkg: FORCE
packagesbuild "ext/installfiles/mac/ZeroTier One.pkgproj" packagesbuild "ext/installfiles/mac/ZeroTier One.pkgproj"
@@ -102,7 +120,7 @@ official: FORCE
make ZT_OFFICIAL_RELEASE=1 mac-dist-pkg make ZT_OFFICIAL_RELEASE=1 mac-dist-pkg
clean: clean:
rm -rf *.dSYM build-* *.pkg *.dmg *.o node/*.o controller/*.o service/*.o osdep/*.o ext/http-parser/*.o $(OBJS) zerotier-one zerotier-idtool zerotier-selftest zerotier-cli zerotier mkworld doc/node_modules macui/build zt1_update_$(ZT_BUILD_PLATFORM)_$(ZT_BUILD_ARCHITECTURE)_* rm -rf *.dSYM build-* *.a *.pkg *.dmg *.o node/*.o controller/*.o service/*.o osdep/*.o ext/http-parser/*.o $(CORE_OBJS) $(ONE_OBJS) zerotier-one zerotier-idtool zerotier-selftest zerotier-cli zerotier doc/node_modules macui/build zt1_update_$(ZT_BUILD_PLATFORM)_$(ZT_BUILD_ARCHITECTURE)_*
distclean: clean distclean: clean

View File

@@ -123,7 +123,7 @@ public:
inline Buffer &operator=(const Buffer<C2> &b) inline Buffer &operator=(const Buffer<C2> &b)
throw(std::out_of_range) throw(std::out_of_range)
{ {
if (b._l > C) if (unlikely(b._l > C))
throw std::out_of_range("Buffer: assignment from buffer larger than capacity"); throw std::out_of_range("Buffer: assignment from buffer larger than capacity");
memcpy(_b,b._b,_l = b._l); memcpy(_b,b._b,_l = b._l);
return *this; return *this;
@@ -139,7 +139,7 @@ public:
inline void copyFrom(const void *b,unsigned int l) inline void copyFrom(const void *b,unsigned int l)
throw(std::out_of_range) throw(std::out_of_range)
{ {
if (l > C) if (unlikely(l > C))
throw std::out_of_range("Buffer: set from C array larger than capacity"); throw std::out_of_range("Buffer: set from C array larger than capacity");
_l = l; _l = l;
memcpy(_b,b,l); memcpy(_b,b,l);
@@ -148,7 +148,7 @@ public:
unsigned char operator[](const unsigned int i) const unsigned char operator[](const unsigned int i) const
throw(std::out_of_range) throw(std::out_of_range)
{ {
if (i >= _l) if (unlikely(i >= _l))
throw std::out_of_range("Buffer: [] beyond end of data"); throw std::out_of_range("Buffer: [] beyond end of data");
return (unsigned char)_b[i]; return (unsigned char)_b[i];
} }
@@ -156,7 +156,7 @@ public:
unsigned char &operator[](const unsigned int i) unsigned char &operator[](const unsigned int i)
throw(std::out_of_range) throw(std::out_of_range)
{ {
if (i >= _l) if (unlikely(i >= _l))
throw std::out_of_range("Buffer: [] beyond end of data"); throw std::out_of_range("Buffer: [] beyond end of data");
return ((unsigned char *)_b)[i]; return ((unsigned char *)_b)[i];
} }
@@ -177,14 +177,14 @@ public:
unsigned char *field(unsigned int i,unsigned int l) unsigned char *field(unsigned int i,unsigned int l)
throw(std::out_of_range) throw(std::out_of_range)
{ {
if ((i + l) > _l) if (unlikely((i + l) > _l))
throw std::out_of_range("Buffer: field() beyond end of data"); throw std::out_of_range("Buffer: field() beyond end of data");
return (unsigned char *)(_b + i); return (unsigned char *)(_b + i);
} }
const unsigned char *field(unsigned int i,unsigned int l) const const unsigned char *field(unsigned int i,unsigned int l) const
throw(std::out_of_range) throw(std::out_of_range)
{ {
if ((i + l) > _l) if (unlikely((i + l) > _l))
throw std::out_of_range("Buffer: field() beyond end of data"); throw std::out_of_range("Buffer: field() beyond end of data");
return (const unsigned char *)(_b + i); return (const unsigned char *)(_b + i);
} }
@@ -200,7 +200,7 @@ public:
inline void setAt(unsigned int i,const T v) inline void setAt(unsigned int i,const T v)
throw(std::out_of_range) throw(std::out_of_range)
{ {
if ((i + sizeof(T)) > _l) if (unlikely((i + sizeof(T)) > _l))
throw std::out_of_range("Buffer: setAt() beyond end of data"); throw std::out_of_range("Buffer: setAt() beyond end of data");
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_TYPE_PUNNING
uint8_t *p = reinterpret_cast<uint8_t *>(_b + i); uint8_t *p = reinterpret_cast<uint8_t *>(_b + i);
@@ -223,7 +223,7 @@ public:
inline T at(unsigned int i) const inline T at(unsigned int i) const
throw(std::out_of_range) throw(std::out_of_range)
{ {
if ((i + sizeof(T)) > _l) if (unlikely((i + sizeof(T)) > _l))
throw std::out_of_range("Buffer: at() beyond end of data"); throw std::out_of_range("Buffer: at() beyond end of data");
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_TYPE_PUNNING
T v = 0; T v = 0;
@@ -250,7 +250,7 @@ public:
inline void append(const T v) inline void append(const T v)
throw(std::out_of_range) throw(std::out_of_range)
{ {
if ((_l + sizeof(T)) > C) if (unlikely((_l + sizeof(T)) > C))
throw std::out_of_range("Buffer: append beyond capacity"); throw std::out_of_range("Buffer: append beyond capacity");
#ifdef ZT_NO_TYPE_PUNNING #ifdef ZT_NO_TYPE_PUNNING
uint8_t *p = reinterpret_cast<uint8_t *>(_b + _l); uint8_t *p = reinterpret_cast<uint8_t *>(_b + _l);
@@ -273,7 +273,7 @@ public:
inline void append(unsigned char c,unsigned int n) inline void append(unsigned char c,unsigned int n)
throw(std::out_of_range) throw(std::out_of_range)
{ {
if ((_l + n) > C) if (unlikely((_l + n) > C))
throw std::out_of_range("Buffer: append beyond capacity"); throw std::out_of_range("Buffer: append beyond capacity");
for(unsigned int i=0;i<n;++i) for(unsigned int i=0;i<n;++i)
_b[_l++] = (char)c; _b[_l++] = (char)c;
@@ -289,7 +289,7 @@ public:
inline void append(const void *b,unsigned int l) inline void append(const void *b,unsigned int l)
throw(std::out_of_range) throw(std::out_of_range)
{ {
if ((_l + l) > C) if (unlikely((_l + l) > C))
throw std::out_of_range("Buffer: append beyond capacity"); throw std::out_of_range("Buffer: append beyond capacity");
memcpy(_b + _l,b,l); memcpy(_b + _l,b,l);
_l += l; _l += l;
@@ -317,7 +317,7 @@ public:
throw(std::out_of_range) throw(std::out_of_range)
{ {
for(;;) { for(;;) {
if (_l >= C) if (unlikely(_l >= C))
throw std::out_of_range("Buffer: append beyond capacity"); throw std::out_of_range("Buffer: append beyond capacity");
if (!(_b[_l++] = *(s++))) if (!(_b[_l++] = *(s++)))
break; break;
@@ -351,7 +351,7 @@ public:
inline char *appendField(unsigned int l) inline char *appendField(unsigned int l)
throw(std::out_of_range) throw(std::out_of_range)
{ {
if ((_l + l) > C) if (unlikely((_l + l) > C))
throw std::out_of_range("Buffer: append beyond capacity"); throw std::out_of_range("Buffer: append beyond capacity");
char *r = _b + _l; char *r = _b + _l;
_l += l; _l += l;
@@ -369,7 +369,7 @@ public:
inline void addSize(unsigned int i) inline void addSize(unsigned int i)
throw(std::out_of_range) throw(std::out_of_range)
{ {
if ((i + _l) > C) if (unlikely((i + _l) > C))
throw std::out_of_range("Buffer: setSize to larger than capacity"); throw std::out_of_range("Buffer: setSize to larger than capacity");
_l += i; _l += i;
} }
@@ -385,7 +385,7 @@ public:
inline void setSize(const unsigned int i) inline void setSize(const unsigned int i)
throw(std::out_of_range) throw(std::out_of_range)
{ {
if (i > C) if (unlikely(i > C))
throw std::out_of_range("Buffer: setSize to larger than capacity"); throw std::out_of_range("Buffer: setSize to larger than capacity");
_l = i; _l = i;
} }
@@ -401,7 +401,7 @@ public:
{ {
if (!at) if (!at)
return; return;
if (at > _l) if (unlikely(at > _l))
throw std::out_of_range("Buffer: behead() beyond capacity"); throw std::out_of_range("Buffer: behead() beyond capacity");
::memmove(_b,_b + at,_l -= at); ::memmove(_b,_b + at,_l -= at);
} }
@@ -417,7 +417,7 @@ public:
throw(std::out_of_range) throw(std::out_of_range)
{ {
const unsigned int endr = at + length; const unsigned int endr = at + length;
if (endr > _l) if (unlikely(endr > _l))
throw std::out_of_range("Buffer: erase() range beyond end of buffer"); throw std::out_of_range("Buffer: erase() range beyond end of buffer");
::memmove(_b + at,_b + endr,_l - endr); ::memmove(_b + at,_b + endr,_l - endr);
_l -= length; _l -= length;

View File

@@ -257,7 +257,7 @@ void Cluster::handleIncomingStateMessage(const void *msg,unsigned int len)
memcpy(keytmp,_key,32); memcpy(keytmp,_key,32);
for(int i=0;i<8;++i) for(int i=0;i<8;++i)
keytmp[i] ^= reinterpret_cast<const char *>(msg)[i]; keytmp[i] ^= reinterpret_cast<const char *>(msg)[i];
Salsa20 s20(keytmp,256,reinterpret_cast<const char *>(msg) + 8); Salsa20 s20(keytmp,reinterpret_cast<const char *>(msg) + 8);
Utils::burn(keytmp,sizeof(keytmp)); Utils::burn(keytmp,sizeof(keytmp));
// One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard") // One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard")
@@ -956,7 +956,7 @@ void Cluster::_flush(uint16_t memberId)
memcpy(keytmp,m.key,32); memcpy(keytmp,m.key,32);
for(int i=0;i<8;++i) for(int i=0;i<8;++i)
keytmp[i] ^= m.q[i]; keytmp[i] ^= m.q[i];
Salsa20 s20(keytmp,256,m.q.field(8,8)); Salsa20 s20(keytmp,m.q.field(8,8));
Utils::burn(keytmp,sizeof(keytmp)); Utils::burn(keytmp,sizeof(keytmp));
// One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard") // One-time-use Poly1305 key from first 32 bytes of Salsa20 keystream (as per DJB/NaCl "standard")

View File

@@ -60,6 +60,8 @@
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
#define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0)
#include <TargetConditionals.h> #include <TargetConditionals.h>
#ifndef __UNIX_LIKE__ #ifndef __UNIX_LIKE__
#define __UNIX_LIKE__ #define __UNIX_LIKE__
@@ -132,6 +134,22 @@
#include <endian.h> #include <endian.h>
#endif #endif
#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)
#ifndef likely
#define likely(x) __builtin_expect((x),1)
#endif
#ifndef unlikely
#define unlikely(x) __builtin_expect((x),0)
#endif
#else
#ifndef likely
#define likely(x) (x)
#endif
#ifndef unlikely
#define unlikely(x) (x)
#endif
#endif
/** /**
* Length of a ZeroTier address in bytes * Length of a ZeroTier address in bytes
*/ */
@@ -159,15 +177,12 @@
/** /**
* Default MTU used for Ethernet tap device * Default MTU used for Ethernet tap device
*/ */
#define ZT_IF_MTU ZT_MAX_MTU #define ZT_DEFAULT_MTU 2800
/** /**
* Maximum number of packet fragments we'll support * Maximum number of packet fragments we'll support (protocol max: 16)
*
* The actual spec allows 16, but this is the most we'll support right
* now. Packets with more than this many fragments are dropped.
*/ */
#define ZT_MAX_PACKET_FRAGMENTS 4 #define ZT_MAX_PACKET_FRAGMENTS 7
/** /**
* Size of RX queue * Size of RX queue
@@ -372,7 +387,7 @@
/** /**
* Time horizon for push direct paths cutoff * Time horizon for push direct paths cutoff
*/ */
#define ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME 60000 #define ZT_PUSH_DIRECT_PATHS_CUTOFF_TIME 30000
/** /**
* Maximum number of direct path pushes within cutoff time * Maximum number of direct path pushes within cutoff time
@@ -381,12 +396,12 @@
* per CUTOFF_TIME milliseconds per peer to prevent this from being * per CUTOFF_TIME milliseconds per peer to prevent this from being
* useful for DOS amplification attacks. * useful for DOS amplification attacks.
*/ */
#define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 5 #define ZT_PUSH_DIRECT_PATHS_CUTOFF_LIMIT 8
/** /**
* Maximum number of paths per IP scope (e.g. global, link-local) and family (e.g. v4/v6) * Maximum number of paths per IP scope (e.g. global, link-local) and family (e.g. v4/v6)
*/ */
#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 4 #define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 8
/** /**
* Time horizon for VERB_NETWORK_CREDENTIALS cutoff * Time horizon for VERB_NETWORK_CREDENTIALS cutoff

View File

@@ -115,8 +115,6 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr)
case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,tPtr,peer); case Packet::VERB_MULTICAST_GATHER: return _doMULTICAST_GATHER(RR,tPtr,peer);
case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,tPtr,peer); case Packet::VERB_MULTICAST_FRAME: return _doMULTICAST_FRAME(RR,tPtr,peer);
case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,tPtr,peer); case Packet::VERB_PUSH_DIRECT_PATHS: return _doPUSH_DIRECT_PATHS(RR,tPtr,peer);
case Packet::VERB_CIRCUIT_TEST: return _doCIRCUIT_TEST(RR,tPtr,peer);
case Packet::VERB_CIRCUIT_TEST_REPORT: return _doCIRCUIT_TEST_REPORT(RR,tPtr,peer);
case Packet::VERB_USER_MESSAGE: return _doUSER_MESSAGE(RR,tPtr,peer); case Packet::VERB_USER_MESSAGE: return _doUSER_MESSAGE(RR,tPtr,peer);
} }
} else { } else {
@@ -1125,7 +1123,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
//TRACE("<<MC FRAME %.16llx/%s from %s@%s flags %.2x length %u",nwid,to.toString().c_str(),from.toString().c_str(),peer->address().toString().c_str(),flags,frameLen); //TRACE("<<MC FRAME %.16llx/%s from %s@%s flags %.2x length %u",nwid,to.toString().c_str(),from.toString().c_str(),peer->address().toString().c_str(),flags,frameLen);
if ((frameLen > 0)&&(frameLen <= ZT_IF_MTU)) { if ((frameLen > 0)&&(frameLen <= ZT_MAX_MTU)) {
if (!to.mac().isMulticast()) { if (!to.mac().isMulticast()) {
TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str()); TRACE("dropped MULTICAST_FRAME from %s@%s(%s) to %s: destination is unicast, must use FRAME or EXT_FRAME",from.toString().c_str(),peer->address().toString().c_str(),_path->address().toString().c_str(),to.toString().c_str());
peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true); // trustEstablished because COM is okay
@@ -1185,7 +1183,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
// First, subject this to a rate limit // First, subject this to a rate limit
if (!peer->rateGatePushDirectPaths(now)) { if (!peer->rateGatePushDirectPaths(now)) {
TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str()); //TRACE("dropped PUSH_DIRECT_PATHS from %s(%s): circuit breaker tripped",source().toString().c_str(),_path->address().toString().c_str());
peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_PUSH_DIRECT_PATHS,0,Packet::VERB_NOP,false);
return true; return true;
} }
@@ -1220,7 +1218,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0);
} else { } else {
TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); //TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
} }
} }
} break; } break;
@@ -1237,7 +1235,7 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str()); TRACE("attempting to contact %s at pushed direct path %s",peer->address().toString().c_str(),a.toString().c_str());
peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0); peer->attemptToContactAt(tPtr,InetAddress(),a,now,false,0);
} else { } else {
TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str()); //TRACE("ignoring contact for %s at %s -- too many per scope",peer->address().toString().c_str(),a.toString().c_str());
} }
} }
} break; } break;
@@ -1252,196 +1250,6 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
return true; return true;
} }
bool IncomingPacket::_doCIRCUIT_TEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
try {
const Address originatorAddress(field(ZT_PACKET_IDX_PAYLOAD,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
SharedPtr<Peer> originator(RR->topology->getPeer(tPtr,originatorAddress));
if (!originator) {
RR->sw->requestWhois(tPtr,originatorAddress);
return false;
}
const unsigned int flags = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 5);
const uint64_t timestamp = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 7);
const uint64_t testId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 15);
// Tracks total length of variable length fields, initialized to originator credential length below
unsigned int vlf;
// Originator credentials -- right now only a network ID for which the originator is controller or is authorized by controller is allowed
const unsigned int originatorCredentialLength = vlf = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 23);
uint64_t originatorCredentialNetworkId = 0;
if (originatorCredentialLength >= 1) {
switch((*this)[ZT_PACKET_IDX_PAYLOAD + 25]) {
case 0x01: { // 64-bit network ID, originator must be controller
if (originatorCredentialLength >= 9)
originatorCredentialNetworkId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 26);
} break;
default: break;
}
}
// Add length of "additional fields," which are currently unused
vlf += at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 25 + vlf);
// Verify signature -- only tests signed by their originators are allowed
const unsigned int signatureLength = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 27 + vlf);
if (!originator->identity().verify(field(ZT_PACKET_IDX_PAYLOAD,27 + vlf),27 + vlf,field(ZT_PACKET_IDX_PAYLOAD + 29 + vlf,signatureLength),signatureLength)) {
TRACE("dropped CIRCUIT_TEST from %s(%s): signature by originator %s invalid",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str());
peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false);
return true;
}
vlf += signatureLength;
// Save this length so we can copy the immutable parts of this test
// into the one we send along to next hops.
const unsigned int lengthOfSignedPortionAndSignature = 29 + vlf;
// Add length of second "additional fields" section.
vlf += at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 29 + vlf);
uint64_t reportFlags = 0;
// Check credentials (signature already verified)
if (originatorCredentialNetworkId) {
SharedPtr<Network> network(RR->node->network(originatorCredentialNetworkId));
if ((!network)||(!network->config().circuitTestingAllowed(originatorAddress))) {
TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s specified network ID %.16llx as credential, and we don't belong to that network or originator is not allowed'",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str(),originatorCredentialNetworkId);
peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false);
return true;
}
if (network->gate(tPtr,peer))
reportFlags |= ZT_CIRCUIT_TEST_REPORT_FLAGS_UPSTREAM_AUTHORIZED_IN_PATH;
} else {
TRACE("dropped CIRCUIT_TEST from %s(%s): originator %s did not specify a credential or credential type",source().toString().c_str(),_path->address().toString().c_str(),originatorAddress.toString().c_str());
peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false);
return true;
}
const uint64_t now = RR->node->now();
unsigned int breadth = 0;
Address nextHop[256]; // breadth is a uin8_t, so this is the max
InetAddress nextHopBestPathAddress[256];
unsigned int remainingHopsPtr = ZT_PACKET_IDX_PAYLOAD + 33 + vlf;
if ((ZT_PACKET_IDX_PAYLOAD + 31 + vlf) < size()) {
// unsigned int nextHopFlags = (*this)[ZT_PACKET_IDX_PAYLOAD + 31 + vlf]
breadth = (*this)[ZT_PACKET_IDX_PAYLOAD + 32 + vlf];
for(unsigned int h=0;h<breadth;++h) {
nextHop[h].setTo(field(remainingHopsPtr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH);
remainingHopsPtr += ZT_ADDRESS_LENGTH;
SharedPtr<Peer> nhp(RR->topology->getPeer(tPtr,nextHop[h]));
if (nhp) {
SharedPtr<Path> nhbp(nhp->getBestPath(now,false));
if ((nhbp)&&(nhbp->alive(now)))
nextHopBestPathAddress[h] = nhbp->address();
}
}
}
// Report back to originator, depending on flags and whether we are last hop
if ( ((flags & 0x01) != 0) || ((breadth == 0)&&((flags & 0x02) != 0)) ) {
Packet outp(originatorAddress,RR->identity.address(),Packet::VERB_CIRCUIT_TEST_REPORT);
outp.append((uint64_t)timestamp);
outp.append((uint64_t)testId);
outp.append((uint64_t)0); // field reserved for future use
outp.append((uint8_t)ZT_VENDOR_ZEROTIER);
outp.append((uint8_t)ZT_PROTO_VERSION);
outp.append((uint8_t)ZEROTIER_ONE_VERSION_MAJOR);
outp.append((uint8_t)ZEROTIER_ONE_VERSION_MINOR);
outp.append((uint16_t)ZEROTIER_ONE_VERSION_REVISION);
outp.append((uint16_t)ZT_PLATFORM_UNSPECIFIED);
outp.append((uint16_t)ZT_ARCHITECTURE_UNSPECIFIED);
outp.append((uint16_t)0); // error code, currently unused
outp.append((uint64_t)reportFlags);
outp.append((uint64_t)packetId());
peer->address().appendTo(outp);
outp.append((uint8_t)hops());
_path->localAddress().serialize(outp);
_path->address().serialize(outp);
outp.append((uint16_t)_path->linkQuality());
outp.append((uint8_t)breadth);
for(unsigned int h=0;h<breadth;++h) {
nextHop[h].appendTo(outp);
nextHopBestPathAddress[h].serialize(outp); // appends 0 if null InetAddress
}
RR->sw->send(tPtr,outp,true);
}
// If there are next hops, forward the test along through the graph
if (breadth > 0) {
Packet outp(Address(),RR->identity.address(),Packet::VERB_CIRCUIT_TEST);
outp.append(field(ZT_PACKET_IDX_PAYLOAD,lengthOfSignedPortionAndSignature),lengthOfSignedPortionAndSignature);
outp.append((uint16_t)0); // no additional fields
if (remainingHopsPtr < size())
outp.append(field(remainingHopsPtr,size() - remainingHopsPtr),size() - remainingHopsPtr);
for(unsigned int h=0;h<breadth;++h) {
if (RR->identity.address() != nextHop[h]) { // next hops that loop back to the current hop are not valid
outp.newInitializationVector();
outp.setDestination(nextHop[h]);
RR->sw->send(tPtr,outp,true);
}
}
}
peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST,0,Packet::VERB_NOP,false);
} catch ( ... ) {
TRACE("dropped CIRCUIT_TEST from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
}
return true;
}
bool IncomingPacket::_doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{
try {
ZT_CircuitTestReport report;
memset(&report,0,sizeof(report));
report.current = peer->address().toInt();
report.upstream = Address(field(ZT_PACKET_IDX_PAYLOAD + 52,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt();
report.testId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 8);
report.timestamp = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD);
report.sourcePacketId = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 44);
report.flags = at<uint64_t>(ZT_PACKET_IDX_PAYLOAD + 36);
report.sourcePacketHopCount = (*this)[ZT_PACKET_IDX_PAYLOAD + 57]; // end of fixed length headers: 58
report.errorCode = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 34);
report.vendor = (enum ZT_Vendor)((*this)[ZT_PACKET_IDX_PAYLOAD + 24]);
report.protocolVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 25];
report.majorVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 26];
report.minorVersion = (*this)[ZT_PACKET_IDX_PAYLOAD + 27];
report.revision = at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 28);
report.platform = (enum ZT_Platform)at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 30);
report.architecture = (enum ZT_Architecture)at<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 32);
const unsigned int receivedOnLocalAddressLen = reinterpret_cast<InetAddress *>(&(report.receivedOnLocalAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58);
const unsigned int receivedFromRemoteAddressLen = reinterpret_cast<InetAddress *>(&(report.receivedFromRemoteAddress))->deserialize(*this,ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen);
unsigned int ptr = ZT_PACKET_IDX_PAYLOAD + 58 + receivedOnLocalAddressLen + receivedFromRemoteAddressLen;
if (report.protocolVersion >= 9) {
report.receivedFromLinkQuality = at<uint16_t>(ptr); ptr += 2;
} else {
report.receivedFromLinkQuality = ZT_PATH_LINK_QUALITY_MAX;
ptr += at<uint16_t>(ptr) + 2; // this field was once an 'extended field length' reserved field, which was always set to 0
}
report.nextHopCount = (*this)[ptr++];
if (report.nextHopCount > ZT_CIRCUIT_TEST_MAX_HOP_BREADTH) // sanity check, shouldn't be possible
report.nextHopCount = ZT_CIRCUIT_TEST_MAX_HOP_BREADTH;
for(unsigned int h=0;h<report.nextHopCount;++h) {
report.nextHops[h].address = Address(field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH).toInt(); ptr += ZT_ADDRESS_LENGTH;
ptr += reinterpret_cast<InetAddress *>(&(report.nextHops[h].physicalAddress))->deserialize(*this,ptr);
}
RR->node->postCircuitTestReport(&report);
peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false);
} catch ( ... ) {
TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
}
return true;
}
bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer) bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{ {
try { try {
@@ -1453,9 +1261,9 @@ bool IncomingPacket::_doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,con
um.length = size() - (ZT_PACKET_IDX_PAYLOAD + 8); um.length = size() - (ZT_PACKET_IDX_PAYLOAD + 8);
RR->node->postEvent(tPtr,ZT_EVENT_USER_MESSAGE,reinterpret_cast<const void *>(&um)); RR->node->postEvent(tPtr,ZT_EVENT_USER_MESSAGE,reinterpret_cast<const void *>(&um));
} }
peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_CIRCUIT_TEST_REPORT,0,Packet::VERB_NOP,false); peer->received(tPtr,_path,hops(),packetId(),Packet::VERB_USER_MESSAGE,0,Packet::VERB_NOP,false);
} catch ( ... ) { } catch ( ... ) {
TRACE("dropped CIRCUIT_TEST_REPORT from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str()); TRACE("dropped USER_MESSAGE from %s(%s): unexpected exception",source().toString().c_str(),_path->address().toString().c_str());
} }
return true; return true;
} }

View File

@@ -138,8 +138,6 @@ private:
bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doCIRCUIT_TEST(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doCIRCUIT_TEST_REPORT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doUSER_MESSAGE(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid); void _sendErrorNeedCredentials(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer,const uint64_t nwid);

View File

@@ -1225,6 +1225,8 @@ void Network::requestConfiguration(void *tPtr)
nconf->revision = 1; nconf->revision = 1;
nconf->issuedTo = RR->identity.address(); nconf->issuedTo = RR->identity.address();
nconf->flags = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION; nconf->flags = ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION;
nconf->mtu = ZT_DEFAULT_MTU;
nconf->multicastLimit = 0;
nconf->staticIpCount = 1; nconf->staticIpCount = 1;
nconf->ruleCount = 14; nconf->ruleCount = 14;
nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,RR->identity.address().toInt()); nconf->staticIps[0] = InetAddress::makeIpv66plane(_id,RR->identity.address().toInt());
@@ -1495,7 +1497,7 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const
else ec->name[0] = (char)0; else ec->name[0] = (char)0;
ec->status = _status(); ec->status = _status();
ec->type = (_config) ? (_config.isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) : ZT_NETWORK_TYPE_PRIVATE; ec->type = (_config) ? (_config.isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) : ZT_NETWORK_TYPE_PRIVATE;
ec->mtu = ZT_IF_MTU; ec->mtu = (_config) ? _config.mtu : ZT_DEFAULT_MTU;
ec->physicalMtu = ZT_UDP_DEFAULT_PAYLOAD_MTU - (ZT_PACKET_IDX_PAYLOAD + 16); ec->physicalMtu = ZT_UDP_DEFAULT_PAYLOAD_MTU - (ZT_PACKET_IDX_PAYLOAD + 16);
ec->dhcp = 0; ec->dhcp = 0;
std::vector<Address> ab(_config.activeBridges()); std::vector<Address> ab(_config.activeBridges());

View File

@@ -51,6 +51,7 @@ bool NetworkConfig::toDictionary(Dictionary<ZT_NETWORKCONFIG_DICT_CAPACITY> &d,b
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name)) return false;
if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MTU,(uint64_t)this->mtu)) return false;
#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
if (includeLegacy) { if (includeLegacy) {
@@ -217,6 +218,12 @@ bool NetworkConfig::fromDictionary(const Dictionary<ZT_NETWORKCONFIG_DICT_CAPACI
this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,0); this->multicastLimit = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,0);
d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name,sizeof(this->name)); d.get(ZT_NETWORKCONFIG_DICT_KEY_NAME,this->name,sizeof(this->name));
this->mtu = (unsigned int)d.getUI(ZT_NETWORKCONFIG_DICT_KEY_MTU,ZT_DEFAULT_MTU);
if (this->mtu < 1280)
this->mtu = 1280; // minimum MTU allowed by IPv6 standard and others
else if (this->mtu > ZT_MAX_MTU)
this->mtu = ZT_MAX_MTU;
if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION,0) < 6) { if (d.getUI(ZT_NETWORKCONFIG_DICT_KEY_VERSION,0) < 6) {
#ifdef ZT_SUPPORT_OLD_STYLE_NETCONF #ifdef ZT_SUPPORT_OLD_STYLE_NETCONF
char tmp2[1024]; char tmp2[1024];

View File

@@ -167,6 +167,8 @@ namespace ZeroTier {
#define ZT_NETWORKCONFIG_DICT_KEY_TYPE "t" #define ZT_NETWORKCONFIG_DICT_KEY_TYPE "t"
// text // text
#define ZT_NETWORKCONFIG_DICT_KEY_NAME "n" #define ZT_NETWORKCONFIG_DICT_KEY_NAME "n"
// network MTU
#define ZT_NETWORKCONFIG_DICT_KEY_MTU "mtu"
// credential time max delta in ms // credential time max delta in ms
#define ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA "ctmd" #define ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA "ctmd"
// binary serialized certificate of membership // binary serialized certificate of membership
@@ -465,6 +467,11 @@ public:
*/ */
uint64_t flags; uint64_t flags;
/**
* Network MTU
*/
unsigned int mtu;
/** /**
* Maximum number of recipients per multicast (not including active bridges) * Maximum number of recipients per multicast (not including active bridges)
*/ */

View File

@@ -327,6 +327,7 @@ ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr)
} else { } else {
if (uptr) if (uptr)
*uptr = *n->second->userPtr(); *uptr = *n->second->userPtr();
n->second->externalConfig(&ctmp);
n->second->destroy(); n->second->destroy();
nUserPtr = n->second->userPtr(); nUserPtr = n->second->userPtr();
} }
@@ -502,64 +503,6 @@ void Node::setNetconfMaster(void *networkControllerInstance)
RR->localNetworkController->init(RR->identity,this); RR->localNetworkController->init(RR->identity,this);
} }
ZT_ResultCode Node::circuitTestBegin(void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *))
{
if (test->hopCount > 0) {
try {
Packet outp(Address(),RR->identity.address(),Packet::VERB_CIRCUIT_TEST);
RR->identity.address().appendTo(outp);
outp.append((uint16_t)((test->reportAtEveryHop != 0) ? 0x03 : 0x02));
outp.append((uint64_t)test->timestamp);
outp.append((uint64_t)test->testId);
outp.append((uint16_t)0); // originator credential length, updated later
if (test->credentialNetworkId) {
outp.append((uint8_t)0x01);
outp.append((uint64_t)test->credentialNetworkId);
outp.setAt<uint16_t>(ZT_PACKET_IDX_PAYLOAD + 23,(uint16_t)9);
}
outp.append((uint16_t)0);
C25519::Signature sig(RR->identity.sign(reinterpret_cast<const char *>(outp.data()) + ZT_PACKET_IDX_PAYLOAD,outp.size() - ZT_PACKET_IDX_PAYLOAD));
outp.append((uint16_t)sig.size());
outp.append(sig.data,(unsigned int)sig.size());
outp.append((uint16_t)0); // originator doesn't need an extra credential, since it's the originator
for(unsigned int h=1;h<test->hopCount;++h) {
outp.append((uint8_t)0);
outp.append((uint8_t)(test->hops[h].breadth & 0xff));
for(unsigned int a=0;a<test->hops[h].breadth;++a)
Address(test->hops[h].addresses[a]).appendTo(outp);
}
for(unsigned int a=0;a<test->hops[0].breadth;++a) {
outp.newInitializationVector();
outp.setDestination(Address(test->hops[0].addresses[a]));
RR->sw->send(tptr,outp,true);
}
} catch ( ... ) {
return ZT_RESULT_FATAL_ERROR_INTERNAL; // probably indicates FIFO too big for packet
}
}
{
test->_internalPtr = reinterpret_cast<void *>(reportCallback);
Mutex::Lock _l(_circuitTests_m);
if (std::find(_circuitTests.begin(),_circuitTests.end(),test) == _circuitTests.end())
_circuitTests.push_back(test);
}
return ZT_RESULT_OK;
}
void Node::circuitTestEnd(ZT_CircuitTest *test)
{
Mutex::Lock _l(_circuitTests_m);
for(;;) {
std::vector< ZT_CircuitTest * >::iterator ct(std::find(_circuitTests.begin(),_circuitTests.end(),test));
if (ct == _circuitTests.end())
break;
else _circuitTests.erase(ct);
}
}
ZT_ResultCode Node::clusterInit( ZT_ResultCode Node::clusterInit(
unsigned int myId, unsigned int myId,
const struct sockaddr_storage *zeroTierPhysicalEndpoints, const struct sockaddr_storage *zeroTierPhysicalEndpoints,
@@ -714,20 +657,6 @@ uint64_t Node::prng()
return z + y; return z + y;
} }
void Node::postCircuitTestReport(const ZT_CircuitTestReport *report)
{
std::vector< ZT_CircuitTest * > toNotify;
{
Mutex::Lock _l(_circuitTests_m);
for(std::vector< ZT_CircuitTest * >::iterator i(_circuitTests.begin());i!=_circuitTests.end();++i) {
if ((*i)->testId == report->testId)
toNotify.push_back(*i);
}
}
for(std::vector< ZT_CircuitTest * >::iterator i(toNotify.begin());i!=toNotify.end();++i)
(reinterpret_cast<void (*)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *)>((*i)->_internalPtr))(reinterpret_cast<ZT_Node *>(this),*i,report);
}
void Node::setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count) void Node::setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count)
{ {
RR->topology->setTrustedPaths(reinterpret_cast<const InetAddress *>(networks),ids,count); RR->topology->setTrustedPaths(reinterpret_cast<const InetAddress *>(networks),ids,count);
@@ -1069,22 +998,6 @@ void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance)
} catch ( ... ) {} } catch ( ... ) {}
} }
enum ZT_ResultCode ZT_Node_circuitTestBegin(ZT_Node *node,void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *))
{
try {
return reinterpret_cast<ZeroTier::Node *>(node)->circuitTestBegin(tptr,test,reportCallback);
} catch ( ... ) {
return ZT_RESULT_FATAL_ERROR_INTERNAL;
}
}
void ZT_Node_circuitTestEnd(ZT_Node *node,ZT_CircuitTest *test)
{
try {
reinterpret_cast<ZeroTier::Node *>(node)->circuitTestEnd(test);
} catch ( ... ) {}
}
enum ZT_ResultCode ZT_Node_clusterInit( enum ZT_ResultCode ZT_Node_clusterInit(
ZT_Node *node, ZT_Node *node,
unsigned int myId, unsigned int myId,

View File

@@ -117,8 +117,6 @@ public:
void clearLocalInterfaceAddresses(); void clearLocalInterfaceAddresses();
int sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len); int sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *data,unsigned int len);
void setNetconfMaster(void *networkControllerInstance); void setNetconfMaster(void *networkControllerInstance);
ZT_ResultCode circuitTestBegin(void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *));
void circuitTestEnd(ZT_CircuitTest *test);
ZT_ResultCode clusterInit( ZT_ResultCode clusterInit(
unsigned int myId, unsigned int myId,
const struct sockaddr_storage *zeroTierPhysicalEndpoints, const struct sockaddr_storage *zeroTierPhysicalEndpoints,
@@ -219,7 +217,6 @@ public:
inline bool externalPathLookup(void *tPtr,const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ztaddr.toInt(),family,reinterpret_cast<struct sockaddr_storage *>(&addr)) != 0) : false ); } inline bool externalPathLookup(void *tPtr,const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast<ZT_Node *>(this),_uPtr,tPtr,ztaddr.toInt(),family,reinterpret_cast<struct sockaddr_storage *>(&addr)) != 0) : false ); }
uint64_t prng(); uint64_t prng();
void postCircuitTestReport(const ZT_CircuitTestReport *report);
void setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count); void setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count);
World planet() const; World planet() const;
@@ -309,9 +306,6 @@ private:
std::vector< std::pair< uint64_t, SharedPtr<Network> > > _networks; std::vector< std::pair< uint64_t, SharedPtr<Network> > > _networks;
Mutex _networks_m; Mutex _networks_m;
std::vector< ZT_CircuitTest * > _circuitTests;
Mutex _circuitTests_m;
std::vector<InetAddress> _directPaths; std::vector<InetAddress> _directPaths;
Mutex _directPaths_m; Mutex _directPaths_m;

View File

@@ -320,6 +320,7 @@ union LZ4_streamDecode_u {
#define FORCE_INLINE static inline #define FORCE_INLINE static inline
#endif #endif
#if 0
#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__) #if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__)
# define expect(expr,value) (__builtin_expect ((expr),(value)) ) # define expect(expr,value) (__builtin_expect ((expr),(value)) )
#else #else
@@ -328,6 +329,7 @@ union LZ4_streamDecode_u {
#define likely(expr) expect((expr) != 0, 1) #define likely(expr) expect((expr) != 0, 1)
#define unlikely(expr) expect((expr) != 0, 0) #define unlikely(expr) expect((expr) != 0, 0)
#endif
/*-************************************ /*-************************************
* Memory routines * Memory routines
@@ -1080,8 +1082,6 @@ const char *Packet::verbString(Verb v)
case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER"; case VERB_MULTICAST_GATHER: return "MULTICAST_GATHER";
case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME"; case VERB_MULTICAST_FRAME: return "MULTICAST_FRAME";
case VERB_PUSH_DIRECT_PATHS: return "PUSH_DIRECT_PATHS"; case VERB_PUSH_DIRECT_PATHS: return "PUSH_DIRECT_PATHS";
case VERB_CIRCUIT_TEST: return "CIRCUIT_TEST";
case VERB_CIRCUIT_TEST_REPORT: return "CIRCUIT_TEST_REPORT";
case VERB_USER_MESSAGE: return "USER_MESSAGE"; case VERB_USER_MESSAGE: return "USER_MESSAGE";
} }
return "(unknown)"; return "(unknown)";

View File

@@ -61,7 +61,7 @@
* 4 - 0.6.0 ... 1.0.6 * 4 - 0.6.0 ... 1.0.6
* + BREAKING CHANGE: New identity format based on hashcash design * + BREAKING CHANGE: New identity format based on hashcash design
* 5 - 1.1.0 ... 1.1.5 * 5 - 1.1.0 ... 1.1.5
* + Supports circuit test, proof of work, and echo * + Supports echo
* + Supports in-band world (root server definition) updates * + Supports in-band world (root server definition) updates
* + Clustering! (Though this will work with protocol v4 clients.) * + Clustering! (Though this will work with protocol v4 clients.)
* + Otherwise backward compatible with protocol v4 * + Otherwise backward compatible with protocol v4
@@ -954,119 +954,7 @@ public:
*/ */
VERB_PUSH_DIRECT_PATHS = 0x10, VERB_PUSH_DIRECT_PATHS = 0x10,
/** // 0x11, 0x12 -- deprecated
* Source-routed circuit test message:
* <[5] address of originator of circuit test>
* <[2] 16-bit flags>
* <[8] 64-bit timestamp>
* <[8] 64-bit test ID (arbitrary, set by tester)>
* <[2] 16-bit originator credential length (includes type)>
* [[1] originator credential type (for authorizing test)]
* [[...] originator credential]
* <[2] 16-bit length of additional fields>
* [[...] additional fields]
* [ ... end of signed portion of request ... ]
* <[2] 16-bit length of signature of request>
* <[...] signature of request by originator>
* <[2] 16-bit length of additional fields>
* [[...] additional fields]
* <[...] next hop(s) in path>
*
* Flags:
* 0x01 - Report back to originator at all hops
* 0x02 - Report back to originator at last hop
*
* Originator credential types:
* 0x01 - 64-bit network ID for which originator is controller
*
* Path record format:
* <[1] 8-bit flags (unused, must be zero)>
* <[1] 8-bit breadth (number of next hops)>
* <[...] one or more ZeroTier addresses of next hops>
*
* The circuit test allows a device to send a message that will traverse
* the network along a specified path, with each hop optionally reporting
* back to the tester via VERB_CIRCUIT_TEST_REPORT.
*
* Each circuit test packet includes a digital signature by the originator
* of the request, as well as a credential by which that originator claims
* authorization to perform the test. Currently this signature is ed25519,
* but in the future flags might be used to indicate an alternative
* algorithm. For example, the originator might be a network controller.
* In this case the test might be authorized if the recipient is a member
* of a network controlled by it, and if the previous hop(s) are also
* members. Each hop may include its certificate of network membership.
*
* Circuit test paths consist of a series of records. When a node receives
* an authorized circuit test, it:
*
* (1) Reports back to circuit tester as flags indicate
* (2) Reads and removes the next hop from the packet's path
* (3) Sends the packet along to next hop(s), if any.
*
* It is perfectly legal for a path to contain the same hop more than
* once. In fact, this can be a very useful test to determine if a hop
* can be reached bidirectionally and if so what that connectivity looks
* like.
*
* The breadth field in source-routed path records allows a hop to forward
* to more than one recipient, allowing the tester to specify different
* forms of graph traversal in a test.
*
* There is no hard limit to the number of hops in a test, but it is
* practically limited by the maximum size of a (possibly fragmented)
* ZeroTier packet.
*
* Support for circuit tests is optional. If they are not supported, the
* node should respond with an UNSUPPORTED_OPERATION error. If a circuit
* test request is not authorized, it may be ignored or reported as
* an INVALID_REQUEST. No OK messages are generated, but TEST_REPORT
* messages may be sent (see below).
*
* ERROR packet format:
* <[8] 64-bit timestamp (echoed from original>
* <[8] 64-bit test ID (echoed from original)>
*/
VERB_CIRCUIT_TEST = 0x11,
/**
* Circuit test hop report:
* <[8] 64-bit timestamp (echoed from original test)>
* <[8] 64-bit test ID (echoed from original test)>
* <[8] 64-bit reserved field (set to 0, currently unused)>
* <[1] 8-bit vendor ID (set to 0, currently unused)>
* <[1] 8-bit reporter protocol version>
* <[1] 8-bit reporter software major version>
* <[1] 8-bit reporter software minor version>
* <[2] 16-bit reporter software revision>
* <[2] 16-bit reporter OS/platform or 0 if not specified>
* <[2] 16-bit reporter architecture or 0 if not specified>
* <[2] 16-bit error code (set to 0, currently unused)>
* <[8] 64-bit report flags>
* <[8] 64-bit packet ID of received CIRCUIT_TEST packet>
* <[5] upstream ZeroTier address from which CIRCUIT_TEST was received>
* <[1] 8-bit packet hop count of received CIRCUIT_TEST>
* <[...] local wire address on which packet was received>
* <[...] remote wire address from which packet was received>
* <[2] 16-bit path link quality of path over which packet was received>
* <[1] 8-bit number of next hops (breadth)>
* <[...] next hop information>
*
* Next hop information record format:
* <[5] ZeroTier address of next hop>
* <[...] current best direct path address, if any, 0 if none>
*
* Report flags:
* 0x1 - Upstream peer in circuit test path allowed in path (e.g. network COM valid)
*
* Circuit test reports can be sent by hops in a circuit test to report
* back results. They should include information about the sender as well
* as about the paths to which next hops are being sent.
*
* If a test report is received and no circuit test was sent, it should be
* ignored. This message generates no OK or ERROR response.
*/
VERB_CIRCUIT_TEST_REPORT = 0x12,
/** /**
* A message with arbitrary user-definable content: * A message with arbitrary user-definable content:

View File

@@ -1,6 +1,4 @@
OBJS=\ CORE_OBJS=\
controller/EmbeddedNetworkController.o \
controller/JSONDB.o \
node/C25519.o \ node/C25519.o \
node/Capability.o \ node/Capability.o \
node/CertificateOfMembership.o \ node/CertificateOfMembership.o \
@@ -26,9 +24,15 @@ OBJS=\
node/Switch.o \ node/Switch.o \
node/Tag.o \ node/Tag.o \
node/Topology.o \ node/Topology.o \
node/Utils.o \ node/Utils.o
ONE_OBJS=\
controller/EmbeddedNetworkController.o \
controller/JSONDB.o \
osdep/ManagedRoute.o \ osdep/ManagedRoute.o \
osdep/Http.o \ osdep/Http.o \
osdep/OSUtils.o \ osdep/OSUtils.o \
service/ClusterGeoIpService.o \ service/ClusterGeoIpService.o \
service/SoftwareUpdater.o service/SoftwareUpdater.o \
service/OneService.o

View File

@@ -1488,7 +1488,8 @@ int main(int argc,char **argv)
#ifdef __UNIX_LIKE__ #ifdef __UNIX_LIKE__
#ifdef ZT_HAVE_DROP_PRIVILEGES #ifdef ZT_HAVE_DROP_PRIVILEGES
dropPrivileges(argv[0],homeDir); if (!skipRootCheck)
dropPrivileges(argv[0],homeDir);
#endif #endif
std::string pidPath(homeDir + ZT_PATH_SEPARATOR_S + ZT_PID_PATH); std::string pidPath(homeDir + ZT_PATH_SEPARATOR_S + ZT_PID_PATH);

View File

@@ -94,9 +94,6 @@ BSDEthernetTap::BSDEthernetTap(
Mutex::Lock _gl(globalTapCreateLock); Mutex::Lock _gl(globalTapCreateLock);
if (mtu > 2800)
throw std::runtime_error("max tap MTU is 2800");
#ifdef __FreeBSD__ #ifdef __FreeBSD__
/* FreeBSD allows long interface names and interface renaming */ /* FreeBSD allows long interface names and interface renaming */
@@ -321,7 +318,7 @@ std::vector<InetAddress> BSDEthernetTap::ips() const
void BSDEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) void BSDEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
{ {
char putBuf[4096]; char putBuf[ZT_MAX_MTU + 64];
if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) {
to.copyTo(putBuf,6); to.copyTo(putBuf,6);
from.copyTo(putBuf + 6,6); from.copyTo(putBuf + 6,6);
@@ -381,49 +378,22 @@ void BSDEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std:
_multicastGroups.swap(newGroups); _multicastGroups.swap(newGroups);
} }
/* void BSDEthernetTap::setMtu(unsigned int mtu)
bool BSDEthernetTap::updateMulticastGroups(std::set<MulticastGroup> &groups)
{ {
std::set<MulticastGroup> newGroups; if (mtu != _mtu) {
struct ifmaddrs *ifmap = (struct ifmaddrs *)0; _mtu = mtu;
if (!getifmaddrs(&ifmap)) { long cpid = (long)vfork();
struct ifmaddrs *p = ifmap; if (cpid == 0) {
while (p) { char tmp[64];
if (p->ifma_addr->sa_family == AF_LINK) { Utils::snprintf(tmp,sizeof(tmp),"%u",mtu);
struct sockaddr_dl *in = (struct sockaddr_dl *)p->ifma_name; execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"mtu",tmp,(const char *)0);
struct sockaddr_dl *la = (struct sockaddr_dl *)p->ifma_addr; _exit(-1);
if ((la->sdl_alen == 6)&&(in->sdl_nlen <= _dev.length())&&(!memcmp(_dev.data(),in->sdl_data,in->sdl_nlen))) } else if (cpid > 0) {
newGroups.insert(MulticastGroup(MAC(la->sdl_data + la->sdl_nlen,6),0)); int exitcode = -1;
} waitpid(cpid,&exitcode,0);
p = p->ifma_next;
}
freeifmaddrs(ifmap);
}
{
std::set<InetAddress> allIps(ips());
for(std::set<InetAddress>::const_iterator i(allIps.begin());i!=allIps.end();++i)
newGroups.insert(MulticastGroup::deriveMulticastGroupForAddressResolution(*i));
}
bool changed = false;
for(std::set<MulticastGroup>::iterator mg(newGroups.begin());mg!=newGroups.end();++mg) {
if (!groups.count(*mg)) {
groups.insert(*mg);
changed = true;
} }
} }
for(std::set<MulticastGroup>::iterator mg(groups.begin());mg!=groups.end();) {
if ((!newGroups.count(*mg))&&(*mg != _blindWildcardMulticastGroup)) {
groups.erase(mg++);
changed = true;
} else ++mg;
}
return changed;
} }
*/
void BSDEthernetTap::threadMain() void BSDEthernetTap::threadMain()
throw() throw()
@@ -431,7 +401,7 @@ void BSDEthernetTap::threadMain()
fd_set readfds,nullfds; fd_set readfds,nullfds;
MAC to,from; MAC to,from;
int n,nfds,r; int n,nfds,r;
char getBuf[8194]; char getBuf[ZT_MAX_MTU + 64];
// Wait for a moment after startup -- wait for Network to finish // Wait for a moment after startup -- wait for Network to finish
// constructing itself. // constructing itself.

View File

@@ -65,6 +65,7 @@ public:
std::string deviceName() const; std::string deviceName() const;
void setFriendlyName(const char *friendlyName); void setFriendlyName(const char *friendlyName);
void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed); void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
void setMtu(unsigned int mtu);
void threadMain() void threadMain()
throw(); throw();

View File

@@ -71,12 +71,7 @@
* *
* OneService also does this on detected restarts. * OneService also does this on detected restarts.
*/ */
#ifdef ZT_SDK
#define ZT_BINDER_REFRESH_PERIOD 5000
#else
#define ZT_BINDER_REFRESH_PERIOD 30000 #define ZT_BINDER_REFRESH_PERIOD 30000
#endif
namespace ZeroTier { namespace ZeroTier {

View File

@@ -48,6 +48,7 @@
#include <algorithm> #include <algorithm>
#include <utility> #include <utility>
#include <string>
#include "../node/Constants.hpp" #include "../node/Constants.hpp"
#include "../node/Utils.hpp" #include "../node/Utils.hpp"
@@ -63,6 +64,19 @@ namespace ZeroTier {
static Mutex __tapCreateLock; static Mutex __tapCreateLock;
static const char _base32_chars[32] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','2','3','4','5','6','7' };
static void _base32_5_to_8(const uint8_t *in,char *out)
{
out[0] = _base32_chars[(in[0]) >> 3];
out[1] = _base32_chars[(in[0] & 0x07) << 2 | (in[1] & 0xc0) >> 6];
out[2] = _base32_chars[(in[1] & 0x3e) >> 1];
out[3] = _base32_chars[(in[1] & 0x01) << 4 | (in[2] & 0xf0) >> 4];
out[4] = _base32_chars[(in[2] & 0x0f) << 1 | (in[3] & 0x80) >> 7];
out[5] = _base32_chars[(in[3] & 0x7c) >> 2];
out[6] = _base32_chars[(in[3] & 0x03) << 3 | (in[4] & 0xe0) >> 5];
out[7] = _base32_chars[(in[4] & 0x1f)];
}
LinuxEthernetTap::LinuxEthernetTap( LinuxEthernetTap::LinuxEthernetTap(
const char *homePath, const char *homePath,
const MAC &mac, const MAC &mac,
@@ -87,9 +101,6 @@ LinuxEthernetTap::LinuxEthernetTap(
Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally Mutex::Lock _l(__tapCreateLock); // create only one tap at a time, globally
if (mtu > 2800)
throw std::runtime_error("max tap MTU is 2800");
_fd = ::open("/dev/net/tun",O_RDWR); _fd = ::open("/dev/net/tun",O_RDWR);
if (_fd <= 0) { if (_fd <= 0) {
_fd = ::open("/dev/tun",O_RDWR); _fd = ::open("/dev/tun",O_RDWR);
@@ -100,7 +111,7 @@ LinuxEthernetTap::LinuxEthernetTap(
struct ifreq ifr; struct ifreq ifr;
memset(&ifr,0,sizeof(ifr)); memset(&ifr,0,sizeof(ifr));
// Try to recall our last device name, or pick an unused one if that fails. // Restore device names from legacy devicemap, but for new devices we use a base32-based canonical naming
std::map<std::string,std::string> globalDeviceMap; std::map<std::string,std::string> globalDeviceMap;
FILE *devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"r"); FILE *devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"r");
if (devmapf) { if (devmapf) {
@@ -126,17 +137,30 @@ LinuxEthernetTap::LinuxEthernetTap(
Utils::snprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name); Utils::snprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
recalledDevice = (stat(procpath,&sbuf) != 0); recalledDevice = (stat(procpath,&sbuf) != 0);
} }
if (!recalledDevice) { if (!recalledDevice) {
int devno = 0;
do {
#ifdef __SYNOLOGY__ #ifdef __SYNOLOGY__
devno+=50; // Arbitrary number to prevent interface name conflicts int devno = 50;
do {
Utils::snprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"eth%d",devno++); Utils::snprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"eth%d",devno++);
#else
Utils::snprintf(ifr.ifr_name,sizeof(ifr.ifr_name),"zt%d",devno++);
#endif
Utils::snprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name); Utils::snprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
} while (stat(procpath,&sbuf) == 0); // try zt#++ until we find one that does not exist } while (stat(procpath,&sbuf) == 0); // try zt#++ until we find one that does not exist
#else
char devno = 0;
do {
uint64_t tmp2[2];
tmp2[0] = Utils::hton(nwid);
tmp2[1] = 0;
char tmp3[17];
tmp3[0] = 'z';
tmp3[1] = 't' + (devno++);
_base32_5_to_8(reinterpret_cast<const uint8_t *>(tmp2),tmp3 + 2);
_base32_5_to_8(reinterpret_cast<const uint8_t *>(tmp2) + 5,tmp3 + 10);
tmp3[15] = (char)0;
memcpy(ifr.ifr_name,tmp3,16);
Utils::snprintf(procpath,sizeof(procpath),"/proc/sys/net/ipv4/conf/%s",ifr.ifr_name);
} while (stat(procpath,&sbuf) == 0);
#endif
} }
ifr.ifr_flags = IFF_TAP | IFF_NO_PI; ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
@@ -199,6 +223,7 @@ LinuxEthernetTap::LinuxEthernetTap(
(void)::pipe(_shutdownSignalPipe); (void)::pipe(_shutdownSignalPipe);
/*
globalDeviceMap[nwids] = _dev; globalDeviceMap[nwids] = _dev;
devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"w"); devmapf = fopen((_homePath + ZT_PATH_SEPARATOR_S + "devicemap").c_str(),"w");
if (devmapf) { if (devmapf) {
@@ -209,6 +234,7 @@ LinuxEthernetTap::LinuxEthernetTap(
} }
fclose(devmapf); fclose(devmapf);
} }
*/
_thread = Thread::start(this); _thread = Thread::start(this);
} }
@@ -386,7 +412,7 @@ std::vector<InetAddress> LinuxEthernetTap::ips() const
void LinuxEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) void LinuxEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
{ {
char putBuf[8194]; char putBuf[ZT_MAX_MTU + 64];
if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) {
to.copyTo(putBuf,6); to.copyTo(putBuf,6);
from.copyTo(putBuf + 6,6); from.copyTo(putBuf + 6,6);
@@ -455,13 +481,28 @@ void LinuxEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,st
_multicastGroups.swap(newGroups); _multicastGroups.swap(newGroups);
} }
void LinuxEthernetTap::setMtu(unsigned int mtu)
{
if (_mtu != mtu) {
_mtu = mtu;
int sock = socket(AF_INET,SOCK_DGRAM,0);
if (sock > 0) {
struct ifreq ifr;
memset(&ifr,0,sizeof(ifr));
ifr.ifr_ifru.ifru_mtu = (int)mtu;
ioctl(sock,SIOCSIFMTU,(void *)&ifr);
close(sock);
}
}
}
void LinuxEthernetTap::threadMain() void LinuxEthernetTap::threadMain()
throw() throw()
{ {
fd_set readfds,nullfds; fd_set readfds,nullfds;
MAC to,from; MAC to,from;
int n,nfds,r; int n,nfds,r;
char getBuf[8194]; char getBuf[ZT_MAX_MTU + 64];
Thread::sleep(500); Thread::sleep(500);

View File

@@ -69,6 +69,7 @@ public:
std::string deviceName() const; std::string deviceName() const;
void setFriendlyName(const char *friendlyName); void setFriendlyName(const char *friendlyName);
void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed); void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
void setMtu(unsigned int mtu);
void threadMain() void threadMain()
throw(); throw();

View File

@@ -51,6 +51,9 @@
#include <sys/time.h> #include <sys/time.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#ifdef __LINUX__
#include <sys/syscall.h>
#endif
#endif #endif
#include "../ext/json/json.hpp" #include "../ext/json/json.hpp"
@@ -185,7 +188,6 @@ public:
* @return Current time in milliseconds since epoch * @return Current time in milliseconds since epoch
*/ */
static inline uint64_t now() static inline uint64_t now()
throw()
{ {
#ifdef __WINDOWS__ #ifdef __WINDOWS__
FILETIME ft; FILETIME ft;
@@ -198,33 +200,15 @@ public:
return ( ((tmp.QuadPart - 116444736000000000ULL) / 10000L) + st.wMilliseconds ); return ( ((tmp.QuadPart - 116444736000000000ULL) / 10000L) + st.wMilliseconds );
#else #else
struct timeval tv; struct timeval tv;
#ifdef __LINUX__
syscall(SYS_gettimeofday,&tv,0); /* fix for musl libc broken gettimeofday bug */
#else
gettimeofday(&tv,(struct timezone *)0); gettimeofday(&tv,(struct timezone *)0);
#endif
return ( (1000ULL * (uint64_t)tv.tv_sec) + (uint64_t)(tv.tv_usec / 1000) ); return ( (1000ULL * (uint64_t)tv.tv_sec) + (uint64_t)(tv.tv_usec / 1000) );
#endif #endif
}; };
/**
* @return Current time in seconds since epoch, to the highest available resolution
*/
static inline double nowf()
throw()
{
#ifdef __WINDOWS__
FILETIME ft;
SYSTEMTIME st;
ULARGE_INTEGER tmp;
GetSystemTime(&st);
SystemTimeToFileTime(&st,&ft);
tmp.LowPart = ft.dwLowDateTime;
tmp.HighPart = ft.dwHighDateTime;
return (((double)(tmp.QuadPart - 116444736000000000ULL)) / 10000000.0);
#else
struct timeval tv;
gettimeofday(&tv,(struct timezone *)0);
return ( ((double)tv.tv_sec) + (((double)tv.tv_usec) / 1000000.0) );
#endif
}
/** /**
* Read the full contents of a file into a string buffer * Read the full contents of a file into a string buffer
* *

View File

@@ -338,9 +338,6 @@ OSXEthernetTap::OSXEthernetTap(
Utils::snprintf(nwids,sizeof(nwids),"%.16llx",nwid); Utils::snprintf(nwids,sizeof(nwids),"%.16llx",nwid);
if (mtu > 2800)
throw std::runtime_error("max tap MTU is 2800");
Mutex::Lock _gl(globalTapCreateLock); Mutex::Lock _gl(globalTapCreateLock);
if (::stat("/dev/zt0",&stattmp)) { if (::stat("/dev/zt0",&stattmp)) {
@@ -574,7 +571,7 @@ std::vector<InetAddress> OSXEthernetTap::ips() const
void OSXEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) void OSXEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
{ {
char putBuf[4096]; char putBuf[ZT_MAX_MTU + 64];
if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) { if ((_fd > 0)&&(len <= _mtu)&&(_enabled)) {
to.copyTo(putBuf,6); to.copyTo(putBuf,6);
from.copyTo(putBuf + 6,6); from.copyTo(putBuf + 6,6);
@@ -632,13 +629,30 @@ void OSXEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,std:
_multicastGroups.swap(newGroups); _multicastGroups.swap(newGroups);
} }
void OSXEthernetTap::setMtu(unsigned int mtu)
{
if (mtu != _mtu) {
_mtu = mtu;
long cpid = (long)vfork();
if (cpid == 0) {
char tmp[64];
Utils::snprintf(tmp,sizeof(tmp),"%u",mtu);
execl("/sbin/ifconfig","/sbin/ifconfig",_dev.c_str(),"mtu",tmp,(const char *)0);
_exit(-1);
} else if (cpid > 0) {
int exitcode = -1;
waitpid(cpid,&exitcode,0);
}
}
}
void OSXEthernetTap::threadMain() void OSXEthernetTap::threadMain()
throw() throw()
{ {
fd_set readfds,nullfds; fd_set readfds,nullfds;
MAC to,from; MAC to,from;
int n,nfds,r; int n,nfds,r;
char getBuf[8194]; char getBuf[ZT_MAX_MTU + 64];
Thread::sleep(500); Thread::sleep(500);

View File

@@ -70,6 +70,7 @@ public:
std::string deviceName() const; std::string deviceName() const;
void setFriendlyName(const char *friendlyName); void setFriendlyName(const char *friendlyName);
void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed); void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
void setMtu(unsigned int mtu);
void threadMain() void threadMain()
throw(); throw();

View File

@@ -139,6 +139,10 @@ public:
{ {
} }
inline void setMtu(unsigned int mtu)
{
}
private: private:
uint64_t _nwid; uint64_t _nwid;
std::string _dev; std::string _dev;

View File

@@ -470,6 +470,7 @@ WindowsEthernetTap::WindowsEthernetTap(
_arg(arg), _arg(arg),
_mac(mac), _mac(mac),
_nwid(nwid), _nwid(nwid),
_mtu(mtu),
_tap(INVALID_HANDLE_VALUE), _tap(INVALID_HANDLE_VALUE),
_injectSemaphore(INVALID_HANDLE_VALUE), _injectSemaphore(INVALID_HANDLE_VALUE),
_pathToHelpers(hp), _pathToHelpers(hp),
@@ -481,10 +482,6 @@ WindowsEthernetTap::WindowsEthernetTap(
char subkeyClass[1024]; char subkeyClass[1024];
char data[1024]; char data[1024];
char tag[24]; char tag[24];
std::string mySubkeyName;
if (mtu > 2800)
throw std::runtime_error("MTU too large.");
// We "tag" registry entries with the network ID to identify persistent devices // We "tag" registry entries with the network ID to identify persistent devices
Utils::snprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)nwid); Utils::snprintf(tag,sizeof(tag),"%.16llx",(unsigned long long)nwid);
@@ -530,7 +527,7 @@ WindowsEthernetTap::WindowsEthernetTap(
_netCfgInstanceId = instanceId; _netCfgInstanceId = instanceId;
_deviceInstanceId = instanceIdPath; _deviceInstanceId = instanceIdPath;
mySubkeyName = subkeyName; _mySubkeyName = subkeyName;
break; // found it! break; // found it!
} }
} }
@@ -573,7 +570,7 @@ WindowsEthernetTap::WindowsEthernetTap(
if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS) if (RegGetValueA(nwAdapters,subkeyName,"DeviceInstanceID",RRF_RT_ANY,&type,(PVOID)data,&dataLen) == ERROR_SUCCESS)
_deviceInstanceId.assign(data,dataLen); _deviceInstanceId.assign(data,dataLen);
mySubkeyName = subkeyName; _mySubkeyName = subkeyName;
// Disable DHCP by default on new devices // Disable DHCP by default on new devices
HKEY tcpIpInterfaces; HKEY tcpIpInterfaces;
@@ -605,24 +602,24 @@ WindowsEthernetTap::WindowsEthernetTap(
if (_netCfgInstanceId.length() > 0) { if (_netCfgInstanceId.length() > 0) {
char tmps[64]; char tmps[64];
unsigned int tmpsl = Utils::snprintf(tmps,sizeof(tmps),"%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",(unsigned int)mac[0],(unsigned int)mac[1],(unsigned int)mac[2],(unsigned int)mac[3],(unsigned int)mac[4],(unsigned int)mac[5]) + 1; unsigned int tmpsl = Utils::snprintf(tmps,sizeof(tmps),"%.2X-%.2X-%.2X-%.2X-%.2X-%.2X",(unsigned int)mac[0],(unsigned int)mac[1],(unsigned int)mac[2],(unsigned int)mac[3],(unsigned int)mac[4],(unsigned int)mac[5]) + 1;
RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"NetworkAddress",REG_SZ,tmps,tmpsl); RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"NetworkAddress",REG_SZ,tmps,tmpsl);
RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"MAC",REG_SZ,tmps,tmpsl); RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"MAC",REG_SZ,tmps,tmpsl);
tmpsl = Utils::snprintf(tmps, sizeof(tmps), "%d", mtu); tmpsl = Utils::snprintf(tmps, sizeof(tmps), "%d", mtu);
RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"MTU",REG_SZ,tmps,tmpsl); RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"MTU",REG_SZ,tmps,tmpsl);
DWORD tmp = 0; DWORD tmp = 0;
RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"*NdisDeviceType",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp)); RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"*NdisDeviceType",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp));
tmp = IF_TYPE_ETHERNET_CSMACD; tmp = IF_TYPE_ETHERNET_CSMACD;
RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"*IfType",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp)); RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"*IfType",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp));
if (creatingNewDevice) { if (creatingNewDevice) {
// Vista/2008 does not set this // Vista/2008 does not set this
if (newDeviceInstanceId.length() > 0) if (newDeviceInstanceId.length() > 0)
RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"DeviceInstanceID",REG_SZ,newDeviceInstanceId.c_str(),(DWORD)newDeviceInstanceId.length()); RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"DeviceInstanceID",REG_SZ,newDeviceInstanceId.c_str(),(DWORD)newDeviceInstanceId.length());
// Set EnableDHCP to 0 by default on new devices // Set EnableDHCP to 0 by default on new devices
tmp = 0; tmp = 0;
RegSetKeyValueA(nwAdapters,mySubkeyName.c_str(),"EnableDHCP",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp)); RegSetKeyValueA(nwAdapters,_mySubkeyName.c_str(),"EnableDHCP",REG_DWORD,(LPCVOID)&tmp,sizeof(tmp));
} }
RegCloseKey(nwAdapters); RegCloseKey(nwAdapters);
} else { } else {
@@ -792,11 +789,11 @@ std::vector<InetAddress> WindowsEthernetTap::ips() const
void WindowsEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len) void WindowsEthernetTap::put(const MAC &from,const MAC &to,unsigned int etherType,const void *data,unsigned int len)
{ {
if ((!_initialized)||(!_enabled)||(_tap == INVALID_HANDLE_VALUE)||(len > (ZT_IF_MTU))) if ((!_initialized)||(!_enabled)||(_tap == INVALID_HANDLE_VALUE)||(len > _mtu))
return; return;
Mutex::Lock _l(_injectPending_m); Mutex::Lock _l(_injectPending_m);
_injectPending.push( std::pair<Array<char,ZT_IF_MTU + 32>,unsigned int>(Array<char,ZT_IF_MTU + 32>(),len + 14) ); _injectPending.push( std::pair<Array<char,ZT_MAX_MTU + 32>,unsigned int>(Array<char,ZT_MAX_MTU + 32>(),len + 14) );
char *d = _injectPending.back().first.data; char *d = _injectPending.back().first.data;
to.copyTo(d,6); to.copyTo(d,6);
from.copyTo(d + 6,6); from.copyTo(d + 6,6);
@@ -875,6 +872,20 @@ void WindowsEthernetTap::scanMulticastGroups(std::vector<MulticastGroup> &added,
_multicastGroups.swap(newGroups); _multicastGroups.swap(newGroups);
} }
void WindowsEthernetTap::setMtu(unsigned int mtu)
{
if (mtu != _mtu) {
_mtu = mtu;
HKEY nwAdapters;
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Control\\Class\\{4D36E972-E325-11CE-BFC1-08002BE10318}", 0, KEY_READ | KEY_WRITE, &nwAdapters) == ERROR_SUCCESS) {
char tmps[64];
unsigned int tmpsl = Utils::snprintf(tmps, sizeof(tmps), "%d", mtu);
RegSetKeyValueA(nwAdapters, _mySubkeyName.c_str(), "MTU", REG_SZ, tmps, tmpsl);
RegCloseKey(nwAdapters);
}
}
}
NET_IFINDEX WindowsEthernetTap::interfaceIndex() const NET_IFINDEX WindowsEthernetTap::interfaceIndex() const
{ {
NET_IFINDEX idx = -1; NET_IFINDEX idx = -1;
@@ -886,7 +897,7 @@ NET_IFINDEX WindowsEthernetTap::interfaceIndex() const
void WindowsEthernetTap::threadMain() void WindowsEthernetTap::threadMain()
throw() throw()
{ {
char tapReadBuf[ZT_IF_MTU + 32]; char tapReadBuf[ZT_MAX_MTU + 32];
char tapPath[128]; char tapPath[128];
HANDLE wait4[3]; HANDLE wait4[3];
OVERLAPPED tapOvlRead,tapOvlWrite; OVERLAPPED tapOvlRead,tapOvlWrite;
@@ -1015,13 +1026,16 @@ void WindowsEthernetTap::threadMain()
ReadFile(_tap,tapReadBuf,sizeof(tapReadBuf),NULL,&tapOvlRead); ReadFile(_tap,tapReadBuf,sizeof(tapReadBuf),NULL,&tapOvlRead);
bool writeInProgress = false; bool writeInProgress = false;
ULONGLONG timeOfLastBorkCheck = GetTickCount64(); ULONGLONG timeOfLastBorkCheck = GetTickCount64();
_initialized = true;
unsigned int oldmtu = _mtu;
_initialized = true;
while (_run) { while (_run) {
DWORD waitResult = WaitForMultipleObjectsEx(writeInProgress ? 3 : 2,wait4,FALSE,2500,TRUE); DWORD waitResult = WaitForMultipleObjectsEx(writeInProgress ? 3 : 2,wait4,FALSE,2500,TRUE);
if (!_run) break; // will also break outer while(_run) if (!_run) break; // will also break outer while(_run) since _run is false
// Check for changes in MTU and break to restart tap device to reconfigure in this case
if (_mtu != oldmtu)
break;
// Check for issues with adapter and close/reopen if any are detected. This // Check for issues with adapter and close/reopen if any are detected. This
// check fixes a while boatload of Windows adapter 'coma' issues after // check fixes a while boatload of Windows adapter 'coma' issues after
@@ -1070,7 +1084,7 @@ void WindowsEthernetTap::threadMain()
} catch ( ... ) {} // handlers should not throw } catch ( ... ) {} // handlers should not throw
} }
} }
ReadFile(_tap,tapReadBuf,ZT_IF_MTU + 32,NULL,&tapOvlRead); ReadFile(_tap,tapReadBuf,ZT_MAX_MTU + 32,NULL,&tapOvlRead);
} }
if (writeInProgress) { if (writeInProgress) {

View File

@@ -109,6 +109,7 @@ public:
std::string deviceName() const; std::string deviceName() const;
void setFriendlyName(const char *friendlyName); void setFriendlyName(const char *friendlyName);
void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed); void scanMulticastGroups(std::vector<MulticastGroup> &added,std::vector<MulticastGroup> &removed);
void setMtu(unsigned int mtu);
inline const NET_LUID &luid() const { return _deviceLuid; } inline const NET_LUID &luid() const { return _deviceLuid; }
inline const GUID &guid() const { return _deviceGuid; } inline const GUID &guid() const { return _deviceGuid; }
@@ -130,6 +131,7 @@ private:
void *_arg; void *_arg;
MAC _mac; MAC _mac;
uint64_t _nwid; uint64_t _nwid;
volatile unsigned int _mtu;
Thread _thread; Thread _thread;
volatile HANDLE _tap; volatile HANDLE _tap;
@@ -139,13 +141,14 @@ private:
NET_LUID _deviceLuid; NET_LUID _deviceLuid;
std::string _netCfgInstanceId; std::string _netCfgInstanceId;
std::string _deviceInstanceId; std::string _deviceInstanceId;
std::string _mySubkeyName;
std::vector<InetAddress> _assignedIps; // IPs assigned with addIp std::vector<InetAddress> _assignedIps; // IPs assigned with addIp
Mutex _assignedIps_m; Mutex _assignedIps_m;
std::vector<MulticastGroup> _multicastGroups; std::vector<MulticastGroup> _multicastGroups;
std::queue< std::pair< Array<char,ZT_IF_MTU + 32>,unsigned int > > _injectPending; std::queue< std::pair< Array<char,ZT_MAX_MTU + 32>,unsigned int > > _injectPending;
Mutex _injectPending_m; Mutex _injectPending_m;
std::string _pathToHelpers; std::string _pathToHelpers;

View File

@@ -151,8 +151,8 @@ static const C25519TestVector C25519_TEST_VECTORS[ZT_NUM_C25519_TEST_VECTORS] =
static int testCrypto() static int testCrypto()
{ {
unsigned char buf1[16384]; static unsigned char buf1[16384];
unsigned char buf2[sizeof(buf1)],buf3[sizeof(buf1)]; static unsigned char buf2[sizeof(buf1)],buf3[sizeof(buf1)];
for(int i=0;i<3;++i) { for(int i=0;i<3;++i) {
Utils::getSecureRandom(buf1,64); Utils::getSecureRandom(buf1,64);
@@ -1077,6 +1077,7 @@ int main(int argc,char **argv)
*/ */
std::cout << "[info] sizeof(void *) == " << sizeof(void *) << std::endl; std::cout << "[info] sizeof(void *) == " << sizeof(void *) << std::endl;
std::cout << "[info] OSUtils::now() == " << OSUtils::now() << std::endl;
std::cout << "[info] hardware concurrency == " << std::thread::hardware_concurrency() << std::endl; std::cout << "[info] hardware concurrency == " << std::thread::hardware_concurrency() << std::endl;
std::cout << "[info] sizeof(NetworkConfig) == " << sizeof(ZeroTier::NetworkConfig) << std::endl; std::cout << "[info] sizeof(NetworkConfig) == " << sizeof(ZeroTier::NetworkConfig) << std::endl;

View File

@@ -1022,9 +1022,7 @@ public:
for(it = _nets.begin(); it != _nets.end(); it++) { for(it = _nets.begin(); it != _nets.end(); it++) {
if(it->second.tap) { if(it->second.tap) {
for(int j=0; j<it->second.tap->_ips.size(); j++) { for(int j=0; j<it->second.tap->_ips.size(); j++) {
if(it->second.tap->_ips[j].isEqualPrefix(addr) if(it->second.tap->_ips[j].isEqualPrefix(addr) || it->second.tap->_ips[j].ipsEqual(addr)) {
|| it->second.tap->_ips[j].containsAddress(addr)
|| it->second.tap->_ips[j].ipsEqual(addr)) {
return it->second.tap; return it->second.tap;
} }
} }
@@ -2084,16 +2082,17 @@ public:
memcpy(&(n.config),nwc,sizeof(ZT_VirtualNetworkConfig)); memcpy(&(n.config),nwc,sizeof(ZT_VirtualNetworkConfig));
if (n.tap) { // sanity check if (n.tap) { // sanity check
#ifdef __WINDOWS__ #ifdef __WINDOWS__
// wait for up to 5 seconds for the WindowsEthernetTap to actually be initialized // wait for up to 5 seconds for the WindowsEthernetTap to actually be initialized
// //
// without WindowsEthernetTap::isInitialized() returning true, the won't actually // without WindowsEthernetTap::isInitialized() returning true, the won't actually
// be online yet and setting managed routes on it will fail. // be online yet and setting managed routes on it will fail.
const int MAX_SLEEP_COUNT = 500; const int MAX_SLEEP_COUNT = 500;
for (int i = 0; !n.tap->isInitialized() && i < MAX_SLEEP_COUNT; i++) { for (int i = 0; !n.tap->isInitialized() && i < MAX_SLEEP_COUNT; i++) {
Sleep(10); Sleep(10);
} }
#endif #endif
syncManagedStuff(n,true,true); syncManagedStuff(n,true,true);
n.tap->setMtu(nwc->mtu);
} else { } else {
_nets.erase(nwid); _nets.erase(nwid);
return -999; // tap init failed return -999; // tap init failed

View File

@@ -1,173 +0,0 @@
Name: zerotier-one
Version: 1.2.4
Release: 1%{?dist}
Summary: ZeroTier One network virtualization service
License: GPLv3
URL: https://www.zerotier.com
%if 0%{?rhel} >= 7
BuildRequires: systemd
%endif
%if 0%{?fedora} >= 21
BuildRequires: systemd
%endif
Requires: iproute
%if 0%{?rhel} >= 7
Requires: systemd
Requires(pre): /usr/sbin/useradd, /usr/bin/getent
%endif
%if 0%{?rhel} <= 6
Requires: chkconfig
%endif
%if 0%{?fedora} >= 21
Requires: systemd
Requires(pre): /usr/sbin/useradd, /usr/bin/getent
%endif
%description
ZeroTier is a software defined networking layer for Earth.
It can be used for on-premise network virtualization, as a peer to peer VPN
for mobile teams, for hybrid or multi-data-center cloud deployments, or just
about anywhere else secure software defined virtual networking is useful.
ZeroTier One is our OS-level client service. It allows Mac, Linux, Windows,
FreeBSD, and soon other types of clients to join ZeroTier virtual networks
like conventional VPNs or VLANs. It can run on native systems, VMs, or
containers (Docker, OpenVZ, etc.).
%prep
#rm -rf *
#ln -s %{getenv:PWD} %{name}-%{version}
#tar --exclude=%{name}-%{version}/.git --exclude=%{name}-%{version}/%{name}-%{version} -czf %{_sourcedir}/%{name}-%{version}.tar.gz %{name}-%{version}/*
#rm -f %{name}-%{version}
#cp -a %{getenv:PWD}/* .
%build
#%if 0%{?rhel} <= 7
#make CFLAGS="`echo %{optflags} | sed s/stack-protector-strong/stack-protector/`" CXXFLAGS="`echo %{optflags} | sed s/stack-protector-strong/stack-protector/`" ZT_USE_MINIUPNPC=1 %{?_smp_mflags} one manpages selftest
#%else
#make CFLAGS="%{optflags}" CXXFLAGS="%{optflags}" ZT_USE_MINIUPNPC=1 %{?_smp_mflags} one manpages selftest
#%endif
%pre
%if 0%{?rhel} >= 7
/usr/bin/getent passwd zerotier-one || /usr/sbin/useradd -r -d /var/lib/zerotier-one -s /sbin/nologin zerotier-one
%endif
%if 0%{?fedora} >= 21
/usr/bin/getent passwd zerotier-one || /usr/sbin/useradd -r -d /var/lib/zerotier-one -s /sbin/nologin zerotier-one
%endif
%install
rm -rf $RPM_BUILD_ROOT
pushd %{getenv:PWD}
make install DESTDIR=$RPM_BUILD_ROOT
popd
%if 0%{?rhel} >= 7
mkdir -p $RPM_BUILD_ROOT%{_unitdir}
cp %{getenv:PWD}/debian/zerotier-one.service $RPM_BUILD_ROOT%{_unitdir}/%{name}.service
%endif
%if 0%{?fedora} >= 21
mkdir -p $RPM_BUILD_ROOT%{_unitdir}
cp ${getenv:PWD}/debian/zerotier-one.service $RPM_BUILD_ROOT%{_unitdir}/%{name}.service
%endif
%if 0%{?rhel} <= 6
mkdir -p $RPM_BUILD_ROOT/etc/init.d
cp %{getenv:PWD}/ext/installfiles/linux/zerotier-one.init.rhel6 $RPM_BUILD_ROOT/etc/init.d/zerotier-one
chmod 0755 $RPM_BUILD_ROOT/etc/init.d/zerotier-one
%endif
%files
%{_sbindir}/*
%{_mandir}/*
%{_localstatedir}/*
%if 0%{?rhel} >= 7
%{_unitdir}/%{name}.service
%endif
%if 0%{?fedora} >= 21
%{_unitdir}/%{name}.service
%endif
%if 0%{?rhel} <= 6
/etc/init.d/zerotier-one
%endif
%post
%if 0%{?rhel} >= 7
%systemd_post zerotier-one.service
%endif
%if 0%{?fedora} >= 21
%systemd_post zerotier-one.service
%endif
%if 0%{?rhel} <= 6
case "$1" in
1)
chkconfig --add zerotier-one
;;
2)
chkconfig --del newservice
chkconfig --add newservice
;;
esac
%endif
%preun
%if 0%{?rhel} >= 7
%systemd_preun zerotier-one.service
%endif
%if 0%{?fedora} >= 21
%systemd_preun zerotier-one.service
%endif
%if 0%{?rhel} <= 6
case "$1" in
0)
service zerotier-one stop
chkconfig --del zerotier-one
;;
1)
# This is an upgrade.
:
;;
esac
%endif
%postun
%if 0%{?rhel} >= 7
%systemd_postun_with_restart zerotier-one.service
%endif
%if 0%{?fedora} >= 21
%systemd_postun_with_restart zerotier-one.service
%endif
%changelog
* Mon Apr 24 2017 Adam Ierymenko <adam.ierymenko@zerotier.com> - 1.2.2-0.1
- see https://github.com/zerotier/ZeroTierOne for release notes
* Fri Mar 17 2017 Adam Ierymenko <adam.ierymenko@zerotier.com> - 1.2.2-0.1
- see https://github.com/zerotier/ZeroTierOne for release notes
* Tue Mar 14 2017 Adam Ierymenko <adam.ierymenko@zerotier.com> - 1.2.0-0.1
- see https://github.com/zerotier/ZeroTierOne for release notes
* Tue Jul 12 2016 Adam Ierymenko <adam.ierymenko@zerotier.com> - 1.1.10-0.1
- see https://github.com/zerotier/ZeroTierOne for release notes
* Fri Jul 08 2016 Adam Ierymenko <adam.ierymenko@zerotier.com> - 1.1.8-0.1
- see https://github.com/zerotier/ZeroTierOne for release notes
* Sat Jun 25 2016 Adam Ierymenko <adam.ierymenko@zerotier.com> - 1.1.6-0.1
- now builds on CentOS 6 as well as newer distros, and some cleanup
* Wed Jun 08 2016 François Kooman <fkooman@tuxed.net> - 1.1.5-0.3
- include systemd unit file
* Wed Jun 08 2016 François Kooman <fkooman@tuxed.net> - 1.1.5-0.2
- add libnatpmp as (build)dependency
* Wed Jun 08 2016 François Kooman <fkooman@tuxed.net> - 1.1.5-0.1
- initial package