updated core to 1.2.4, fixed pico_device init bug
This commit is contained in:
@@ -39,6 +39,10 @@
|
||||
|
||||
#define ZT_SDK_RPC_DIR_PREFIX "rpc.d"
|
||||
|
||||
#define ZT_CORE_VERSION_MAJOR 1
|
||||
#define ZT_CORE_VERSION_MINOR 2
|
||||
#define ZT_CORE_VERSION_REVISION 4
|
||||
|
||||
#define ZT_SDK_VERSION_MAJOR 1
|
||||
#define ZT_SDK_VERSION_MINOR 0
|
||||
#define ZT_SDK_VERSION_REVISION 0
|
||||
|
||||
@@ -56,6 +56,7 @@ INCLUDES+= -Iext \
|
||||
-I$(ZTO)/node \
|
||||
-I$(ZTO)/service \
|
||||
-I$(ZTO)/include \
|
||||
-I$(ZTO)/controller \
|
||||
-I../$(ZTO)/osdep \
|
||||
-I../$(ZTO)/node \
|
||||
-I../$(ZTO)/service \
|
||||
|
||||
@@ -292,7 +292,7 @@ namespace ZeroTier {
|
||||
const struct sockaddr *from) {}
|
||||
void SocketTap::phyOnTcpClose(PhySocket *sock,void **uptr) {}
|
||||
void SocketTap::phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len) {}
|
||||
void SocketTap::phyOnTcpWritable(PhySocket *sock,void **uptr, bool stack_invoked) {}
|
||||
void SocketTap::phyOnTcpWritable(PhySocket *sock,void **uptr) {}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
|
||||
@@ -135,8 +135,8 @@ namespace ZeroTier {
|
||||
/* Vars */
|
||||
/****************************************************************************/
|
||||
|
||||
struct pico_device picodev;
|
||||
struct pico_device picodev6;
|
||||
struct pico_device *picodev;
|
||||
struct pico_device *picodev6;
|
||||
|
||||
std::vector<InetAddress> ips() const;
|
||||
std::vector<InetAddress> _ips;
|
||||
@@ -236,7 +236,7 @@ namespace ZeroTier {
|
||||
const struct sockaddr *from);
|
||||
void phyOnTcpClose(PhySocket *sock,void **uptr);
|
||||
void phyOnTcpData(PhySocket *sock,void **uptr,void *data,unsigned long len);
|
||||
void phyOnTcpWritable(PhySocket *sock,void **uptr, bool stack_invoked);
|
||||
void phyOnTcpWritable(PhySocket *sock,void **uptr);
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
@@ -81,48 +81,47 @@ namespace ZeroTier {
|
||||
std::sort(tap->_ips.begin(),tap->_ips.end());
|
||||
if(ip.isV4())
|
||||
{
|
||||
tap->picodev = new struct pico_device;
|
||||
struct pico_ip4 ipaddr, netmask;
|
||||
ipaddr.addr = *((uint32_t *)ip.rawIpData());
|
||||
netmask.addr = *((uint32_t *)ip.netmask().rawIpData());
|
||||
tap->picodev->send = pico_eth_send; // tx
|
||||
tap->picodev->poll = pico_eth_poll; // rx
|
||||
tap->picodev->mtu = tap->_mtu;
|
||||
tap->picodev->tap = tap;
|
||||
uint8_t mac[PICO_SIZE_ETH];
|
||||
tap->_mac.copyTo(mac, PICO_SIZE_ETH);
|
||||
// DEBUG_ATTN("mac = %s", tap->_mac.toString().c_str());
|
||||
tap->picodev.send = pico_eth_send; // tx
|
||||
tap->picodev.poll = pico_eth_poll; // rx
|
||||
DEBUG_INFO("tap->picodev.poll = %p", tap->picodev.poll);
|
||||
tap->picodev.mtu = tap->_mtu;
|
||||
tap->picodev.tap = tap;
|
||||
if(pico_device_init(&(tap->picodev), "p4", mac) != 0) {
|
||||
if(pico_device_init(tap->picodev, "p4", mac) != 0) {
|
||||
DEBUG_ERROR("dev init failed");
|
||||
delete tap->picodev;
|
||||
return false;
|
||||
}
|
||||
pico_ipv4_link_add(&(tap->picodev), ipaddr, netmask);
|
||||
pico_ipv4_link_add(tap->picodev, ipaddr, netmask);
|
||||
DEBUG_INFO("addr = %s", ip.toString().c_str());
|
||||
return true;
|
||||
}
|
||||
if(ip.isV6())
|
||||
{
|
||||
struct pico_ip6 ipaddr, netmask;
|
||||
char ipv6_str[INET6_ADDRSTRLEN], nm_str[INET6_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET6, ip.rawIpData(), ipv6_str, INET6_ADDRSTRLEN);
|
||||
inet_ntop(AF_INET6, ip.netmask().rawIpData(), nm_str, INET6_ADDRSTRLEN);
|
||||
DEBUG_ERROR("ipv6_str = %s", ipv6_str);
|
||||
DEBUG_ERROR("nm_str = %s", nm_str);
|
||||
|
||||
tap->picodev6 = new struct pico_device;
|
||||
struct pico_ip6 ipaddr, netmask;
|
||||
pico_string_to_ipv6(ipv6_str, ipaddr.addr);
|
||||
pico_string_to_ipv6(nm_str, netmask.addr);
|
||||
pico_ipv6_link_add(&(tap->picodev6), ipaddr, netmask);
|
||||
tap->picodev6.send = pico_eth_send; // tx
|
||||
tap->picodev6.poll = pico_eth_poll; // rx
|
||||
tap->picodev6.tap = tap;
|
||||
tap->picodev6->send = pico_eth_send; // tx
|
||||
tap->picodev6->poll = pico_eth_poll; // rx
|
||||
tap->picodev6->mtu = tap->_mtu;
|
||||
tap->picodev6->tap = tap;
|
||||
uint8_t mac[PICO_SIZE_ETH];
|
||||
tap->_mac.copyTo(mac, PICO_SIZE_ETH);
|
||||
//mac[3]=9;
|
||||
//mac[0]='b';
|
||||
// DEBUG_ATTN("mac = %s", tap->_mac.toString().c_str());
|
||||
if(pico_device_init(&(tap->picodev6), "p6", mac) != 0) {
|
||||
if(pico_device_init(tap->picodev6, "p6", mac) != 0) {
|
||||
DEBUG_ERROR("dev init failed");
|
||||
delete tap->picodev6;
|
||||
return false;
|
||||
}
|
||||
pico_ipv6_link_add(tap->picodev6, ipaddr, netmask);
|
||||
DEBUG_INFO("addr6 = %s", ip.toString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
82
zto/Jenkinsfile
vendored
Normal file
82
zto/Jenkinsfile
vendored
Normal file
@@ -0,0 +1,82 @@
|
||||
#!/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...>)"
|
||||
37
zto/LICENSE.txt
Normal file
37
zto/LICENSE.txt
Normal file
@@ -0,0 +1,37 @@
|
||||
ZeroTier One - Network Virtualization Everywhere
|
||||
Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
See LICENSE.GPL-3 for the full GNU GPL v3 license.
|
||||
|
||||
--
|
||||
|
||||
You can be released from the requirements of the license by purchasing
|
||||
a commercial license. Buying such a license is mandatory as soon as you
|
||||
develop commercial closed-source software that incorporates or links
|
||||
directly against ZeroTier software without disclosing the source code
|
||||
of your own application.
|
||||
|
||||
--
|
||||
|
||||
The above license does not apply to third party code included with or
|
||||
linked against by ZeroTier software. See the third party code section
|
||||
of the AUTHORS.md for an index of third party software included in
|
||||
this software repository.
|
||||
|
||||
Licenses for third party code are all relatively permissive: MIT,
|
||||
BSD, and public domain. The only exception is the tap-windows driver
|
||||
which is under the GPLv2, but this is only needed to produce the
|
||||
binary tap device driver used by the ZeroTier service on Windows.
|
||||
@@ -1,16 +1,22 @@
|
||||
ZeroTier Release Notes
|
||||
======
|
||||
|
||||
# 2017-03-17 -- Version 1.2.2
|
||||
# 2017-04-20 -- Version 1.2.4
|
||||
|
||||
Version 1.2.2 fixes a few bugs discovered after the 1.2.0 release. These are:
|
||||
* Managed routes are now only bifurcated for the default route. This is a change in behavior, though few people will probably notice. Bifurcating all managed routes was causing more trouble than it was worth for most users.
|
||||
* Up to 2X crypto speedup on x86-64 (except Windows, which will take some porting) and 32-bit ARM platforms due to integration of fast assembly language implementations of Salsa20/12 from the [supercop](http://bench.cr.yp.to/supercop.html) code base. These were written by Daniel J. Bernstein and are in the public domain. My Macbook Pro (Core i5 2.8ghz) now does almost 1.5GiB/sec Salsa20/12 per core and a Raspberry Pi got a 2X boost. 64-bit ARM support and Windows support will take some work but should not be too hard.
|
||||
* Refactored code that manages credentials to greatly reduce memory use in most cases. This may also result in a small performance improvement.
|
||||
* Reworked and simplified path selection and priority logic to fix path instability and dead path persistence edge cases. There have been some sporadic reports of persistent path instabilities and dead paths hanging around that take minutes to resolve. These have proven difficult to reproduce in house, but hopefully this will fix them. In any case it seems to speed up path establishment in our tests and it makes the code simpler and more readable.
|
||||
* Eliminated some unused cruft from the code around path management and in the peer class.
|
||||
* Fixed an issue causing build problems on some MIPS architecture systems.
|
||||
* Fixed Windows forgetting routes on sleep/wake or in some other circumstances. (GitHub issue #465)
|
||||
|
||||
# 2017-03-17 -- Version 1.2.2
|
||||
|
||||
* A bug causing unreliable multicast propagation (GitHub issue #461).
|
||||
* A crash in ARM binaries due to a build chain and flags problem.
|
||||
* A bug in the network controller preventing members from being listed (GitHub issue #460).
|
||||
|
||||
------
|
||||
|
||||
# 2017-03-14 -- Version 1.2.0
|
||||
|
||||
Version 1.2.0 is a major milestone release representing almost nine months of work. It includes our rules engine for distributed network packet filtering and security monitoring, federated roots, and many other architectural and UI improvements and bug fixes.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc.
|
||||
* Copyright (C) 2011-2015 ZeroTier, Inc->
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -30,8 +30,9 @@
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include <stdexcept>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <thread>
|
||||
#include <memory>
|
||||
|
||||
#include "../include/ZeroTierOne.h"
|
||||
#include "../node/Constants.hpp"
|
||||
@@ -58,9 +59,6 @@ using json = nlohmann::json;
|
||||
// Min duration between requests for an address/nwid combo to prevent floods
|
||||
#define ZT_NETCONF_MIN_REQUEST_PERIOD 1000
|
||||
|
||||
// Nodes are considered active if they've queried in less than this long
|
||||
#define ZT_NETCONF_NODE_ACTIVE_THRESHOLD (ZT_NETWORK_AUTOCONF_DELAY * 2)
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
static json _renderRule(ZT_VirtualNetworkRule &rule)
|
||||
@@ -430,22 +428,24 @@ static bool _parseRule(json &r,ZT_VirtualNetworkRule &rule)
|
||||
|
||||
EmbeddedNetworkController::EmbeddedNetworkController(Node *node,const char *dbPath) :
|
||||
_startTime(OSUtils::now()),
|
||||
_threadsStarted(false),
|
||||
_running(true),
|
||||
_db(dbPath),
|
||||
_node(node)
|
||||
{
|
||||
OSUtils::mkdir(dbPath);
|
||||
OSUtils::lockDownFile(dbPath,true); // networks might contain auth tokens, etc., so restrict directory permissions
|
||||
}
|
||||
|
||||
EmbeddedNetworkController::~EmbeddedNetworkController()
|
||||
{
|
||||
Mutex::Lock _l(_threads_m);
|
||||
if (_threadsStarted) {
|
||||
for(int i=0;i<(ZT_EMBEDDEDNETWORKCONTROLLER_BACKGROUND_THREAD_COUNT*2);++i)
|
||||
_queue.post((_RQEntry *)0);
|
||||
for(int i=0;i<ZT_EMBEDDEDNETWORKCONTROLLER_BACKGROUND_THREAD_COUNT;++i)
|
||||
Thread::join(_threads[i]);
|
||||
std::vector<Thread> t;
|
||||
{
|
||||
Mutex::Lock _l(_threads_m);
|
||||
_running = false;
|
||||
t = _threads;
|
||||
}
|
||||
if (t.size() > 0) {
|
||||
_queue.stop();
|
||||
for(std::vector<Thread>::iterator i(t.begin());i!=t.end();++i)
|
||||
Thread::join(*i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -464,22 +464,14 @@ void EmbeddedNetworkController::request(
|
||||
{
|
||||
if (((!_signingId)||(!_signingId.hasPrivate()))||(_signingId.address().toInt() != (nwid >> 24))||(!_sender))
|
||||
return;
|
||||
|
||||
{
|
||||
Mutex::Lock _l(_threads_m);
|
||||
if (!_threadsStarted) {
|
||||
for(int i=0;i<ZT_EMBEDDEDNETWORKCONTROLLER_BACKGROUND_THREAD_COUNT;++i)
|
||||
_threads[i] = Thread::start(this);
|
||||
}
|
||||
_threadsStarted = true;
|
||||
}
|
||||
|
||||
_startThreads();
|
||||
_RQEntry *qe = new _RQEntry;
|
||||
qe->nwid = nwid;
|
||||
qe->requestPacketId = requestPacketId;
|
||||
qe->fromAddr = fromAddr;
|
||||
qe->identity = identity;
|
||||
qe->metaData = metaData;
|
||||
qe->type = _RQEntry::RQENTRY_TYPE_REQUEST;
|
||||
_queue.post(qe);
|
||||
}
|
||||
|
||||
@@ -499,11 +491,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET(
|
||||
Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid);
|
||||
|
||||
json network;
|
||||
{
|
||||
Mutex::Lock _l(_db_m);
|
||||
network = _db.get("network",nwids);
|
||||
}
|
||||
if (!network.size())
|
||||
if (!_db.getNetwork(nwid,network))
|
||||
return 404;
|
||||
|
||||
if (path.size() >= 3) {
|
||||
@@ -512,48 +500,35 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET(
|
||||
|
||||
if (path.size() >= 4) {
|
||||
const uint64_t address = Utils::hexStrToU64(path[3].c_str());
|
||||
|
||||
json member;
|
||||
{
|
||||
Mutex::Lock _l(_db_m);
|
||||
member = _db.get("network",nwids,"member",Address(address).toString());
|
||||
}
|
||||
if (!member.size())
|
||||
if (!_db.getNetworkMember(nwid,address,member))
|
||||
return 404;
|
||||
|
||||
_addMemberNonPersistedFields(member,OSUtils::now());
|
||||
_addMemberNonPersistedFields(nwid,address,member,OSUtils::now());
|
||||
responseBody = OSUtils::jsonDump(member);
|
||||
responseContentType = "application/json";
|
||||
|
||||
return 200;
|
||||
} else {
|
||||
|
||||
Mutex::Lock _l(_db_m);
|
||||
|
||||
responseBody = "{";
|
||||
_db.filter((std::string("network/") + nwids + "/member/"),[&responseBody](const std::string &n,const json &member) {
|
||||
_db.eachMember(nwid,[&responseBody](uint64_t networkId,uint64_t nodeId,const json &member) {
|
||||
if ((member.is_object())&&(member.size() > 0)) {
|
||||
responseBody.append((responseBody.length() == 1) ? "\"" : ",\"");
|
||||
responseBody.append(OSUtils::jsonString(member["id"],"0"));
|
||||
responseBody.append("\":");
|
||||
responseBody.append(OSUtils::jsonString(member["revision"],"0"));
|
||||
}
|
||||
return true; // never delete
|
||||
});
|
||||
responseBody.push_back('}');
|
||||
responseContentType = "application/json";
|
||||
|
||||
return 200;
|
||||
}
|
||||
return 200;
|
||||
|
||||
} // else 404
|
||||
|
||||
} else {
|
||||
|
||||
const uint64_t now = OSUtils::now();
|
||||
_NetworkMemberInfo nmi;
|
||||
_getNetworkMemberInfo(now,nwid,nmi);
|
||||
_addNetworkNonPersistedFields(network,now,nmi);
|
||||
JSONDB::NetworkSummaryInfo ns;
|
||||
_db.getNetworkSummaryInfo(nwid,ns);
|
||||
_addNetworkNonPersistedFields(network,now,ns);
|
||||
responseBody = OSUtils::jsonDump(network);
|
||||
responseContentType = "application/json";
|
||||
return 200;
|
||||
@@ -561,24 +536,20 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpGET(
|
||||
}
|
||||
} else if (path.size() == 1) {
|
||||
|
||||
std::set<std::string> networkIds;
|
||||
{
|
||||
Mutex::Lock _l(_db_m);
|
||||
_db.filter("network/",[&networkIds](const std::string &n,const json &obj) {
|
||||
if (n.length() == (16 + 8))
|
||||
networkIds.insert(n.substr(8));
|
||||
return true; // do not delete
|
||||
});
|
||||
}
|
||||
std::vector<uint64_t> networkIds(_db.networkIds());
|
||||
std::sort(networkIds.begin(),networkIds.end());
|
||||
|
||||
char tmp[64];
|
||||
responseBody.push_back('[');
|
||||
for(std::set<std::string>::iterator i(networkIds.begin());i!=networkIds.end();++i) {
|
||||
responseBody.append((responseBody.length() == 1) ? "\"" : ",\"");
|
||||
responseBody.append(*i);
|
||||
responseBody.append("\"");
|
||||
for(std::vector<uint64_t>::const_iterator i(networkIds.begin());i!=networkIds.end();++i) {
|
||||
if (responseBody.length() > 1)
|
||||
responseBody.push_back(',');
|
||||
Utils::snprintf(tmp,sizeof(tmp),"\"%.16llx\"",(unsigned long long)*i);
|
||||
responseBody.append(tmp);
|
||||
}
|
||||
responseBody.push_back(']');
|
||||
responseContentType = "application/json";
|
||||
|
||||
return 200;
|
||||
|
||||
} // else 404
|
||||
@@ -637,10 +608,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
|
||||
Utils::snprintf(addrs,sizeof(addrs),"%.10llx",(unsigned long long)address);
|
||||
|
||||
json member;
|
||||
{
|
||||
Mutex::Lock _l(_db_m);
|
||||
member = _db.get("network",nwids,"member",Address(address).toString());
|
||||
}
|
||||
_db.getNetworkMember(nwid,address,member);
|
||||
json origMember(member); // for detecting changes
|
||||
_initMember(member);
|
||||
|
||||
@@ -664,13 +632,13 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
|
||||
|
||||
// Member is being de-authorized, so spray Revocation objects to all online members
|
||||
if (!newAuth) {
|
||||
_clearNetworkMemberInfoCache(nwid);
|
||||
Revocation rev(_node->prng(),nwid,0,now,ZT_REVOCATION_FLAG_FAST_PROPAGATE,Address(address),Revocation::CREDENTIAL_TYPE_COM);
|
||||
Revocation rev((uint32_t)_node->prng(),nwid,0,now,ZT_REVOCATION_FLAG_FAST_PROPAGATE,Address(address),Revocation::CREDENTIAL_TYPE_COM);
|
||||
rev.sign(_signingId);
|
||||
Mutex::Lock _l(_lastRequestTime_m);
|
||||
for(std::map< std::pair<uint64_t,uint64_t>,uint64_t >::iterator i(_lastRequestTime.begin());i!=_lastRequestTime.end();++i) {
|
||||
if ((now - i->second) < ZT_NETWORK_AUTOCONF_DELAY)
|
||||
_node->ncSendRevocation(Address(i->first.first),rev);
|
||||
|
||||
Mutex::Lock _l(_memberStatus_m);
|
||||
for(auto i=_memberStatus.begin();i!=_memberStatus.end();++i) {
|
||||
if ((i->first.networkId == nwid)&&(i->second.online(now)))
|
||||
_node->ncSendRevocation(Address(i->first.nodeId),rev);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -733,22 +701,25 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
|
||||
member["address"] = addrs; // legacy
|
||||
member["nwid"] = nwids;
|
||||
|
||||
_removeMemberNonPersistedFields(member);
|
||||
if (member != origMember) {
|
||||
member["lastModified"] = now;
|
||||
json &revj = member["revision"];
|
||||
member["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL);
|
||||
{
|
||||
Mutex::Lock _l(_db_m);
|
||||
_db.put("network",nwids,"member",Address(address).toString(),member);
|
||||
}
|
||||
_pushMemberUpdate(now,nwid,member);
|
||||
_db.saveNetworkMember(nwid,address,member);
|
||||
|
||||
// Push update to member if online
|
||||
try {
|
||||
Mutex::Lock _l(_memberStatus_m);
|
||||
_MemberStatus &ms = _memberStatus[_MemberStatusKey(nwid,address)];
|
||||
if ((ms.online(now))&&(ms.lastRequestMetaData))
|
||||
request(nwid,InetAddress(),0,ms.identity,ms.lastRequestMetaData);
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
|
||||
// Add non-persisted fields
|
||||
member["clock"] = now;
|
||||
|
||||
_addMemberNonPersistedFields(nwid,address,member,now);
|
||||
responseBody = OSUtils::jsonDump(member);
|
||||
responseContentType = "application/json";
|
||||
|
||||
return 200;
|
||||
} else if ((path.size() == 3)&&(path[2] == "test")) {
|
||||
|
||||
@@ -808,31 +779,27 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
|
||||
} else {
|
||||
// POST to network ID
|
||||
|
||||
json network;
|
||||
{
|
||||
Mutex::Lock _l(_db_m);
|
||||
|
||||
// Magic ID ending with ______ picks a random unused network ID
|
||||
if (path[1].substr(10) == "______") {
|
||||
nwid = 0;
|
||||
uint64_t nwidPrefix = (Utils::hexStrToU64(path[1].substr(0,10).c_str()) << 24) & 0xffffffffff000000ULL;
|
||||
uint64_t nwidPostfix = 0;
|
||||
for(unsigned long k=0;k<100000;++k) { // sanity limit on trials
|
||||
Utils::getSecureRandom(&nwidPostfix,sizeof(nwidPostfix));
|
||||
uint64_t tryNwid = nwidPrefix | (nwidPostfix & 0xffffffULL);
|
||||
if ((tryNwid & 0xffffffULL) == 0ULL) tryNwid |= 1ULL;
|
||||
Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)tryNwid);
|
||||
if (_db.get("network",nwids).size() <= 0) {
|
||||
nwid = tryNwid;
|
||||
break;
|
||||
}
|
||||
// Magic ID ending with ______ picks a random unused network ID
|
||||
if (path[1].substr(10) == "______") {
|
||||
nwid = 0;
|
||||
uint64_t nwidPrefix = (Utils::hexStrToU64(path[1].substr(0,10).c_str()) << 24) & 0xffffffffff000000ULL;
|
||||
uint64_t nwidPostfix = 0;
|
||||
for(unsigned long k=0;k<100000;++k) { // sanity limit on trials
|
||||
Utils::getSecureRandom(&nwidPostfix,sizeof(nwidPostfix));
|
||||
uint64_t tryNwid = nwidPrefix | (nwidPostfix & 0xffffffULL);
|
||||
if ((tryNwid & 0xffffffULL) == 0ULL) tryNwid |= 1ULL;
|
||||
if (!_db.hasNetwork(tryNwid)) {
|
||||
nwid = tryNwid;
|
||||
break;
|
||||
}
|
||||
if (!nwid)
|
||||
return 503;
|
||||
}
|
||||
|
||||
network = _db.get("network",nwids);
|
||||
if (!nwid)
|
||||
return 503;
|
||||
}
|
||||
Utils::snprintf(nwids,sizeof(nwids),"%.16llx",(unsigned long long)nwid);
|
||||
|
||||
json network;
|
||||
_db.getNetwork(nwid,network);
|
||||
json origNetwork(network); // for detecting changes
|
||||
_initNetwork(network);
|
||||
|
||||
@@ -1018,9 +985,10 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
|
||||
json ntag = json::object();
|
||||
const uint64_t tagId = OSUtils::jsonInt(tag["id"],0ULL);
|
||||
ntag["id"] = tagId;
|
||||
if (tag.find("default") == tag.end())
|
||||
ntag["default"] = json();
|
||||
else ntag["default"] = OSUtils::jsonInt(tag["default"],0ULL);
|
||||
json &dfl = tag["default"];
|
||||
if (dfl.is_null())
|
||||
ntag["default"] = dfl;
|
||||
else ntag["default"] = OSUtils::jsonInt(dfl,0ULL);
|
||||
ntags[tagId] = ntag;
|
||||
}
|
||||
}
|
||||
@@ -1041,25 +1009,23 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
|
||||
network["id"] = nwids;
|
||||
network["nwid"] = nwids; // legacy
|
||||
|
||||
_removeNetworkNonPersistedFields(network);
|
||||
if (network != origNetwork) {
|
||||
json &revj = network["revision"];
|
||||
network["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL);
|
||||
network["lastModified"] = now;
|
||||
{
|
||||
Mutex::Lock _l(_db_m);
|
||||
_db.put("network",nwids,network);
|
||||
}
|
||||
_db.saveNetwork(nwid,network);
|
||||
|
||||
// Send an update to all members of the network
|
||||
_db.filter((std::string("network/") + nwids + "/member/"),[this,&now,&nwid](const std::string &n,const json &obj) {
|
||||
_pushMemberUpdate(now,nwid,obj);
|
||||
return true; // do not delete
|
||||
});
|
||||
// Send an update to all members of the network that are online
|
||||
Mutex::Lock _l(_memberStatus_m);
|
||||
for(auto i=_memberStatus.begin();i!=_memberStatus.end();++i) {
|
||||
if ((i->first.networkId == nwid)&&(i->second.online(now))&&(i->second.lastRequestMetaData))
|
||||
request(nwid,InetAddress(),0,i->second.identity,i->second.lastRequestMetaData);
|
||||
}
|
||||
}
|
||||
|
||||
_NetworkMemberInfo nmi;
|
||||
_getNetworkMemberInfo(now,nwid,nmi);
|
||||
_addNetworkNonPersistedFields(network,now,nmi);
|
||||
JSONDB::NetworkSummaryInfo ns;
|
||||
_db.getNetworkSummaryInfo(nwid,ns);
|
||||
_addNetworkNonPersistedFields(network,now,ns);
|
||||
|
||||
responseBody = OSUtils::jsonDump(network);
|
||||
responseContentType = "application/json";
|
||||
@@ -1068,13 +1034,19 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST(
|
||||
|
||||
} // else 404
|
||||
|
||||
} else if (path[0] == "dbtest") {
|
||||
} else if (path[0] == "ping") {
|
||||
|
||||
json testRec;
|
||||
const uint64_t now = OSUtils::now();
|
||||
testRec["clock"] = now;
|
||||
testRec["uptime"] = (now - _startTime);
|
||||
_db.put("dbtest",testRec);
|
||||
_startThreads();
|
||||
_RQEntry *qe = new _RQEntry;
|
||||
qe->type = _RQEntry::RQENTRY_TYPE_PING;
|
||||
_queue.post(qe);
|
||||
|
||||
char tmp[64];
|
||||
Utils::snprintf(tmp,sizeof(tmp),"{\"clock\":%llu,\"ping\":%s}",(unsigned long long)now,OSUtils::jsonDump(b).c_str());
|
||||
responseBody = tmp;
|
||||
responseContentType = "application/json";
|
||||
|
||||
return 200;
|
||||
|
||||
}
|
||||
|
||||
@@ -1095,25 +1067,16 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpDELETE(
|
||||
if (path[0] == "network") {
|
||||
if ((path.size() >= 2)&&(path[1].length() == 16)) {
|
||||
const uint64_t nwid = Utils::hexStrToU64(path[1].c_str());
|
||||
|
||||
char nwids[24];
|
||||
Utils::snprintf(nwids,sizeof(nwids),"%.16llx",nwid);
|
||||
json network;
|
||||
{
|
||||
Mutex::Lock _l(_db_m);
|
||||
network = _db.get("network",nwids);
|
||||
}
|
||||
if (!network.size())
|
||||
return 404;
|
||||
|
||||
if (path.size() >= 3) {
|
||||
if ((path.size() == 4)&&(path[2] == "member")&&(path[3].length() == 10)) {
|
||||
const uint64_t address = Utils::hexStrToU64(path[3].c_str());
|
||||
|
||||
Mutex::Lock _l(_db_m);
|
||||
json member = _db.eraseNetworkMember(nwid,address);
|
||||
|
||||
json member = _db.get("network",nwids,"member",Address(address).toString());
|
||||
_db.erase("network",nwids,"member",Address(address).toString());
|
||||
{
|
||||
Mutex::Lock _l(_memberStatus_m);
|
||||
_memberStatus.erase(_MemberStatusKey(nwid,address));
|
||||
}
|
||||
|
||||
if (!member.size())
|
||||
return 404;
|
||||
@@ -1122,16 +1085,19 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpDELETE(
|
||||
return 200;
|
||||
}
|
||||
} else {
|
||||
Mutex::Lock _l(_db_m);
|
||||
json network = _db.eraseNetwork(nwid);
|
||||
|
||||
std::string pfx("network/"); pfx.append(nwids);
|
||||
_db.filter(pfx,[](const std::string &n,const json &obj) {
|
||||
return false; // delete
|
||||
});
|
||||
|
||||
Mutex::Lock _l2(_nmiCache_m);
|
||||
_nmiCache.erase(nwid);
|
||||
{
|
||||
Mutex::Lock _l(_memberStatus_m);
|
||||
for(auto i=_memberStatus.begin();i!=_memberStatus.end();) {
|
||||
if (i->first.networkId == nwid)
|
||||
_memberStatus.erase(i++);
|
||||
else ++i;
|
||||
}
|
||||
}
|
||||
|
||||
if (!network.size())
|
||||
return 404;
|
||||
responseBody = OSUtils::jsonDump(network);
|
||||
responseContentType = "application/json";
|
||||
return 200;
|
||||
@@ -1147,23 +1113,52 @@ void EmbeddedNetworkController::threadMain()
|
||||
throw()
|
||||
{
|
||||
uint64_t lastCircuitTestCheck = 0;
|
||||
for(;;) {
|
||||
_RQEntry *const qe = _queue.get(); // waits on next request
|
||||
if (!qe) break; // enqueue a NULL to terminate threads
|
||||
_RQEntry *qe = (_RQEntry *)0;
|
||||
while ((_running)&&(_queue.get(qe))) {
|
||||
try {
|
||||
_request(qe->nwid,qe->fromAddr,qe->requestPacketId,qe->identity,qe->metaData);
|
||||
if (qe->type == _RQEntry::RQENTRY_TYPE_REQUEST) {
|
||||
_request(qe->nwid,qe->fromAddr,qe->requestPacketId,qe->identity,qe->metaData);
|
||||
} else if (qe->type == _RQEntry::RQENTRY_TYPE_PING) {
|
||||
const uint64_t now = OSUtils::now();
|
||||
bool first = true;
|
||||
std::string pong("{\"memberStatus\":{");
|
||||
{
|
||||
Mutex::Lock _l(_memberStatus_m);
|
||||
pong.reserve(64 * _memberStatus.size());
|
||||
_db.eachId([this,&pong,&now,&first](uint64_t networkId,uint64_t nodeId) {
|
||||
char tmp[64];
|
||||
uint64_t lrt = 0ULL;
|
||||
auto ms = this->_memberStatus.find(_MemberStatusKey(networkId,nodeId));
|
||||
if (ms != _memberStatus.end())
|
||||
lrt = ms->second.lastRequestTime;
|
||||
Utils::snprintf(tmp,sizeof(tmp),"%s\"%.16llx-%.10llx\":%llu",
|
||||
(first) ? "" : ",",
|
||||
(unsigned long long)networkId,
|
||||
(unsigned long long)nodeId,
|
||||
(unsigned long long)lrt);
|
||||
pong.append(tmp);
|
||||
first = false;
|
||||
});
|
||||
}
|
||||
char tmp2[256];
|
||||
Utils::snprintf(tmp2,sizeof(tmp2),"},\"clock\":%llu,\"startTime\":%llu}",(unsigned long long)now,(unsigned long long)_startTime);
|
||||
pong.append(tmp2);
|
||||
_db.writeRaw("pong",pong);
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
delete qe;
|
||||
|
||||
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;
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1171,7 +1166,7 @@ void EmbeddedNetworkController::threadMain()
|
||||
|
||||
void EmbeddedNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTest *test,const ZT_CircuitTestReport *report)
|
||||
{
|
||||
char tmp[1024],id[128];
|
||||
char tmp[2048],id[128];
|
||||
EmbeddedNetworkController *const self = reinterpret_cast<EmbeddedNetworkController *>(test->ptr);
|
||||
|
||||
if ((!test)||(!report)||(!test->credentialNetworkId)) return; // sanity check
|
||||
@@ -1180,6 +1175,7 @@ void EmbeddedNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTes
|
||||
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\","
|
||||
@@ -1222,7 +1218,6 @@ void EmbeddedNetworkController::_circuitTestCallback(ZT_Node *node,ZT_CircuitTes
|
||||
reinterpret_cast<const InetAddress *>(&(report->receivedFromRemoteAddress))->toString().c_str(),
|
||||
((double)report->receivedFromLinkQuality / (double)ZT_PATH_LINK_QUALITY_MAX));
|
||||
|
||||
Mutex::Lock _l(self->_db_m);
|
||||
self->_db.writeRaw(id,std::string(tmp));
|
||||
}
|
||||
|
||||
@@ -1233,37 +1228,30 @@ void EmbeddedNetworkController::_request(
|
||||
const Identity &identity,
|
||||
const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData)
|
||||
{
|
||||
char nwids[24];
|
||||
JSONDB::NetworkSummaryInfo ns;
|
||||
json network,member,origMember;
|
||||
|
||||
if (((!_signingId)||(!_signingId.hasPrivate()))||(_signingId.address().toInt() != (nwid >> 24))||(!_sender))
|
||||
return;
|
||||
|
||||
const uint64_t now = OSUtils::now();
|
||||
|
||||
if (requestPacketId) {
|
||||
Mutex::Lock _l(_lastRequestTime_m);
|
||||
uint64_t &lrt = _lastRequestTime[std::pair<uint64_t,uint64_t>(identity.address().toInt(),nwid)];
|
||||
if ((now - lrt) <= ZT_NETCONF_MIN_REQUEST_PERIOD)
|
||||
Mutex::Lock _l(_memberStatus_m);
|
||||
_MemberStatus &ms = _memberStatus[_MemberStatusKey(nwid,identity.address().toInt())];
|
||||
if ((now - ms.lastRequestTime) <= ZT_NETCONF_MIN_REQUEST_PERIOD)
|
||||
return;
|
||||
lrt = now;
|
||||
ms.lastRequestTime = now;
|
||||
}
|
||||
|
||||
char nwids[24];
|
||||
Utils::snprintf(nwids,sizeof(nwids),"%.16llx",nwid);
|
||||
json network;
|
||||
json member;
|
||||
{
|
||||
Mutex::Lock _l(_db_m);
|
||||
network = _db.get("network",nwids);
|
||||
member = _db.get("network",nwids,"member",identity.address().toString());
|
||||
}
|
||||
|
||||
if (!network.size()) {
|
||||
if (!_db.getNetworkAndMember(nwid,identity.address().toInt(),network,member,ns)) {
|
||||
_sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_OBJECT_NOT_FOUND);
|
||||
return;
|
||||
}
|
||||
|
||||
const bool newMember = (member.size() == 0);
|
||||
|
||||
json origMember(member); // for detecting modification later
|
||||
origMember = member;
|
||||
const bool newMember = ((!member.is_object())||(member.size() == 0));
|
||||
_initMember(member);
|
||||
|
||||
{
|
||||
@@ -1288,9 +1276,12 @@ void EmbeddedNetworkController::_request(
|
||||
}
|
||||
|
||||
// These are always the same, but make sure they are set
|
||||
member["id"] = identity.address().toString();
|
||||
member["address"] = member["id"];
|
||||
member["nwid"] = nwids;
|
||||
{
|
||||
const std::string addrs(identity.address().toString());
|
||||
member["id"] = addrs;
|
||||
member["address"] = addrs;
|
||||
member["nwid"] = nwids;
|
||||
}
|
||||
|
||||
// Determine whether and how member is authorized
|
||||
const char *authorizedBy = (const char *)0;
|
||||
@@ -1366,42 +1357,41 @@ void EmbeddedNetworkController::_request(
|
||||
member["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL);
|
||||
}
|
||||
|
||||
// Log this request
|
||||
if (requestPacketId) { // only log if this is a request, not for generated pushes
|
||||
json rlEntry = json::object();
|
||||
rlEntry["ts"] = now;
|
||||
rlEntry["auth"] = (authorizedBy) ? true : false;
|
||||
rlEntry["authBy"] = (authorizedBy) ? authorizedBy : "";
|
||||
rlEntry["vMajor"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,0);
|
||||
rlEntry["vMinor"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,0);
|
||||
rlEntry["vRev"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,0);
|
||||
rlEntry["vProto"] = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION,0);
|
||||
if (fromAddr)
|
||||
rlEntry["fromAddr"] = fromAddr.toString();
|
||||
if (authorizedBy) {
|
||||
// Update version info and meta-data if authorized and if this is a genuine request
|
||||
if (requestPacketId) {
|
||||
const uint64_t vMajor = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MAJOR_VERSION,0);
|
||||
const uint64_t vMinor = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_MINOR_VERSION,0);
|
||||
const uint64_t vRev = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_NODE_REVISION,0);
|
||||
const uint64_t vProto = metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_PROTOCOL_VERSION,0);
|
||||
|
||||
json recentLog = json::array();
|
||||
recentLog.push_back(rlEntry);
|
||||
json &oldLog = member["recentLog"];
|
||||
if (oldLog.is_array()) {
|
||||
for(unsigned long i=0;i<oldLog.size();++i) {
|
||||
recentLog.push_back(oldLog[i]);
|
||||
if (recentLog.size() >= ZT_NETCONF_DB_MEMBER_HISTORY_LENGTH)
|
||||
break;
|
||||
member["vMajor"] = vMajor;
|
||||
member["vMinor"] = vMinor;
|
||||
member["vRev"] = vRev;
|
||||
member["vProto"] = vProto;
|
||||
|
||||
{
|
||||
Mutex::Lock _l(_memberStatus_m);
|
||||
_MemberStatus &ms = _memberStatus[_MemberStatusKey(nwid,identity.address().toInt())];
|
||||
|
||||
ms.vMajor = (int)vMajor;
|
||||
ms.vMinor = (int)vMinor;
|
||||
ms.vRev = (int)vRev;
|
||||
ms.vProto = (int)vProto;
|
||||
ms.lastRequestMetaData = metaData;
|
||||
ms.identity = identity;
|
||||
|
||||
if (fromAddr)
|
||||
ms.physicalAddr = fromAddr;
|
||||
if (ms.physicalAddr)
|
||||
member["physicalAddr"] = ms.physicalAddr.toString();
|
||||
}
|
||||
}
|
||||
member["recentLog"] = recentLog;
|
||||
|
||||
// Also only do this on real requests
|
||||
member["lastRequestMetaData"] = metaData.data();
|
||||
}
|
||||
|
||||
// If they are not authorized, STOP!
|
||||
if (!authorizedBy) {
|
||||
if (origMember != member) {
|
||||
member["lastModified"] = now;
|
||||
Mutex::Lock _l(_db_m);
|
||||
_db.put("network",nwids,"member",identity.address().toString(),member);
|
||||
}
|
||||
} else {
|
||||
// If they are not authorized, STOP!
|
||||
_removeMemberNonPersistedFields(member);
|
||||
if (origMember != member)
|
||||
_db.saveNetworkMember(nwid,identity.address().toInt(),member);
|
||||
_sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED);
|
||||
return;
|
||||
}
|
||||
@@ -1410,16 +1400,12 @@ void EmbeddedNetworkController::_request(
|
||||
// If we made it this far, they are authorized.
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
NetworkConfig nc;
|
||||
_NetworkMemberInfo nmi;
|
||||
_getNetworkMemberInfo(now,nwid,nmi);
|
||||
|
||||
uint64_t credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA;
|
||||
if (now > nmi.mostRecentDeauthTime) {
|
||||
if (now > ns.mostRecentDeauthTime) {
|
||||
// If we recently de-authorized a member, shrink credential TTL/max delta to
|
||||
// be below the threshold required to exclude it. Cap this to a min/max to
|
||||
// prevent jitter or absurdly large values.
|
||||
const uint64_t deauthWindow = now - nmi.mostRecentDeauthTime;
|
||||
const uint64_t deauthWindow = now - ns.mostRecentDeauthTime;
|
||||
if (deauthWindow < ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA) {
|
||||
credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA;
|
||||
} else if (deauthWindow < (ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA + 5000ULL)) {
|
||||
@@ -1427,20 +1413,21 @@ void EmbeddedNetworkController::_request(
|
||||
}
|
||||
}
|
||||
|
||||
nc.networkId = nwid;
|
||||
nc.type = OSUtils::jsonBool(network["private"],true) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC;
|
||||
nc.timestamp = now;
|
||||
nc.credentialTimeMaxDelta = credentialtmd;
|
||||
nc.revision = OSUtils::jsonInt(network["revision"],0ULL);
|
||||
nc.issuedTo = identity.address();
|
||||
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;
|
||||
Utils::scopy(nc.name,sizeof(nc.name),OSUtils::jsonString(network["name"],"").c_str());
|
||||
nc.multicastLimit = (unsigned int)OSUtils::jsonInt(network["multicastLimit"],32ULL);
|
||||
std::auto_ptr<NetworkConfig> nc(new NetworkConfig());
|
||||
|
||||
for(std::set<Address>::const_iterator ab(nmi.activeBridges.begin());ab!=nmi.activeBridges.end();++ab) {
|
||||
nc.addSpecialist(*ab,ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE);
|
||||
}
|
||||
nc->networkId = nwid;
|
||||
nc->type = OSUtils::jsonBool(network["private"],true) ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC;
|
||||
nc->timestamp = now;
|
||||
nc->credentialTimeMaxDelta = credentialtmd;
|
||||
nc->revision = OSUtils::jsonInt(network["revision"],0ULL);
|
||||
nc->issuedTo = identity.address();
|
||||
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;
|
||||
Utils::scopy(nc->name,sizeof(nc->name),OSUtils::jsonString(network["name"],"").c_str());
|
||||
nc->multicastLimit = (unsigned int)OSUtils::jsonInt(network["multicastLimit"],32ULL);
|
||||
|
||||
for(std::vector<Address>::const_iterator ab(ns.activeBridges.begin());ab!=ns.activeBridges.end();++ab)
|
||||
nc->addSpecialist(*ab,ZT_NETWORKCONFIG_SPECIALIST_TYPE_ACTIVE_BRIDGE);
|
||||
|
||||
json &v4AssignMode = network["v4AssignMode"];
|
||||
json &v6AssignMode = network["v6AssignMode"];
|
||||
@@ -1456,15 +1443,15 @@ void EmbeddedNetworkController::_request(
|
||||
// Old versions with no rules engine support get an allow everything rule.
|
||||
// Since rules are enforced bidirectionally, newer versions *will* still
|
||||
// enforce rules on the inbound side.
|
||||
nc.ruleCount = 1;
|
||||
nc.rules[0].t = ZT_NETWORK_RULE_ACTION_ACCEPT;
|
||||
nc->ruleCount = 1;
|
||||
nc->rules[0].t = ZT_NETWORK_RULE_ACTION_ACCEPT;
|
||||
} else {
|
||||
if (rules.is_array()) {
|
||||
for(unsigned long i=0;i<rules.size();++i) {
|
||||
if (nc.ruleCount >= ZT_MAX_NETWORK_RULES)
|
||||
if (nc->ruleCount >= ZT_MAX_NETWORK_RULES)
|
||||
break;
|
||||
if (_parseRule(rules[i],nc.rules[nc.ruleCount]))
|
||||
++nc.ruleCount;
|
||||
if (_parseRule(rules[i],nc->rules[nc->ruleCount]))
|
||||
++nc->ruleCount;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1508,10 +1495,10 @@ void EmbeddedNetworkController::_request(
|
||||
++caprc;
|
||||
}
|
||||
}
|
||||
nc.capabilities[nc.capabilityCount] = Capability((uint32_t)capId,nwid,now,1,capr,caprc);
|
||||
if (nc.capabilities[nc.capabilityCount].sign(_signingId,identity.address()))
|
||||
++nc.capabilityCount;
|
||||
if (nc.capabilityCount >= ZT_MAX_NETWORK_CAPABILITIES)
|
||||
nc->capabilities[nc->capabilityCount] = Capability((uint32_t)capId,nwid,now,1,capr,caprc);
|
||||
if (nc->capabilities[nc->capabilityCount].sign(_signingId,identity.address()))
|
||||
++nc->capabilityCount;
|
||||
if (nc->capabilityCount >= ZT_MAX_NETWORK_CAPABILITIES)
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1542,17 +1529,17 @@ void EmbeddedNetworkController::_request(
|
||||
}
|
||||
}
|
||||
for(std::map< uint32_t,uint32_t >::const_iterator t(memberTagsById.begin());t!=memberTagsById.end();++t) {
|
||||
if (nc.tagCount >= ZT_MAX_NETWORK_TAGS)
|
||||
if (nc->tagCount >= ZT_MAX_NETWORK_TAGS)
|
||||
break;
|
||||
nc.tags[nc.tagCount] = Tag(nwid,now,identity.address(),t->first,t->second);
|
||||
if (nc.tags[nc.tagCount].sign(_signingId))
|
||||
++nc.tagCount;
|
||||
nc->tags[nc->tagCount] = Tag(nwid,now,identity.address(),t->first,t->second);
|
||||
if (nc->tags[nc->tagCount].sign(_signingId))
|
||||
++nc->tagCount;
|
||||
}
|
||||
}
|
||||
|
||||
if (routes.is_array()) {
|
||||
for(unsigned long i=0;i<routes.size();++i) {
|
||||
if (nc.routeCount >= ZT_MAX_NETWORK_ROUTES)
|
||||
if (nc->routeCount >= ZT_MAX_NETWORK_ROUTES)
|
||||
break;
|
||||
json &route = routes[i];
|
||||
json &target = route["target"];
|
||||
@@ -1562,11 +1549,11 @@ void EmbeddedNetworkController::_request(
|
||||
InetAddress v;
|
||||
if (via.is_string()) v.fromString(via.get<std::string>());
|
||||
if ((t.ss_family == AF_INET)||(t.ss_family == AF_INET6)) {
|
||||
ZT_VirtualNetworkRoute *r = &(nc.routes[nc.routeCount]);
|
||||
ZT_VirtualNetworkRoute *r = &(nc->routes[nc->routeCount]);
|
||||
*(reinterpret_cast<InetAddress *>(&(r->target))) = t;
|
||||
if (v.ss_family == t.ss_family)
|
||||
*(reinterpret_cast<InetAddress *>(&(r->via))) = v;
|
||||
++nc.routeCount;
|
||||
++nc->routeCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1575,13 +1562,13 @@ void EmbeddedNetworkController::_request(
|
||||
const bool noAutoAssignIps = OSUtils::jsonBool(member["noAutoAssignIps"],false);
|
||||
|
||||
if ((v6AssignMode.is_object())&&(!noAutoAssignIps)) {
|
||||
if ((OSUtils::jsonBool(v6AssignMode["rfc4193"],false))&&(nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) {
|
||||
nc.staticIps[nc.staticIpCount++] = InetAddress::makeIpv6rfc4193(nwid,identity.address().toInt());
|
||||
nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION;
|
||||
if ((OSUtils::jsonBool(v6AssignMode["rfc4193"],false))&&(nc->staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) {
|
||||
nc->staticIps[nc->staticIpCount++] = InetAddress::makeIpv6rfc4193(nwid,identity.address().toInt());
|
||||
nc->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION;
|
||||
}
|
||||
if ((OSUtils::jsonBool(v6AssignMode["6plane"],false))&&(nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) {
|
||||
nc.staticIps[nc.staticIpCount++] = InetAddress::makeIpv66plane(nwid,identity.address().toInt());
|
||||
nc.flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION;
|
||||
if ((OSUtils::jsonBool(v6AssignMode["6plane"],false))&&(nc->staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)) {
|
||||
nc->staticIps[nc->staticIpCount++] = InetAddress::makeIpv66plane(nwid,identity.address().toInt());
|
||||
nc->flags |= ZT_NETWORKCONFIG_FLAG_ENABLE_IPV6_NDP_EMULATION;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1599,15 +1586,15 @@ void EmbeddedNetworkController::_request(
|
||||
// this route, ignoring the netmask bits field of the assigned IP itself. Using that was worthless and a source
|
||||
// of user error / poor UX.
|
||||
int routedNetmaskBits = 0;
|
||||
for(unsigned int rk=0;rk<nc.routeCount;++rk) {
|
||||
if ( (!nc.routes[rk].via.ss_family) && (reinterpret_cast<const InetAddress *>(&(nc.routes[rk].target))->containsAddress(ip)) )
|
||||
routedNetmaskBits = reinterpret_cast<const InetAddress *>(&(nc.routes[rk].target))->netmaskBits();
|
||||
for(unsigned int rk=0;rk<nc->routeCount;++rk) {
|
||||
if ( (!nc->routes[rk].via.ss_family) && (reinterpret_cast<const InetAddress *>(&(nc->routes[rk].target))->containsAddress(ip)) )
|
||||
routedNetmaskBits = reinterpret_cast<const InetAddress *>(&(nc->routes[rk].target))->netmaskBits();
|
||||
}
|
||||
|
||||
if (routedNetmaskBits > 0) {
|
||||
if (nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES) {
|
||||
if (nc->staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES) {
|
||||
ip.setPort(routedNetmaskBits);
|
||||
nc.staticIps[nc.staticIpCount++] = ip;
|
||||
nc->staticIps[nc->staticIpCount++] = ip;
|
||||
}
|
||||
if (ip.ss_family == AF_INET)
|
||||
haveManagedIpv4AutoAssignment = true;
|
||||
@@ -1658,20 +1645,19 @@ void EmbeddedNetworkController::_request(
|
||||
|
||||
// Check if this IP is within a local-to-Ethernet routed network
|
||||
int routedNetmaskBits = 0;
|
||||
for(unsigned int rk=0;rk<nc.routeCount;++rk) {
|
||||
if ( (!nc.routes[rk].via.ss_family) && (nc.routes[rk].target.ss_family == AF_INET6) && (reinterpret_cast<const InetAddress *>(&(nc.routes[rk].target))->containsAddress(ip6)) )
|
||||
routedNetmaskBits = reinterpret_cast<const InetAddress *>(&(nc.routes[rk].target))->netmaskBits();
|
||||
for(unsigned int rk=0;rk<nc->routeCount;++rk) {
|
||||
if ( (!nc->routes[rk].via.ss_family) && (nc->routes[rk].target.ss_family == AF_INET6) && (reinterpret_cast<const InetAddress *>(&(nc->routes[rk].target))->containsAddress(ip6)) )
|
||||
routedNetmaskBits = reinterpret_cast<const InetAddress *>(&(nc->routes[rk].target))->netmaskBits();
|
||||
}
|
||||
|
||||
// If it's routed, then try to claim and assign it and if successful end loop
|
||||
if ((routedNetmaskBits > 0)&&(!nmi.allocatedIps.count(ip6))) {
|
||||
if ( (routedNetmaskBits > 0) && (!std::binary_search(ns.allocatedIps.begin(),ns.allocatedIps.end(),ip6)) ) {
|
||||
ipAssignments.push_back(ip6.toIpString());
|
||||
member["ipAssignments"] = ipAssignments;
|
||||
ip6.setPort((unsigned int)routedNetmaskBits);
|
||||
if (nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)
|
||||
nc.staticIps[nc.staticIpCount++] = ip6;
|
||||
if (nc->staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES)
|
||||
nc->staticIps[nc->staticIpCount++] = ip6;
|
||||
haveManagedIpv6AutoAssignment = true;
|
||||
_clearNetworkMemberInfoCache(nwid); // clear cache to prevent IP assignment duplication on many rapid assigns
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1704,10 +1690,10 @@ void EmbeddedNetworkController::_request(
|
||||
|
||||
// Check if this IP is within a local-to-Ethernet routed network
|
||||
int routedNetmaskBits = -1;
|
||||
for(unsigned int rk=0;rk<nc.routeCount;++rk) {
|
||||
if (nc.routes[rk].target.ss_family == AF_INET) {
|
||||
uint32_t targetIp = Utils::ntoh((uint32_t)(reinterpret_cast<const struct sockaddr_in *>(&(nc.routes[rk].target))->sin_addr.s_addr));
|
||||
int targetBits = Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in *>(&(nc.routes[rk].target))->sin_port));
|
||||
for(unsigned int rk=0;rk<nc->routeCount;++rk) {
|
||||
if (nc->routes[rk].target.ss_family == AF_INET) {
|
||||
uint32_t targetIp = Utils::ntoh((uint32_t)(reinterpret_cast<const struct sockaddr_in *>(&(nc->routes[rk].target))->sin_addr.s_addr));
|
||||
int targetBits = Utils::ntoh((uint16_t)(reinterpret_cast<const struct sockaddr_in *>(&(nc->routes[rk].target))->sin_port));
|
||||
if ((ip & (0xffffffff << (32 - targetBits))) == targetIp) {
|
||||
routedNetmaskBits = targetBits;
|
||||
break;
|
||||
@@ -1717,17 +1703,16 @@ void EmbeddedNetworkController::_request(
|
||||
|
||||
// If it's routed, then try to claim and assign it and if successful end loop
|
||||
const InetAddress ip4(Utils::hton(ip),0);
|
||||
if ((routedNetmaskBits > 0)&&(!nmi.allocatedIps.count(ip4))) {
|
||||
if ( (routedNetmaskBits > 0) && (!std::binary_search(ns.allocatedIps.begin(),ns.allocatedIps.end(),ip4)) ) {
|
||||
ipAssignments.push_back(ip4.toIpString());
|
||||
member["ipAssignments"] = ipAssignments;
|
||||
if (nc.staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES) {
|
||||
struct sockaddr_in *const v4ip = reinterpret_cast<struct sockaddr_in *>(&(nc.staticIps[nc.staticIpCount++]));
|
||||
if (nc->staticIpCount < ZT_MAX_ZT_ASSIGNED_ADDRESSES) {
|
||||
struct sockaddr_in *const v4ip = reinterpret_cast<struct sockaddr_in *>(&(nc->staticIps[nc->staticIpCount++]));
|
||||
v4ip->sin_family = AF_INET;
|
||||
v4ip->sin_port = Utils::hton((uint16_t)routedNetmaskBits);
|
||||
v4ip->sin_addr.s_addr = Utils::hton(ip);
|
||||
}
|
||||
haveManagedIpv4AutoAssignment = true;
|
||||
_clearNetworkMemberInfoCache(nwid); // clear cache to prevent IP assignment duplication on many rapid assigns
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1737,114 +1722,27 @@ void EmbeddedNetworkController::_request(
|
||||
}
|
||||
|
||||
// Issue a certificate of ownership for all static IPs
|
||||
if (nc.staticIpCount) {
|
||||
nc.certificatesOfOwnership[0] = CertificateOfOwnership(nwid,now,identity.address(),1);
|
||||
for(unsigned int i=0;i<nc.staticIpCount;++i)
|
||||
nc.certificatesOfOwnership[0].addThing(nc.staticIps[i]);
|
||||
nc.certificatesOfOwnership[0].sign(_signingId);
|
||||
nc.certificateOfOwnershipCount = 1;
|
||||
if (nc->staticIpCount) {
|
||||
nc->certificatesOfOwnership[0] = CertificateOfOwnership(nwid,now,identity.address(),1);
|
||||
for(unsigned int i=0;i<nc->staticIpCount;++i)
|
||||
nc->certificatesOfOwnership[0].addThing(nc->staticIps[i]);
|
||||
nc->certificatesOfOwnership[0].sign(_signingId);
|
||||
nc->certificateOfOwnershipCount = 1;
|
||||
}
|
||||
|
||||
CertificateOfMembership com(now,credentialtmd,nwid,identity.address());
|
||||
if (com.sign(_signingId)) {
|
||||
nc.com = com;
|
||||
nc->com = com;
|
||||
} else {
|
||||
_sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_INTERNAL_SERVER_ERROR);
|
||||
return;
|
||||
}
|
||||
|
||||
if (member != origMember) {
|
||||
member["lastModified"] = now;
|
||||
Mutex::Lock _l(_db_m);
|
||||
_db.put("network",nwids,"member",identity.address().toString(),member);
|
||||
}
|
||||
_removeMemberNonPersistedFields(member);
|
||||
if (member != origMember)
|
||||
_db.saveNetworkMember(nwid,identity.address().toInt(),member);
|
||||
|
||||
_sender->ncSendConfig(nwid,requestPacketId,identity.address(),nc,metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6);
|
||||
}
|
||||
|
||||
void EmbeddedNetworkController::_getNetworkMemberInfo(uint64_t now,uint64_t nwid,_NetworkMemberInfo &nmi)
|
||||
{
|
||||
char pfx[256];
|
||||
Utils::snprintf(pfx,sizeof(pfx),"network/%.16llx/member",nwid);
|
||||
|
||||
{
|
||||
Mutex::Lock _l(_nmiCache_m);
|
||||
std::map<uint64_t,_NetworkMemberInfo>::iterator c(_nmiCache.find(nwid));
|
||||
if ((c != _nmiCache.end())&&((now - c->second.nmiTimestamp) < 1000)) { // a short duration cache but limits CPU use on big networks
|
||||
nmi = c->second;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
Mutex::Lock _l(_db_m);
|
||||
_db.filter(pfx,[&nmi,&now](const std::string &n,const json &member) {
|
||||
try {
|
||||
if (OSUtils::jsonBool(member["authorized"],false)) {
|
||||
++nmi.authorizedMemberCount;
|
||||
|
||||
if (member.count("recentLog")) {
|
||||
const json &mlog = member["recentLog"];
|
||||
if ((mlog.is_array())&&(mlog.size() > 0)) {
|
||||
const json &mlog1 = mlog[0];
|
||||
if (mlog1.is_object()) {
|
||||
if ((now - OSUtils::jsonInt(mlog1["ts"],0ULL)) < ZT_NETCONF_NODE_ACTIVE_THRESHOLD)
|
||||
++nmi.activeMemberCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (OSUtils::jsonBool(member["activeBridge"],false)) {
|
||||
nmi.activeBridges.insert(Address(Utils::hexStrToU64(OSUtils::jsonString(member["id"],"0000000000").c_str())));
|
||||
}
|
||||
|
||||
if (member.count("ipAssignments")) {
|
||||
const json &mips = member["ipAssignments"];
|
||||
if (mips.is_array()) {
|
||||
for(unsigned long i=0;i<mips.size();++i) {
|
||||
InetAddress mip(OSUtils::jsonString(mips[i],""));
|
||||
if ((mip.ss_family == AF_INET)||(mip.ss_family == AF_INET6))
|
||||
nmi.allocatedIps.insert(mip);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
nmi.mostRecentDeauthTime = std::max(nmi.mostRecentDeauthTime,OSUtils::jsonInt(member["lastDeauthorizedTime"],0ULL));
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
return true;
|
||||
});
|
||||
}
|
||||
nmi.nmiTimestamp = now;
|
||||
|
||||
{
|
||||
Mutex::Lock _l(_nmiCache_m);
|
||||
_nmiCache[nwid] = nmi;
|
||||
}
|
||||
}
|
||||
|
||||
void EmbeddedNetworkController::_pushMemberUpdate(uint64_t now,uint64_t nwid,const nlohmann::json &member)
|
||||
{
|
||||
try {
|
||||
const std::string idstr = member["identity"];
|
||||
const std::string mdstr = member["lastRequestMetaData"];
|
||||
if ((idstr.length() > 0)&&(mdstr.length() > 0)) {
|
||||
const Identity id(idstr);
|
||||
bool online;
|
||||
{
|
||||
Mutex::Lock _l(_lastRequestTime_m);
|
||||
std::map< std::pair<uint64_t,uint64_t>,uint64_t >::iterator lrt(_lastRequestTime.find(std::pair<uint64_t,uint64_t>(id.address().toInt(),nwid)));
|
||||
online = ( (lrt != _lastRequestTime.end()) && ((now - lrt->second) < ZT_NETWORK_AUTOCONF_DELAY) );
|
||||
}
|
||||
if (online) {
|
||||
Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> *metaData = new Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY>(mdstr.c_str());
|
||||
try {
|
||||
this->request(nwid,InetAddress(),0,id,*metaData);
|
||||
} catch ( ... ) {}
|
||||
delete metaData;
|
||||
}
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
_sender->ncSendConfig(nwid,requestPacketId,identity.address(),*(nc.get()),metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6);
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <list>
|
||||
#include <thread>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
|
||||
@@ -34,6 +35,7 @@
|
||||
#include "../node/Utils.hpp"
|
||||
#include "../node/Address.hpp"
|
||||
#include "../node/InetAddress.hpp"
|
||||
#include "../node/NonCopyable.hpp"
|
||||
|
||||
#include "../osdep/OSUtils.hpp"
|
||||
#include "../osdep/Thread.hpp"
|
||||
@@ -43,9 +45,6 @@
|
||||
|
||||
#include "JSONDB.hpp"
|
||||
|
||||
// Number of background threads to start -- not actually started until needed
|
||||
#define ZT_EMBEDDEDNETWORKCONTROLLER_BACKGROUND_THREAD_COUNT 4
|
||||
|
||||
// TTL for circuit tests
|
||||
#define ZT_EMBEDDEDNETWORKCONTROLLER_CIRCUIT_TEST_EXPIRATION 120000
|
||||
|
||||
@@ -53,7 +52,7 @@ namespace ZeroTier {
|
||||
|
||||
class Node;
|
||||
|
||||
class EmbeddedNetworkController : public NetworkController
|
||||
class EmbeddedNetworkController : public NetworkController,NonCopyable
|
||||
{
|
||||
public:
|
||||
/**
|
||||
@@ -105,26 +104,28 @@ private:
|
||||
InetAddress fromAddr;
|
||||
Identity identity;
|
||||
Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> metaData;
|
||||
};
|
||||
|
||||
// Gathers a bunch of statistics about members of a network, IP assignments, etc. that we need in various places
|
||||
struct _NetworkMemberInfo
|
||||
{
|
||||
_NetworkMemberInfo() : authorizedMemberCount(0),activeMemberCount(0),totalMemberCount(0),mostRecentDeauthTime(0) {}
|
||||
std::set<Address> activeBridges;
|
||||
std::set<InetAddress> allocatedIps;
|
||||
unsigned long authorizedMemberCount;
|
||||
unsigned long activeMemberCount;
|
||||
unsigned long totalMemberCount;
|
||||
uint64_t mostRecentDeauthTime;
|
||||
uint64_t nmiTimestamp; // time this NMI structure was computed
|
||||
enum {
|
||||
RQENTRY_TYPE_REQUEST = 0,
|
||||
RQENTRY_TYPE_PING = 1
|
||||
} 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 _getNetworkMemberInfo(uint64_t now,uint64_t nwid,_NetworkMemberInfo &nmi);
|
||||
inline void _clearNetworkMemberInfoCache(const uint64_t nwid) { Mutex::Lock _l(_nmiCache_m); _nmiCache.erase(nwid); }
|
||||
void _pushMemberUpdate(uint64_t now,uint64_t nwid,const nlohmann::json &member);
|
||||
|
||||
inline void _startThreads()
|
||||
{
|
||||
Mutex::Lock _l(_threads_m);
|
||||
if (_threads.size() == 0) {
|
||||
long hwc = (long)std::thread::hardware_concurrency();
|
||||
if (hwc < 1)
|
||||
hwc = 1;
|
||||
else if (hwc > 16)
|
||||
hwc = 16;
|
||||
for(long i=0;i<hwc;++i)
|
||||
_threads.push_back(Thread::start(this));
|
||||
}
|
||||
}
|
||||
|
||||
// These init objects with default and static/informational fields
|
||||
inline void _initMember(nlohmann::json &member)
|
||||
@@ -132,7 +133,6 @@ private:
|
||||
if (!member.count("authorized")) member["authorized"] = false;
|
||||
if (!member.count("authHistory")) member["authHistory"] = nlohmann::json::array();
|
||||
if (!member.count("ipAssignments")) member["ipAssignments"] = nlohmann::json::array();
|
||||
if (!member.count("recentLog")) member["recentLog"] = nlohmann::json::array();
|
||||
if (!member.count("activeBridge")) member["activeBridge"] = false;
|
||||
if (!member.count("tags")) member["tags"] = nlohmann::json::array();
|
||||
if (!member.count("capabilities")) member["capabilities"] = nlohmann::json::array();
|
||||
@@ -141,6 +141,11 @@ private:
|
||||
if (!member.count("revision")) member["revision"] = 0ULL;
|
||||
if (!member.count("lastDeauthorizedTime")) member["lastDeauthorizedTime"] = 0ULL;
|
||||
if (!member.count("lastAuthorizedTime")) member["lastAuthorizedTime"] = 0ULL;
|
||||
if (!member.count("vMajor")) member["vMajor"] = -1;
|
||||
if (!member.count("vMinor")) member["vMinor"] = -1;
|
||||
if (!member.count("vRev")) member["vRev"] = -1;
|
||||
if (!member.count("vProto")) member["vProto"] = -1;
|
||||
if (!member.count("physicalAddr")) member["physicalAddr"] = nlohmann::json();
|
||||
member["objtype"] = "member";
|
||||
}
|
||||
inline void _initNetwork(nlohmann::json &network)
|
||||
@@ -167,30 +172,45 @@ private:
|
||||
}
|
||||
network["objtype"] = "network";
|
||||
}
|
||||
inline void _addNetworkNonPersistedFields(nlohmann::json &network,uint64_t now,const _NetworkMemberInfo &nmi)
|
||||
inline void _addNetworkNonPersistedFields(nlohmann::json &network,uint64_t now,const JSONDB::NetworkSummaryInfo &ns)
|
||||
{
|
||||
network["clock"] = now;
|
||||
network["authorizedMemberCount"] = nmi.authorizedMemberCount;
|
||||
network["activeMemberCount"] = nmi.activeMemberCount;
|
||||
network["totalMemberCount"] = nmi.totalMemberCount;
|
||||
network["authorizedMemberCount"] = ns.authorizedMemberCount;
|
||||
network["activeMemberCount"] = ns.activeMemberCount;
|
||||
network["totalMemberCount"] = ns.totalMemberCount;
|
||||
}
|
||||
inline void _addMemberNonPersistedFields(nlohmann::json &member,uint64_t now)
|
||||
inline void _removeNetworkNonPersistedFields(nlohmann::json &network)
|
||||
{
|
||||
network.erase("clock");
|
||||
network.erase("authorizedMemberCount");
|
||||
network.erase("activeMemberCount");
|
||||
network.erase("totalMemberCount");
|
||||
// legacy fields
|
||||
network.erase("lastModified");
|
||||
}
|
||||
inline void _addMemberNonPersistedFields(uint64_t nwid,uint64_t nodeId,nlohmann::json &member,uint64_t now)
|
||||
{
|
||||
member["clock"] = now;
|
||||
Mutex::Lock _l(_memberStatus_m);
|
||||
member["online"] = _memberStatus[_MemberStatusKey(nwid,nodeId)].online(now);
|
||||
}
|
||||
inline void _removeMemberNonPersistedFields(nlohmann::json &member)
|
||||
{
|
||||
member.erase("clock");
|
||||
// legacy fields
|
||||
member.erase("recentLog");
|
||||
member.erase("lastModified");
|
||||
member.erase("lastRequestMetaData");
|
||||
}
|
||||
|
||||
const uint64_t _startTime;
|
||||
|
||||
volatile bool _running;
|
||||
BlockingQueue<_RQEntry *> _queue;
|
||||
Thread _threads[ZT_EMBEDDEDNETWORKCONTROLLER_BACKGROUND_THREAD_COUNT];
|
||||
bool _threadsStarted;
|
||||
std::vector<Thread> _threads;
|
||||
Mutex _threads_m;
|
||||
|
||||
std::map<uint64_t,_NetworkMemberInfo> _nmiCache;
|
||||
Mutex _nmiCache_m;
|
||||
|
||||
JSONDB _db;
|
||||
Mutex _db_m;
|
||||
|
||||
Node *const _node;
|
||||
std::string _path;
|
||||
@@ -201,8 +221,33 @@ private:
|
||||
std::list< ZT_CircuitTest > _tests;
|
||||
Mutex _tests_m;
|
||||
|
||||
std::map< std::pair<uint64_t,uint64_t>,uint64_t > _lastRequestTime; // last request time by <address,networkId>
|
||||
Mutex _lastRequestTime_m;
|
||||
struct _MemberStatusKey
|
||||
{
|
||||
_MemberStatusKey() : networkId(0),nodeId(0) {}
|
||||
_MemberStatusKey(const uint64_t nwid,const uint64_t nid) : networkId(nwid),nodeId(nid) {}
|
||||
uint64_t networkId;
|
||||
uint64_t nodeId;
|
||||
inline bool operator==(const _MemberStatusKey &k) const { return ((k.networkId == networkId)&&(k.nodeId == nodeId)); }
|
||||
};
|
||||
struct _MemberStatus
|
||||
{
|
||||
_MemberStatus() : lastRequestTime(0),vMajor(-1),vMinor(-1),vRev(-1),vProto(-1) {}
|
||||
uint64_t lastRequestTime;
|
||||
int vMajor,vMinor,vRev,vProto;
|
||||
Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> lastRequestMetaData;
|
||||
Identity identity;
|
||||
InetAddress physicalAddr; // last known physical address
|
||||
inline bool online(const uint64_t now) const { return ((now - lastRequestTime) < (ZT_NETWORK_AUTOCONF_DELAY * 2)); }
|
||||
};
|
||||
struct _MemberStatusHash
|
||||
{
|
||||
inline std::size_t operator()(const _MemberStatusKey &networkIdNodeId) const
|
||||
{
|
||||
return (std::size_t)(networkIdNodeId.networkId + networkIdNodeId.nodeId);
|
||||
}
|
||||
};
|
||||
std::unordered_map< _MemberStatusKey,_MemberStatus,_MemberStatusHash > _memberStatus;
|
||||
Mutex _memberStatus_m;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
@@ -18,126 +18,436 @@
|
||||
|
||||
#include "JSONDB.hpp"
|
||||
|
||||
#define ZT_JSONDB_HTTP_TIMEOUT 60000
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
static const nlohmann::json _EMPTY_JSON(nlohmann::json::object());
|
||||
static const std::map<std::string,std::string> _ZT_JSONDB_GET_HEADERS;
|
||||
|
||||
JSONDB::JSONDB(const std::string &basePath) :
|
||||
_basePath(basePath),
|
||||
_summaryThreadRun(true)
|
||||
{
|
||||
if ((_basePath.length() > 7)&&(_basePath.substr(0,7) == "http://")) {
|
||||
// TODO: this doesn't yet support IPv6 since bracketed address notiation isn't supported.
|
||||
// Typically it's just used with 127.0.0.1 anyway.
|
||||
std::string hn = _basePath.substr(7);
|
||||
std::size_t hnend = hn.find_first_of('/');
|
||||
if (hnend != std::string::npos)
|
||||
hn = hn.substr(0,hnend);
|
||||
std::size_t hnsep = hn.find_last_of(':');
|
||||
if (hnsep != std::string::npos)
|
||||
hn[hnsep] = '/';
|
||||
_httpAddr.fromString(hn);
|
||||
if (hnend != std::string::npos)
|
||||
_basePath = _basePath.substr(7 + hnend);
|
||||
if (_basePath.length() == 0)
|
||||
_basePath = "/";
|
||||
if (_basePath[0] != '/')
|
||||
_basePath = std::string("/") + _basePath;
|
||||
} else {
|
||||
OSUtils::mkdir(_basePath.c_str());
|
||||
OSUtils::lockDownFile(_basePath.c_str(),true); // networks might contain auth tokens, etc., so restrict directory permissions
|
||||
}
|
||||
|
||||
unsigned int cnt = 0;
|
||||
while (!_load(_basePath)) {
|
||||
if ((++cnt & 7) == 0)
|
||||
fprintf(stderr,"WARNING: controller still waiting to read '%s'..." ZT_EOL_S,_basePath.c_str());
|
||||
Thread::sleep(250);
|
||||
}
|
||||
|
||||
for(std::unordered_map<uint64_t,_NW>::iterator n(_networks.begin());n!=_networks.end();++n)
|
||||
_recomputeSummaryInfo(n->first);
|
||||
for(;;) {
|
||||
_summaryThread_m.lock();
|
||||
if (_summaryThreadToDo.empty()) {
|
||||
_summaryThread_m.unlock();
|
||||
break;
|
||||
}
|
||||
_summaryThread_m.unlock();
|
||||
Thread::sleep(50);
|
||||
}
|
||||
}
|
||||
|
||||
JSONDB::~JSONDB()
|
||||
{
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
_networks.clear();
|
||||
}
|
||||
Thread t;
|
||||
{
|
||||
Mutex::Lock _l(_summaryThread_m);
|
||||
_summaryThreadRun = false;
|
||||
t = _summaryThread;
|
||||
}
|
||||
if (t)
|
||||
Thread::join(t);
|
||||
}
|
||||
|
||||
bool JSONDB::writeRaw(const std::string &n,const std::string &obj)
|
||||
{
|
||||
if (!_isValidObjectName(n))
|
||||
return false;
|
||||
|
||||
const std::string path(_genPath(n,true));
|
||||
if (!path.length())
|
||||
return false;
|
||||
|
||||
const std::string buf(obj);
|
||||
if (!OSUtils::writeFile(path.c_str(),buf))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JSONDB::put(const std::string &n,const nlohmann::json &obj)
|
||||
{
|
||||
if (!_isValidObjectName(n))
|
||||
return false;
|
||||
|
||||
const std::string path(_genPath(n,true));
|
||||
if (!path.length())
|
||||
return false;
|
||||
|
||||
const std::string buf(OSUtils::jsonDump(obj));
|
||||
if (!OSUtils::writeFile(path.c_str(),buf))
|
||||
return false;
|
||||
|
||||
_E &e = _db[n];
|
||||
e.obj = obj;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const nlohmann::json &JSONDB::get(const std::string &n)
|
||||
{
|
||||
if (!_isValidObjectName(n))
|
||||
return _EMPTY_JSON;
|
||||
|
||||
std::map<std::string,_E>::iterator e(_db.find(n));
|
||||
if (e != _db.end())
|
||||
return e->second.obj;
|
||||
|
||||
const std::string path(_genPath(n,false));
|
||||
if (!path.length())
|
||||
return _EMPTY_JSON;
|
||||
std::string buf;
|
||||
if (!OSUtils::readFile(path.c_str(),buf))
|
||||
return _EMPTY_JSON;
|
||||
|
||||
_E &e2 = _db[n];
|
||||
try {
|
||||
e2.obj = OSUtils::jsonParse(buf);
|
||||
} catch ( ... ) {
|
||||
e2.obj = _EMPTY_JSON;
|
||||
buf = "{}";
|
||||
}
|
||||
|
||||
return e2.obj;
|
||||
}
|
||||
|
||||
void JSONDB::erase(const std::string &n)
|
||||
{
|
||||
if (!_isValidObjectName(n))
|
||||
return;
|
||||
|
||||
std::string path(_genPath(n,true));
|
||||
if (!path.length())
|
||||
return;
|
||||
|
||||
OSUtils::rm(path.c_str());
|
||||
_db.erase(n);
|
||||
}
|
||||
|
||||
void JSONDB::_reload(const std::string &p,const std::string &b)
|
||||
{
|
||||
std::vector<std::string> dl(OSUtils::listDirectory(p.c_str()));
|
||||
for(std::vector<std::string>::const_iterator di(dl.begin());di!=dl.end();++di) {
|
||||
if ((di->length() > 5)&&(di->substr(di->length() - 5) == ".json")) {
|
||||
this->get(b + di->substr(0,di->length() - 5));
|
||||
} else {
|
||||
this->_reload((p + ZT_PATH_SEPARATOR + *di),(b + *di + ZT_PATH_SEPARATOR));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool JSONDB::_isValidObjectName(const std::string &n)
|
||||
{
|
||||
if (n.length() == 0)
|
||||
return false;
|
||||
const char *p = n.c_str();
|
||||
char c;
|
||||
// For security reasons we should not allow dots, backslashes, or other path characters or potential path characters.
|
||||
while ((c = *(p++))) {
|
||||
if (!( ((c >= 'a')&&(c <= 'z')) || ((c >= 'A')&&(c <= 'Z')) || ((c >= '0')&&(c <= '9')) || (c == '/') || (c == '_') || (c == '~') || (c == '-') ))
|
||||
if (_httpAddr) {
|
||||
std::map<std::string,std::string> headers;
|
||||
std::string body;
|
||||
std::map<std::string,std::string> reqHeaders;
|
||||
char tmp[64];
|
||||
Utils::snprintf(tmp,sizeof(tmp),"%lu",(unsigned long)obj.length());
|
||||
reqHeaders["Content-Length"] = tmp;
|
||||
reqHeaders["Content-Type"] = "application/json";
|
||||
const unsigned int sc = Http::PUT(0,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast<const struct sockaddr *>(&_httpAddr),(_basePath+"/"+n).c_str(),reqHeaders,obj.data(),(unsigned long)obj.length(),headers,body);
|
||||
return (sc == 200);
|
||||
} else {
|
||||
const std::string path(_genPath(n,true));
|
||||
if (!path.length())
|
||||
return false;
|
||||
return OSUtils::writeFile(path.c_str(),obj);
|
||||
}
|
||||
}
|
||||
|
||||
bool JSONDB::hasNetwork(const uint64_t networkId) const
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
return (_networks.find(networkId) != _networks.end());
|
||||
}
|
||||
|
||||
bool JSONDB::getNetwork(const uint64_t networkId,nlohmann::json &config) const
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
const std::unordered_map<uint64_t,_NW>::const_iterator i(_networks.find(networkId));
|
||||
if (i == _networks.end())
|
||||
return false;
|
||||
config = nlohmann::json::from_msgpack(i->second.config);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool JSONDB::getNetworkSummaryInfo(const uint64_t networkId,NetworkSummaryInfo &ns) const
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
const std::unordered_map<uint64_t,_NW>::const_iterator i(_networks.find(networkId));
|
||||
if (i == _networks.end())
|
||||
return false;
|
||||
ns = i->second.summaryInfo;
|
||||
return true;
|
||||
}
|
||||
|
||||
int JSONDB::getNetworkAndMember(const uint64_t networkId,const uint64_t nodeId,nlohmann::json &networkConfig,nlohmann::json &memberConfig,NetworkSummaryInfo &ns) const
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
const std::unordered_map<uint64_t,_NW>::const_iterator i(_networks.find(networkId));
|
||||
if (i == _networks.end())
|
||||
return 0;
|
||||
const std::unordered_map< uint64_t,std::vector<uint8_t> >::const_iterator j(i->second.members.find(nodeId));
|
||||
if (j == i->second.members.end())
|
||||
return 1;
|
||||
networkConfig = nlohmann::json::from_msgpack(i->second.config);
|
||||
memberConfig = nlohmann::json::from_msgpack(j->second);
|
||||
ns = i->second.summaryInfo;
|
||||
return 3;
|
||||
}
|
||||
|
||||
bool JSONDB::getNetworkMember(const uint64_t networkId,const uint64_t nodeId,nlohmann::json &memberConfig) const
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
const std::unordered_map<uint64_t,_NW>::const_iterator i(_networks.find(networkId));
|
||||
if (i == _networks.end())
|
||||
return false;
|
||||
const std::unordered_map< uint64_t,std::vector<uint8_t> >::const_iterator j(i->second.members.find(nodeId));
|
||||
if (j == i->second.members.end())
|
||||
return false;
|
||||
memberConfig = nlohmann::json::from_msgpack(j->second);
|
||||
return true;
|
||||
}
|
||||
|
||||
void JSONDB::saveNetwork(const uint64_t networkId,const nlohmann::json &networkConfig)
|
||||
{
|
||||
char n[64];
|
||||
Utils::snprintf(n,sizeof(n),"network/%.16llx",(unsigned long long)networkId);
|
||||
writeRaw(n,OSUtils::jsonDump(networkConfig));
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
_networks[networkId].config = nlohmann::json::to_msgpack(networkConfig);
|
||||
}
|
||||
_recomputeSummaryInfo(networkId);
|
||||
}
|
||||
|
||||
void JSONDB::saveNetworkMember(const uint64_t networkId,const uint64_t nodeId,const nlohmann::json &memberConfig)
|
||||
{
|
||||
char n[256];
|
||||
Utils::snprintf(n,sizeof(n),"network/%.16llx/member/%.10llx",(unsigned long long)networkId,(unsigned long long)nodeId);
|
||||
writeRaw(n,OSUtils::jsonDump(memberConfig));
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
_networks[networkId].members[nodeId] = nlohmann::json::to_msgpack(memberConfig);
|
||||
}
|
||||
_recomputeSummaryInfo(networkId);
|
||||
}
|
||||
|
||||
nlohmann::json JSONDB::eraseNetwork(const uint64_t networkId)
|
||||
{
|
||||
if (!_httpAddr) { // Member deletion is done by Central in harnessed mode, and deleting the cache network entry also deletes all members
|
||||
std::vector<uint64_t> memberIds;
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
const std::unordered_map<uint64_t,_NW>::iterator i(_networks.find(networkId));
|
||||
if (i == _networks.end())
|
||||
return _EMPTY_JSON;
|
||||
for(std::unordered_map< uint64_t,std::vector<uint8_t> >::iterator m(i->second.members.begin());m!=i->second.members.end();++m)
|
||||
memberIds.push_back(m->first);
|
||||
}
|
||||
for(std::vector<uint64_t>::iterator m(memberIds.begin());m!=memberIds.end();++m)
|
||||
eraseNetworkMember(networkId,*m,false);
|
||||
}
|
||||
|
||||
char n[256];
|
||||
Utils::snprintf(n,sizeof(n),"network/%.16llx",(unsigned long long)networkId);
|
||||
|
||||
if (_httpAddr) {
|
||||
// Deletion is currently done by Central in harnessed mode
|
||||
//std::map<std::string,std::string> headers;
|
||||
//std::string body;
|
||||
//Http::DEL(0,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast<const struct sockaddr *>(&_httpAddr),(_basePath+"/"+n).c_str(),_ZT_JSONDB_GET_HEADERS,headers,body);
|
||||
} else {
|
||||
const std::string path(_genPath(n,false));
|
||||
if (path.length())
|
||||
OSUtils::rm(path.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
std::unordered_map<uint64_t,_NW>::iterator i(_networks.find(networkId));
|
||||
if (i == _networks.end())
|
||||
return _EMPTY_JSON; // sanity check, shouldn't happen
|
||||
nlohmann::json tmp(nlohmann::json::from_msgpack(i->second.config));
|
||||
_networks.erase(i);
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
nlohmann::json JSONDB::eraseNetworkMember(const uint64_t networkId,const uint64_t nodeId,bool recomputeSummaryInfo)
|
||||
{
|
||||
char n[256];
|
||||
Utils::snprintf(n,sizeof(n),"network/%.16llx/member/%.10llx",(unsigned long long)networkId,(unsigned long long)nodeId);
|
||||
|
||||
if (_httpAddr) {
|
||||
// Deletion is currently done by the caller in Central harnessed mode
|
||||
//std::map<std::string,std::string> headers;
|
||||
//std::string body;
|
||||
//Http::DEL(0,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast<const struct sockaddr *>(&_httpAddr),(_basePath+"/"+n).c_str(),_ZT_JSONDB_GET_HEADERS,headers,body);
|
||||
} else {
|
||||
const std::string path(_genPath(n,false));
|
||||
if (path.length())
|
||||
OSUtils::rm(path.c_str());
|
||||
}
|
||||
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
std::unordered_map<uint64_t,_NW>::iterator i(_networks.find(networkId));
|
||||
if (i == _networks.end())
|
||||
return _EMPTY_JSON;
|
||||
std::unordered_map< uint64_t,std::vector<uint8_t> >::iterator j(i->second.members.find(nodeId));
|
||||
if (j == i->second.members.end())
|
||||
return _EMPTY_JSON;
|
||||
nlohmann::json tmp(j->second);
|
||||
i->second.members.erase(j);
|
||||
if (recomputeSummaryInfo)
|
||||
_recomputeSummaryInfo(networkId);
|
||||
return tmp;
|
||||
}
|
||||
}
|
||||
|
||||
void JSONDB::threadMain()
|
||||
throw()
|
||||
{
|
||||
std::vector<uint64_t> todo;
|
||||
while (_summaryThreadRun) {
|
||||
Thread::sleep(10);
|
||||
|
||||
{
|
||||
Mutex::Lock _l(_summaryThread_m);
|
||||
if (_summaryThreadToDo.empty())
|
||||
continue;
|
||||
else _summaryThreadToDo.swap(todo);
|
||||
}
|
||||
|
||||
const uint64_t now = OSUtils::now();
|
||||
for(std::vector<uint64_t>::iterator ii(todo.begin());ii!=todo.end();++ii) {
|
||||
const uint64_t networkId = *ii;
|
||||
|
||||
Mutex::Lock _l(_networks_m);
|
||||
std::unordered_map<uint64_t,_NW>::iterator n(_networks.find(networkId));
|
||||
if (n != _networks.end()) {
|
||||
NetworkSummaryInfo &ns = n->second.summaryInfo;
|
||||
ns.activeBridges.clear();
|
||||
ns.allocatedIps.clear();
|
||||
ns.authorizedMemberCount = 0;
|
||||
ns.activeMemberCount = 0;
|
||||
ns.totalMemberCount = 0;
|
||||
ns.mostRecentDeauthTime = 0;
|
||||
|
||||
for(std::unordered_map< uint64_t,std::vector<uint8_t> >::const_iterator m(n->second.members.begin());m!=n->second.members.end();++m) {
|
||||
try {
|
||||
nlohmann::json member(nlohmann::json::from_msgpack(m->second));
|
||||
|
||||
if (OSUtils::jsonBool(member["authorized"],false)) {
|
||||
++ns.authorizedMemberCount;
|
||||
|
||||
try {
|
||||
const nlohmann::json &mlog = member["recentLog"];
|
||||
if ((mlog.is_array())&&(mlog.size() > 0)) {
|
||||
const nlohmann::json &mlog1 = mlog[0];
|
||||
if (mlog1.is_object()) {
|
||||
if ((now - OSUtils::jsonInt(mlog1["ts"],0ULL)) < (ZT_NETWORK_AUTOCONF_DELAY * 2))
|
||||
++ns.activeMemberCount;
|
||||
}
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
|
||||
try {
|
||||
if (OSUtils::jsonBool(member["activeBridge"],false))
|
||||
ns.activeBridges.push_back(Address(m->first));
|
||||
} catch ( ... ) {}
|
||||
|
||||
try {
|
||||
const nlohmann::json &mips = member["ipAssignments"];
|
||||
if (mips.is_array()) {
|
||||
for(unsigned long i=0;i<mips.size();++i) {
|
||||
InetAddress mip(OSUtils::jsonString(mips[i],""));
|
||||
if ((mip.ss_family == AF_INET)||(mip.ss_family == AF_INET6))
|
||||
ns.allocatedIps.push_back(mip);
|
||||
}
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
} else {
|
||||
try {
|
||||
ns.mostRecentDeauthTime = std::max(ns.mostRecentDeauthTime,OSUtils::jsonInt(member["lastDeauthorizedTime"],0ULL));
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
++ns.totalMemberCount;
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
|
||||
std::sort(ns.activeBridges.begin(),ns.activeBridges.end());
|
||||
std::sort(ns.allocatedIps.begin(),ns.allocatedIps.end());
|
||||
|
||||
n->second.summaryInfoLastComputed = now;
|
||||
}
|
||||
}
|
||||
|
||||
todo.clear();
|
||||
}
|
||||
}
|
||||
|
||||
bool JSONDB::_load(const std::string &p)
|
||||
{
|
||||
if (_httpAddr) {
|
||||
// In HTTP harnessed mode we download our entire working data set on startup.
|
||||
|
||||
std::string body;
|
||||
std::map<std::string,std::string> headers;
|
||||
const unsigned int sc = Http::GET(0,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast<const struct sockaddr *>(&_httpAddr),_basePath.c_str(),_ZT_JSONDB_GET_HEADERS,headers,body);
|
||||
if (sc == 200) {
|
||||
try {
|
||||
nlohmann::json dbImg(OSUtils::jsonParse(body));
|
||||
std::string tmp;
|
||||
if (dbImg.is_object()) {
|
||||
Mutex::Lock _l(_networks_m);
|
||||
for(nlohmann::json::iterator i(dbImg.begin());i!=dbImg.end();++i) {
|
||||
nlohmann::json &j = i.value();
|
||||
if (j.is_object()) {
|
||||
std::string id(OSUtils::jsonString(j["id"],"0"));
|
||||
std::string objtype(OSUtils::jsonString(j["objtype"],""));
|
||||
|
||||
if ((id.length() == 16)&&(objtype == "network")) {
|
||||
const uint64_t nwid = Utils::hexStrToU64(id.c_str());
|
||||
if (nwid)
|
||||
_networks[nwid].config = nlohmann::json::to_msgpack(j);
|
||||
} else if ((id.length() == 10)&&(objtype == "member")) {
|
||||
const uint64_t mid = Utils::hexStrToU64(id.c_str());
|
||||
const uint64_t nwid = Utils::hexStrToU64(OSUtils::jsonString(j["nwid"],"0").c_str());
|
||||
if ((mid)&&(nwid))
|
||||
_networks[nwid].members[mid] = nlohmann::json::to_msgpack(j);
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} catch ( ... ) {} // invalid JSON, so maybe incomplete request
|
||||
}
|
||||
return false;
|
||||
|
||||
} else {
|
||||
// In regular mode we recursively read it from controller.d/ on disk
|
||||
|
||||
std::vector<std::string> dl(OSUtils::listDirectory(p.c_str(),true));
|
||||
for(std::vector<std::string>::const_iterator di(dl.begin());di!=dl.end();++di) {
|
||||
if ((di->length() > 5)&&(di->substr(di->length() - 5) == ".json")) {
|
||||
std::string buf;
|
||||
if (OSUtils::readFile((p + ZT_PATH_SEPARATOR_S + *di).c_str(),buf)) {
|
||||
try {
|
||||
nlohmann::json j(OSUtils::jsonParse(buf));
|
||||
std::string id(OSUtils::jsonString(j["id"],"0"));
|
||||
std::string objtype(OSUtils::jsonString(j["objtype"],""));
|
||||
|
||||
if ((id.length() == 16)&&(objtype == "network")) {
|
||||
const uint64_t nwid = Utils::strToU64(id.c_str());
|
||||
if (nwid) {
|
||||
Mutex::Lock _l(_networks_m);
|
||||
_networks[nwid].config = nlohmann::json::to_msgpack(j);
|
||||
}
|
||||
} else if ((id.length() == 10)&&(objtype == "member")) {
|
||||
const uint64_t mid = Utils::strToU64(id.c_str());
|
||||
const uint64_t nwid = Utils::strToU64(OSUtils::jsonString(j["nwid"],"0").c_str());
|
||||
if ((mid)&&(nwid)) {
|
||||
Mutex::Lock _l(_networks_m);
|
||||
_networks[nwid].members[mid] = nlohmann::json::to_msgpack(j);
|
||||
}
|
||||
}
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
} else {
|
||||
this->_load((p + ZT_PATH_SEPARATOR_S + *di));
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void JSONDB::_recomputeSummaryInfo(const uint64_t networkId)
|
||||
{
|
||||
Mutex::Lock _l(_summaryThread_m);
|
||||
if (std::find(_summaryThreadToDo.begin(),_summaryThreadToDo.end(),networkId) == _summaryThreadToDo.end())
|
||||
_summaryThreadToDo.push_back(networkId);
|
||||
if (!_summaryThread)
|
||||
_summaryThread = Thread::start(this);
|
||||
}
|
||||
|
||||
std::string JSONDB::_genPath(const std::string &n,bool create)
|
||||
{
|
||||
std::vector<std::string> pt(OSUtils::split(n.c_str(),"/","",""));
|
||||
if (pt.size() == 0)
|
||||
return std::string();
|
||||
|
||||
char sep;
|
||||
if (_httpAddr) {
|
||||
sep = '/';
|
||||
create = false;
|
||||
} else {
|
||||
sep = ZT_PATH_SEPARATOR;
|
||||
}
|
||||
|
||||
std::string p(_basePath);
|
||||
if (create) OSUtils::mkdir(p.c_str());
|
||||
for(unsigned long i=0,j=(unsigned long)(pt.size()-1);i<j;++i) {
|
||||
p.push_back(ZT_PATH_SEPARATOR);
|
||||
p.push_back(sep);
|
||||
p.append(pt[i]);
|
||||
if (create) OSUtils::mkdir(p.c_str());
|
||||
}
|
||||
|
||||
p.push_back(ZT_PATH_SEPARATOR);
|
||||
p.push_back(sep);
|
||||
p.append(pt[pt.size()-1]);
|
||||
p.append(".json");
|
||||
|
||||
|
||||
@@ -28,86 +28,125 @@
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "../node/Constants.hpp"
|
||||
#include "../node/Utils.hpp"
|
||||
#include "../node/InetAddress.hpp"
|
||||
#include "../node/Mutex.hpp"
|
||||
#include "../ext/json/json.hpp"
|
||||
#include "../osdep/OSUtils.hpp"
|
||||
#include "../osdep/Http.hpp"
|
||||
#include "../osdep/Thread.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* Hierarchical JSON store that persists into the filesystem
|
||||
* Hierarchical JSON store that persists into the filesystem or via HTTP
|
||||
*/
|
||||
class JSONDB
|
||||
{
|
||||
public:
|
||||
JSONDB(const std::string &basePath) :
|
||||
_basePath(basePath)
|
||||
struct NetworkSummaryInfo
|
||||
{
|
||||
_reload(_basePath,std::string());
|
||||
}
|
||||
NetworkSummaryInfo() : authorizedMemberCount(0),activeMemberCount(0),totalMemberCount(0),mostRecentDeauthTime(0) {}
|
||||
std::vector<Address> activeBridges;
|
||||
std::vector<InetAddress> allocatedIps;
|
||||
unsigned long authorizedMemberCount;
|
||||
unsigned long activeMemberCount;
|
||||
unsigned long totalMemberCount;
|
||||
uint64_t mostRecentDeauthTime;
|
||||
};
|
||||
|
||||
inline void reload()
|
||||
{
|
||||
_db.clear();
|
||||
_reload(_basePath,std::string());
|
||||
}
|
||||
JSONDB(const std::string &basePath);
|
||||
~JSONDB();
|
||||
|
||||
bool writeRaw(const std::string &n,const std::string &obj);
|
||||
|
||||
bool put(const std::string &n,const nlohmann::json &obj);
|
||||
bool hasNetwork(const uint64_t networkId) const;
|
||||
|
||||
inline bool put(const std::string &n1,const std::string &n2,const nlohmann::json &obj) { return this->put((n1 + "/" + n2),obj); }
|
||||
inline bool put(const std::string &n1,const std::string &n2,const std::string &n3,const nlohmann::json &obj) { return this->put((n1 + "/" + n2 + "/" + n3),obj); }
|
||||
inline bool put(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const nlohmann::json &obj) { return this->put((n1 + "/" + n2 + "/" + n3 + "/" + n4),obj); }
|
||||
inline bool put(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const std::string &n5,const nlohmann::json &obj) { return this->put((n1 + "/" + n2 + "/" + n3 + "/" + n4 + "/" + n5),obj); }
|
||||
bool getNetwork(const uint64_t networkId,nlohmann::json &config) const;
|
||||
|
||||
const nlohmann::json &get(const std::string &n);
|
||||
bool getNetworkSummaryInfo(const uint64_t networkId,NetworkSummaryInfo &ns) const;
|
||||
|
||||
inline const nlohmann::json &get(const std::string &n1,const std::string &n2) { return this->get((n1 + "/" + n2)); }
|
||||
inline const nlohmann::json &get(const std::string &n1,const std::string &n2,const std::string &n3) { return this->get((n1 + "/" + n2 + "/" + n3)); }
|
||||
inline const nlohmann::json &get(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4) { return this->get((n1 + "/" + n2 + "/" + n3 + "/" + n4)); }
|
||||
inline const nlohmann::json &get(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const std::string &n5) { return this->get((n1 + "/" + n2 + "/" + n3 + "/" + n4 + "/" + n5)); }
|
||||
/**
|
||||
* @return Bit mask: 0 == none, 1 == network only, 3 == network and member
|
||||
*/
|
||||
int getNetworkAndMember(const uint64_t networkId,const uint64_t nodeId,nlohmann::json &networkConfig,nlohmann::json &memberConfig,NetworkSummaryInfo &ns) const;
|
||||
|
||||
void erase(const std::string &n);
|
||||
bool getNetworkMember(const uint64_t networkId,const uint64_t nodeId,nlohmann::json &memberConfig) const;
|
||||
|
||||
inline void erase(const std::string &n1,const std::string &n2) { this->erase(n1 + "/" + n2); }
|
||||
inline void erase(const std::string &n1,const std::string &n2,const std::string &n3) { this->erase(n1 + "/" + n2 + "/" + n3); }
|
||||
inline void erase(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4) { this->erase(n1 + "/" + n2 + "/" + n3 + "/" + n4); }
|
||||
inline void erase(const std::string &n1,const std::string &n2,const std::string &n3,const std::string &n4,const std::string &n5) { this->erase(n1 + "/" + n2 + "/" + n3 + "/" + n4 + "/" + n5); }
|
||||
void saveNetwork(const uint64_t networkId,const nlohmann::json &networkConfig);
|
||||
|
||||
void saveNetworkMember(const uint64_t networkId,const uint64_t nodeId,const nlohmann::json &memberConfig);
|
||||
|
||||
nlohmann::json eraseNetwork(const uint64_t networkId);
|
||||
|
||||
nlohmann::json eraseNetworkMember(const uint64_t networkId,const uint64_t nodeId,bool recomputeSummaryInfo = true);
|
||||
|
||||
std::vector<uint64_t> networkIds() const
|
||||
{
|
||||
std::vector<uint64_t> r;
|
||||
Mutex::Lock _l(_networks_m);
|
||||
for(std::unordered_map<uint64_t,_NW>::const_iterator n(_networks.begin());n!=_networks.end();++n)
|
||||
r.push_back(n->first);
|
||||
return r;
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
inline void filter(const std::string &prefix,F func)
|
||||
inline void eachMember(const uint64_t networkId,F func)
|
||||
{
|
||||
for(std::map<std::string,_E>::iterator i(_db.lower_bound(prefix));i!=_db.end();) {
|
||||
if ((i->first.length() >= prefix.length())&&(!memcmp(i->first.data(),prefix.data(),prefix.length()))) {
|
||||
if (!func(i->first,get(i->first))) {
|
||||
std::map<std::string,_E>::iterator i2(i); ++i2;
|
||||
this->erase(i->first);
|
||||
i = i2;
|
||||
} else ++i;
|
||||
} else break;
|
||||
Mutex::Lock _l(_networks_m);
|
||||
std::unordered_map<uint64_t,_NW>::const_iterator i(_networks.find(networkId));
|
||||
if (i != _networks.end()) {
|
||||
for(std::unordered_map< uint64_t,std::vector<uint8_t> >::const_iterator m(i->second.members.begin());m!=i->second.members.end();++m) {
|
||||
try {
|
||||
func(networkId,m->first,nlohmann::json::from_msgpack(m->second));
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inline bool operator==(const JSONDB &db) const { return ((_basePath == db._basePath)&&(_db == db._db)); }
|
||||
inline bool operator!=(const JSONDB &db) const { return (!(*this == db)); }
|
||||
template<typename F>
|
||||
inline void eachId(F func)
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
for(std::unordered_map<uint64_t,_NW>::const_iterator i(_networks.begin());i!=_networks.end();++i) {
|
||||
for(std::unordered_map< uint64_t,std::vector<uint8_t> >::const_iterator m(i->second.members.begin());m!=i->second.members.end();++m) {
|
||||
try {
|
||||
func(i->first,m->first);
|
||||
} catch ( ... ) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void threadMain()
|
||||
throw();
|
||||
|
||||
private:
|
||||
void _reload(const std::string &p,const std::string &b);
|
||||
bool _isValidObjectName(const std::string &n);
|
||||
bool _load(const std::string &p);
|
||||
void _recomputeSummaryInfo(const uint64_t networkId);
|
||||
std::string _genPath(const std::string &n,bool create);
|
||||
|
||||
struct _E
|
||||
std::string _basePath;
|
||||
InetAddress _httpAddr;
|
||||
|
||||
Thread _summaryThread;
|
||||
std::vector<uint64_t> _summaryThreadToDo;
|
||||
volatile bool _summaryThreadRun;
|
||||
Mutex _summaryThread_m;
|
||||
|
||||
struct _NW
|
||||
{
|
||||
nlohmann::json obj;
|
||||
inline bool operator==(const _E &e) const { return (obj == e.obj); }
|
||||
inline bool operator!=(const _E &e) const { return (obj != e.obj); }
|
||||
_NW() : summaryInfoLastComputed(0) {}
|
||||
std::vector<uint8_t> config;
|
||||
NetworkSummaryInfo summaryInfo;
|
||||
uint64_t summaryInfoLastComputed;
|
||||
std::unordered_map< uint64_t,std::vector<uint8_t> > members;
|
||||
};
|
||||
|
||||
std::string _basePath;
|
||||
std::map<std::string,_E> _db;
|
||||
std::unordered_map<uint64_t,_NW> _networks;
|
||||
Mutex _networks_m;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
@@ -227,22 +227,12 @@ This returns an object containing all currently online members and the most rece
|
||||
| activeBridge | boolean | Member is able to bridge to other Ethernet nets | YES |
|
||||
| identity | string | Member's public ZeroTier identity (if known) | no |
|
||||
| ipAssignments | array[string] | Managed IP address assignments | YES |
|
||||
| memberRevision | integer | Member revision counter | no |
|
||||
| recentLog | array[object] | Recent member activity log; see below | no |
|
||||
| revision | integer | Member revision counter | no |
|
||||
| vMajor | integer | Most recently known major version | no |
|
||||
| vMinor | integer | Most recently known minor version | no |
|
||||
| vRev | integer | Most recently known revision | no |
|
||||
| vProto | integer | Most recently known protocl version | no |
|
||||
| physicalAddr | string | Last known physical IP/port or null if none | no |
|
||||
|
||||
Note that managed IP assignments are only used if they fall within a managed route. Otherwise they are ignored.
|
||||
|
||||
**Recent log object format:**
|
||||
|
||||
| Field | Type | Description |
|
||||
| --------------------- | ------------- | ------------------------------------------------- |
|
||||
| ts | integer | Time of request, ms since epoch |
|
||||
| auth | boolean | Was member authorized? |
|
||||
| authBy | string | How was member authorized? |
|
||||
| vMajor | integer | Client major version or -1 if unknown |
|
||||
| vMinor | integer | Client minor version or -1 if unknown |
|
||||
| vRev | integer | Client revision or -1 if unknown |
|
||||
| vProto | integer | ZeroTier protocol version reported by client |
|
||||
| fromAddr | string | Physical address if known |
|
||||
|
||||
The controller can only know a member's `fromAddr` if it's able to establish a direct path to it. Members behind very restrictive firewalls may not have this information since the controller will be receiving the member's requests by way of a relay. ZeroTier does not back-trace IP paths as packets are relayed since this would add a lot of protocol overhead.
|
||||
|
||||
@@ -95,7 +95,6 @@ async.series([function(nextStep) {
|
||||
creationTime: parseInt(row.creationTime)||0,
|
||||
enableBroadcast: !!row.enableBroadcast,
|
||||
ipAssignmentPools: [],
|
||||
lastModified: Date.now(),
|
||||
multicastLimit: row.multicastLimit||32,
|
||||
name: row.name||'',
|
||||
private: !!row.private,
|
||||
@@ -177,7 +176,6 @@ async.series([function(nextStep) {
|
||||
ipAssignments: [],
|
||||
lastAuthorizedTime: (row.authorized) ? Date.now() : 0,
|
||||
lastDeauthorizedTime: (row.authorized) ? 0 : Date.now(),
|
||||
lastModified: Date.now(),
|
||||
lastRequestMetaData: '',
|
||||
noAutoAssignIps: false,
|
||||
nwid: row.networkId,
|
||||
|
||||
6
zto/ext/arm32-neon-salsa2012-asm/README.md
Normal file
6
zto/ext/arm32-neon-salsa2012-asm/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
ARM NEON (32-bit) ASM implementation of Salsa20/12
|
||||
======
|
||||
|
||||
This is from [supercop](http://bench.cr.yp.to/supercop.html) and was originally written by Daniel J. Bernstein. Code is in the public domain like the rest of Salsa20. It's much faster than the naive implementation.
|
||||
|
||||
It's included automatically in 32-bit Linux ARM builds. It likely will not work on 64-bit ARM, so it'll need to be ported at least. That will unfortunately keep it out of mobile versions for now since those are all going 64-bit.
|
||||
23
zto/ext/arm32-neon-salsa2012-asm/salsa2012.h
Normal file
23
zto/ext/arm32-neon-salsa2012-asm/salsa2012.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#ifndef ZT_SALSA2012_ARM32NEON_ASM
|
||||
#define ZT_SALSA2012_ARM32NEON_ASM
|
||||
|
||||
#if defined(__linux__) || defined(linux) || defined(__LINUX__) || defined(__linux)
|
||||
#include <sys/auxv.h>
|
||||
#include <asm/hwcap.h>
|
||||
#define zt_arm_has_neon() ((getauxval(AT_HWCAP) & HWCAP_NEON) != 0)
|
||||
#else
|
||||
#define zt_arm_has_neon() (true)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// ciphertext buffer, message/NULL, length, nonce (8 bytes), key (32 bytes)
|
||||
extern int zt_salsa2012_armneon3_xor(unsigned char *c,const unsigned char *m,unsigned long long len,const unsigned char *n,const unsigned char *k);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
2231
zto/ext/arm32-neon-salsa2012-asm/salsa2012.s
Normal file
2231
zto/ext/arm32-neon-salsa2012-asm/salsa2012.s
Normal file
File diff suppressed because it is too large
Load Diff
20
zto/ext/installfiles/linux/zerotier-containerized/Dockerfile
Normal file
20
zto/ext/installfiles/linux/zerotier-containerized/Dockerfile
Normal file
@@ -0,0 +1,20 @@
|
||||
FROM alpine:latest
|
||||
MAINTAINER Adam Ierymenko <adam.ierymenko@zerotier.com>
|
||||
|
||||
LABEL version="1.1.14"
|
||||
LABEL description="Containerized ZeroTier One for use on CoreOS or other Docker-only Linux hosts."
|
||||
|
||||
# Uncomment to build in container
|
||||
#RUN apk add --update alpine-sdk linux-headers
|
||||
|
||||
RUN apk add --update libgcc libstdc++
|
||||
|
||||
ADD zerotier-one /
|
||||
RUN chmod 0755 /zerotier-one
|
||||
RUN ln -sf /zerotier-one /zerotier-cli
|
||||
RUN mkdir -p /var/lib/zerotier-one
|
||||
|
||||
ADD main.sh /
|
||||
RUN chmod 0755 /main.sh
|
||||
|
||||
ENTRYPOINT /main.sh
|
||||
10
zto/ext/installfiles/linux/zerotier-containerized/main.sh
Executable file
10
zto/ext/installfiles/linux/zerotier-containerized/main.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
export PATH=/bin:/usr/bin:/usr/local/bin:/sbin:/usr/sbin
|
||||
|
||||
if [ ! -e /dev/net/tun ]; then
|
||||
echo 'FATAL: cannot start ZeroTier One in container: /dev/net/tun not present.'
|
||||
exit 1
|
||||
fi
|
||||
|
||||
exec /zerotier-one
|
||||
@@ -646,7 +646,7 @@
|
||||
<key>OVERWRITE_PERMISSIONS</key>
|
||||
<false/>
|
||||
<key>VERSION</key>
|
||||
<string>1.2.2</string>
|
||||
<string>1.2.4</string>
|
||||
</dict>
|
||||
<key>PROJECT_COMMENTS</key>
|
||||
<dict>
|
||||
|
||||
@@ -43,4 +43,13 @@ ln -sf "/Library/Application Support/ZeroTier/One/zerotier-one" zerotier-idtool
|
||||
|
||||
launchctl load /Library/LaunchDaemons/com.zerotier.one.plist >>/dev/null 2>&1
|
||||
|
||||
sleep 1
|
||||
|
||||
if [ -f /tmp/zt1-gui-restart.tmp ];
|
||||
for u in `cat /tmp/zt1-gui-restart.tmp`; do
|
||||
su $u -c '/Applications/ZeroTier\ One.app/Contents/MacOS/ZeroTier\ One &' >>/dev/null 2>&1 &
|
||||
done
|
||||
fi
|
||||
rm -f /tmp/zt1-gui-restart.tmp
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -2,6 +2,19 @@
|
||||
|
||||
export PATH=/bin:/usr/bin:/sbin:/usr/sbin
|
||||
|
||||
rm -f /tmp/zt1-gui-restart.tmp
|
||||
for i in `ps axuwww | tr -s ' ' ',' | grep -F '/Applications/ZeroTier,One.app' | grep -F -v grep | cut -d , -f 1,2 | xargs`; do
|
||||
u=`echo $i | cut -d , -f 1`
|
||||
p=`echo $i | cut -d , -f 2`
|
||||
if [ ! -z "$u" -a "0$p" -gt 0 ]; then
|
||||
kill $p >>/dev/null 2>&1
|
||||
sleep 0.2
|
||||
kill -9 $p >>/dev/null 2>&1
|
||||
echo "$u" >>/tmp/zt1-gui-restart.tmp
|
||||
fi
|
||||
done
|
||||
chmod 0600 /tmp/zt1-gui-restart.tmp
|
||||
|
||||
if [ -f /Library/LaunchDaemons/com.zerotier.one.plist ]; then
|
||||
launchctl unload /Library/LaunchDaemons/com.zerotier.one.plist >>/dev/null 2>&1
|
||||
fi
|
||||
|
||||
@@ -28,13 +28,11 @@ echo "Removing ZeroTier One files..."
|
||||
|
||||
rm -rf '/Applications/ZeroTier One.app'
|
||||
rm -f '/usr/bin/zerotier-one' '/usr/bin/zerotier-idtool' '/usr/bin/zerotier-cli' '/Library/LaunchDaemons/com.zerotier.one.plist'
|
||||
mkdir -p /tmp/ZeroTierOne_uninstall_tmp
|
||||
cp "/Library/Application Support/ZeroTier/One/*.secret" /tmp/ZeroTierOne_uninstall_tmp
|
||||
rm -rf '/Library/Application Support/ZeroTier/One'
|
||||
mkdir -p '/Library/Application Support/ZeroTier/One'
|
||||
cp "/tmp/ZeroTierOne_uninstall_tmp/*.secret" '/Library/Application Support/ZeroTier/One'
|
||||
chmod 0600 "/Library/Application Support/ZeroTier/One/*.secret"
|
||||
rm -rf /tmp/ZeroTierOne_uninstall_tmp
|
||||
|
||||
cd '/Library/Application Support/ZeroTier/One'
|
||||
if [ "`pwd`" = '/Library/Application Support/ZeroTier/One' ]; then
|
||||
rm -rf *.d *.sh *.log *.old *.kext *.conf *.pkg *.dmg *.pid *.port *.save *.bin planet zerotier-* devicemap
|
||||
fi
|
||||
|
||||
echo 'Uninstall complete.'
|
||||
echo
|
||||
|
||||
@@ -27,10 +27,10 @@
|
||||
<ROW Property="CTRLS" Value="2"/>
|
||||
<ROW Property="MSIFASTINSTALL" MultiBuildValue="DefaultBuild:2"/>
|
||||
<ROW Property="Manufacturer" Value="ZeroTier, Inc."/>
|
||||
<ROW Property="ProductCode" Value="1033:{C2C8F21B-95CA-4E32-90E1-154D180212FE} " Type="16"/>
|
||||
<ROW Property="ProductCode" Value="1033:{0AF2DC73-6629-41A1-B0C6-B110582FEE29} " Type="16"/>
|
||||
<ROW Property="ProductLanguage" Value="1033"/>
|
||||
<ROW Property="ProductName" Value="ZeroTier One"/>
|
||||
<ROW Property="ProductVersion" Value="1.2.2" Type="32"/>
|
||||
<ROW Property="ProductVersion" Value="1.2.4" Type="32"/>
|
||||
<ROW Property="REBOOT" MultiBuildValue="DefaultBuild:ReallySuppress"/>
|
||||
<ROW Property="RUNAPPLICATION" Value="1" Type="4"/>
|
||||
<ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND;AI_SETUPEXEPATH;SETUPEXEDIR"/>
|
||||
@@ -60,7 +60,7 @@
|
||||
<ROW Directory="x86_Dir" Directory_Parent="tapwindows_Dir" DefaultDir="x86"/>
|
||||
</COMPONENT>
|
||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiCompsComponent">
|
||||
<ROW Component="AI_CustomARPName" ComponentId="{B16DE57C-0F91-4A6D-B059-E2467CACEC1C}" Directory_="APPDIR" Attributes="4" KeyPath="DisplayName" Options="1"/>
|
||||
<ROW Component="AI_CustomARPName" ComponentId="{BEF49A0A-3D61-4162-8934-88473D8A6F3D}" Directory_="APPDIR" Attributes="4" KeyPath="DisplayName" Options="1"/>
|
||||
<ROW Component="AI_DisableModify" ComponentId="{020DCABD-5D56-49B9-AF48-F07F0B55E590}" Directory_="APPDIR" Attributes="4" KeyPath="NoModify" Options="1"/>
|
||||
<ROW Component="AI_ExePath" ComponentId="{8E02B36C-7A19-429B-A93E-77A9261AC918}" Directory_="APPDIR" Attributes="4" KeyPath="AI_ExePath"/>
|
||||
<ROW Component="Hardcodet.Wpf.TaskbarNotification.dll" ComponentId="{BEA825AF-2555-44AF-BE40-47FFC16DCBA6}" Directory_="APPDIR" Attributes="0" KeyPath="Hardcodet.Wpf.TaskbarNotification.dll"/>
|
||||
@@ -432,7 +432,7 @@
|
||||
<ROW XmlAttribute="xsischemaLocation" XmlElement="swidsoftware_identification_tag" Name="xsi:schemaLocation" Flags="14" Order="3" Value="http://standards.iso.org/iso/19770/-2/2008/schema.xsd software_identification_tag.xsd"/>
|
||||
</COMPONENT>
|
||||
<COMPONENT cid="caphyon.advinst.msicomp.XmlElementComponent">
|
||||
<ROW XmlElement="swidbuild" ParentElement="swidnumeric" Name="swid:build" Condition="1" Order="2" Flags="14" Text="2"/>
|
||||
<ROW XmlElement="swidbuild" ParentElement="swidnumeric" Name="swid:build" Condition="1" Order="2" Flags="14" Text="4"/>
|
||||
<ROW XmlElement="swidentitlement_required_indicator" ParentElement="swidsoftware_identification_tag" Name="swid:entitlement_required_indicator" Condition="1" Order="0" Flags="14" Text="false"/>
|
||||
<ROW XmlElement="swidmajor" ParentElement="swidnumeric" Name="swid:major" Condition="1" Order="0" Flags="14" Text="1"/>
|
||||
<ROW XmlElement="swidminor" ParentElement="swidnumeric" Name="swid:minor" Condition="1" Order="1" Flags="14" Text="2"/>
|
||||
|
||||
@@ -26,7 +26,7 @@ This is a nuspec. It mostly adheres to https://docs.nuget.org/create/Nuspec-Refe
|
||||
<!-- version should MATCH as closely as possible with the underlying software -->
|
||||
<!-- Is the version a prerelease of a version? https://docs.nuget.org/create/versioning#creating-prerelease-packages -->
|
||||
<!-- Note that unstable versions like 0.0.1 can be considered a released version, but it's possible that one can release a 0.0.1-beta before you release a 0.0.1 version. If the version number is final, that is considered a released version and not a prerelease. -->
|
||||
<version>1.2.2</version>
|
||||
<version>1.2.4</version>
|
||||
<!-- <packageSourceUrl>Where is this Chocolatey package located (think GitHub)? packageSourceUrl is highly recommended for the community feed</packageSourceUrl>-->
|
||||
<!-- owners is a poor name for maintainers of the package. It sticks around by this name for compatibility reasons. It basically means you. -->
|
||||
<!--<owners>ZeroTier, Inc.</owners>-->
|
||||
|
||||
@@ -1,14 +1,13 @@
|
||||
The library is licensed under the MIT License
|
||||
<http://opensource.org/licenses/MIT>:
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2016 Niels Lohmann
|
||||
Copyright (c) 2013-2017 Niels Lohmann
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
@@ -3,13 +3,34 @@
|
||||
[](https://travis-ci.org/nlohmann/json)
|
||||
[](https://ci.appveyor.com/project/nlohmann/json)
|
||||
[](https://coveralls.io/r/nlohmann/json)
|
||||
[](http://melpon.org/wandbox/permlink/fsf5FqYe6GoX68W6)
|
||||
[](https://scan.coverity.com/projects/nlohmann-json)
|
||||
[](https://www.codacy.com/app/nlohmann/json?utm_source=github.com&utm_medium=referral&utm_content=nlohmann/json&utm_campaign=Badge_Grade)
|
||||
[](http://melpon.org/wandbox/permlink/nv9fOg0XVVhWmFFy)
|
||||
[](http://nlohmann.github.io/json)
|
||||
[](https://raw.githubusercontent.com/nlohmann/json/master/LICENSE.MIT)
|
||||
[](https://github.com/nlohmann/json/releases)
|
||||
[](http://github.com/nlohmann/json/issues)
|
||||
[](https://bestpractices.coreinfrastructure.org/projects/289)
|
||||
|
||||
- [Design goals](#design-goals)
|
||||
- [Integration](#integration)
|
||||
- [Examples](#examples)
|
||||
- [JSON as first-class data type](#json-as-first-class-data-type)
|
||||
- [Serialization / Deserialization](#serialization--deserialization)
|
||||
- [STL-like access](#stl-like-access)
|
||||
- [Conversion from STL containers](#conversion-from-stl-containers)
|
||||
- [JSON Pointer and JSON Patch](#json-pointer-and-json-patch)
|
||||
- [Implicit conversions](#implicit-conversions)
|
||||
- [Conversions to/from arbitrary types](#arbitrary-types-conversions)
|
||||
- [Binary formats (CBOR and MessagePack)](#binary-formats-cbor-and-messagepack)
|
||||
- [Supported compilers](#supported-compilers)
|
||||
- [License](#license)
|
||||
- [Thanks](#thanks)
|
||||
- [Used third-party tools](#used-third-party-tools)
|
||||
- [Projects using JSON for Modern C++](#projects-using-json-for-modern-c)
|
||||
- [Notes](#notes)
|
||||
- [Execute unit tests](#execute-unit-tests)
|
||||
|
||||
## Design goals
|
||||
|
||||
There are myriads of [JSON](http://json.org) libraries out there, and each may even have its reason to exist. Our class had these design goals:
|
||||
@@ -24,7 +45,7 @@ Other aspects were not so important to us:
|
||||
|
||||
- **Memory efficiency**. Each JSON object has an overhead of one pointer (the maximal size of a union) and one enumeration element (1 byte). The default generalization uses the following C++ data types: `std::string` for strings, `int64_t`, `uint64_t` or `double` for numbers, `std::map` for objects, `std::vector` for arrays, and `bool` for Booleans. However, you can template the generalized class `basic_json` to your needs.
|
||||
|
||||
- **Speed**. We currently implement the parser as naive [recursive descent parser](http://en.wikipedia.org/wiki/Recursive_descent_parser) with hand coded string handling. It is fast enough, but a [LALR-parser](http://en.wikipedia.org/wiki/LALR_parser) may be even faster (but would consist of more files which makes the integration harder).
|
||||
- **Speed**. There are certainly [faster JSON libraries](https://github.com/miloyip/nativejson-benchmark#parsing-time) out there. However, if your goal is to speed up your development by adding JSON support with a single header, then this library is the way to go. If you know how to use a `std::vector` or `std::map`, you are already set.
|
||||
|
||||
See the [contribution guidelines](https://github.com/nlohmann/json/blob/master/.github/CONTRIBUTING.md#please-dont) for more information.
|
||||
|
||||
@@ -44,9 +65,15 @@ to the files you want to use JSON objects. That's it. Do not forget to set the n
|
||||
|
||||
:beer: If you are using OS X and [Homebrew](http://brew.sh), just type `brew tap nlohmann/json` and `brew install nlohmann_json` and you're set. If you want the bleeding edge rather than the latest release, use `brew install nlohmann_json --HEAD`.
|
||||
|
||||
:warning: [Version 3.0.0](https://github.com/nlohmann/json/wiki/Road-toward-3.0.0) is currently under development. Branch `develop` is used for the ongoing work and is probably **unstable**. Please use the `master` branch for the last stable version 2.1.1.
|
||||
|
||||
|
||||
## Examples
|
||||
|
||||
Beside the examples below, you may want to check the [documentation](https://nlohmann.github.io/json/) where each function contains a separate code example (e.g., check out [`emplace()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a602f275f0359ab181221384989810604.html#a602f275f0359ab181221384989810604)). All [example files](https://github.com/nlohmann/json/tree/develop/doc/examples) can be compiled and executed on their own (e.g., file [emplace.cpp](https://github.com/nlohmann/json/blob/develop/doc/examples/emplace.cpp)).
|
||||
|
||||
### JSON as first-class data type
|
||||
|
||||
Here are some examples to give you an idea how to use the class.
|
||||
|
||||
Assume you want to create the JSON object
|
||||
@@ -129,6 +156,8 @@ json array_not_object = { json::array({"currency", "USD"}), json::array({"value"
|
||||
|
||||
### Serialization / Deserialization
|
||||
|
||||
#### To/from strings
|
||||
|
||||
You can create an object (deserialization) by appending `_json` to a string literal:
|
||||
|
||||
```cpp
|
||||
@@ -142,8 +171,14 @@ auto j2 = R"(
|
||||
"pi": 3.141
|
||||
}
|
||||
)"_json;
|
||||
```
|
||||
|
||||
// or explicitly
|
||||
Note that without appending the `_json` suffix, the passed string literal is not parsed, but just used as JSON string value. That is, `json j = "{ \"happy\": true, \"pi\": 3.141 }"` would just store the string `"{ "happy": true, "pi": 3.141 }"` rather than parsing the actual object.
|
||||
|
||||
The above example can also be expressed explicitly using `json::parse()`:
|
||||
|
||||
```cpp
|
||||
// parse explicitly
|
||||
auto j3 = json::parse("{ \"happy\": true, \"pi\": 3.141 }");
|
||||
```
|
||||
|
||||
@@ -162,6 +197,8 @@ std::cout << j.dump(4) << std::endl;
|
||||
// }
|
||||
```
|
||||
|
||||
#### To/from streams (e.g. files, string streams)
|
||||
|
||||
You can also use streams to serialize and deserialize:
|
||||
|
||||
```cpp
|
||||
@@ -176,10 +213,37 @@ std::cout << j;
|
||||
std::cout << std::setw(4) << j << std::endl;
|
||||
```
|
||||
|
||||
These operators work for any subclasses of `std::istream` or `std::ostream`.
|
||||
These operators work for any subclasses of `std::istream` or `std::ostream`. Here is the same example with files:
|
||||
|
||||
```cpp
|
||||
// read a JSON file
|
||||
std::ifstream i("file.json");
|
||||
json j;
|
||||
i >> j;
|
||||
|
||||
// write prettified JSON to another file
|
||||
std::ofstream o("pretty.json");
|
||||
o << std::setw(4) << j << std::endl;
|
||||
```
|
||||
|
||||
Please note that setting the exception bit for `failbit` is inappropriate for this use case. It will result in program termination due to the `noexcept` specifier in use.
|
||||
|
||||
#### Read from iterator range
|
||||
|
||||
You can also read JSON from an iterator range; that is, from any container accessible by iterators whose content is stored as contiguous byte sequence, for instance a `std::vector<std::uint8_t>`:
|
||||
|
||||
```cpp
|
||||
std::vector<std::uint8_t> v = {'t', 'r', 'u', 'e'};
|
||||
json j = json::parse(v.begin(), v.end());
|
||||
```
|
||||
|
||||
You may leave the iterators for the range [begin, end):
|
||||
|
||||
```cpp
|
||||
std::vector<std::uint8_t> v = {'t', 'r', 'u', 'e'};
|
||||
json j = json::parse(v);
|
||||
```
|
||||
|
||||
|
||||
### STL-like access
|
||||
|
||||
@@ -192,6 +256,9 @@ j.push_back("foo");
|
||||
j.push_back(1);
|
||||
j.push_back(true);
|
||||
|
||||
// also use emplace_back
|
||||
j.emplace_back(1.78);
|
||||
|
||||
// iterate the array
|
||||
for (json::iterator it = j.begin(); it != j.end(); ++it) {
|
||||
std::cout << *it << '\n';
|
||||
@@ -207,6 +274,9 @@ const std::string tmp = j[0];
|
||||
j[1] = 42;
|
||||
bool foo = j.at(2);
|
||||
|
||||
// comparison
|
||||
j == "[\"foo\", 1, true]"_json; // true
|
||||
|
||||
// other stuff
|
||||
j.size(); // 3 entries
|
||||
j.empty(); // false
|
||||
@@ -221,15 +291,15 @@ j.is_object();
|
||||
j.is_array();
|
||||
j.is_string();
|
||||
|
||||
// comparison
|
||||
j == "[\"foo\", 1, true]"_json; // true
|
||||
|
||||
// create an object
|
||||
json o;
|
||||
o["foo"] = 23;
|
||||
o["bar"] = false;
|
||||
o["baz"] = 3.141;
|
||||
|
||||
// also use emplace
|
||||
o.emplace("weather", "sunny");
|
||||
|
||||
// special iterator member functions for objects
|
||||
for (json::iterator it = o.begin(); it != o.end(); ++it) {
|
||||
std::cout << it.key() << " : " << it.value() << "\n";
|
||||
@@ -383,6 +453,252 @@ int vi = jn.get<int>();
|
||||
// etc.
|
||||
```
|
||||
|
||||
### Arbitrary types conversions
|
||||
|
||||
Every type can be serialized in JSON, not just STL-containers and scalar types. Usually, you would do something along those lines:
|
||||
|
||||
```cpp
|
||||
namespace ns {
|
||||
// a simple struct to model a person
|
||||
struct person {
|
||||
std::string name;
|
||||
std::string address;
|
||||
int age;
|
||||
};
|
||||
}
|
||||
|
||||
ns::person p = {"Ned Flanders", "744 Evergreen Terrace", 60};
|
||||
|
||||
// convert to JSON: copy each value into the JSON object
|
||||
json j;
|
||||
j["name"] = p.name;
|
||||
j["address"] = p.address;
|
||||
j["age"] = p.age;
|
||||
|
||||
// ...
|
||||
|
||||
// convert from JSON: copy each value from the JSON object
|
||||
ns::person p {
|
||||
j["name"].get<std::string>(),
|
||||
j["address"].get<std::string>(),
|
||||
j["age"].get<int>()
|
||||
};
|
||||
```
|
||||
|
||||
It works, but that's quite a lot of boilerplate... Fortunately, there's a better way:
|
||||
|
||||
```cpp
|
||||
// create a person
|
||||
ns::person p {"Ned Flanders", "744 Evergreen Terrace", 60};
|
||||
|
||||
// conversion: person -> json
|
||||
json j = p;
|
||||
|
||||
std::cout << j << std::endl;
|
||||
// {"address":"744 Evergreen Terrace","age":60,"name":"Ned Flanders"}
|
||||
|
||||
// conversion: json -> person
|
||||
ns::person p2 = j;
|
||||
|
||||
// that's it
|
||||
assert(p == p2);
|
||||
```
|
||||
|
||||
#### Basic usage
|
||||
|
||||
To make this work with one of your types, you only need to provide two functions:
|
||||
|
||||
```cpp
|
||||
using nlohmann::json;
|
||||
|
||||
namespace ns {
|
||||
void to_json(json& j, const person& p) {
|
||||
j = json{{"name", p.name}, {"address", p.address}, {"age", p.age}};
|
||||
}
|
||||
|
||||
void from_json(const json& j, person& p) {
|
||||
p.name = j.at("name").get<std::string>();
|
||||
p.address = j.at("address").get<std::string>();
|
||||
p.age = j.at("age").get<int>();
|
||||
}
|
||||
} // namespace ns
|
||||
```
|
||||
|
||||
That's all! When calling the `json` constructor with your type, your custom `to_json` method will be automatically called.
|
||||
Likewise, when calling `get<your_type>()`, the `from_json` method will be called.
|
||||
|
||||
Some important things:
|
||||
|
||||
* Those methods **MUST** be in your type's namespace (which can be the global namespace), or the library will not be able to locate them (in this example, they are in namespace `ns`, where `person` is defined).
|
||||
* When using `get<your_type>()`, `your_type` **MUST** be [DefaultConstructible](http://en.cppreference.com/w/cpp/concept/DefaultConstructible). (There is a way to bypass this requirement described later.)
|
||||
* In function `from_json`, use function [`at()`](https://nlohmann.github.io/json/classnlohmann_1_1basic__json_a93403e803947b86f4da2d1fb3345cf2c.html#a93403e803947b86f4da2d1fb3345cf2c) to access the object values rather than `operator[]`. In case a key does not exists, `at` throws an exception that you can handle, whereas `operator[]` exhibits undefined behavior.
|
||||
|
||||
#### How do I convert third-party types?
|
||||
|
||||
This requires a bit more advanced technique. But first, let's see how this conversion mechanism works:
|
||||
|
||||
The library uses **JSON Serializers** to convert types to json.
|
||||
The default serializer for `nlohmann::json` is `nlohmann::adl_serializer` (ADL means [Argument-Dependent Lookup](http://en.cppreference.com/w/cpp/language/adl)).
|
||||
|
||||
It is implemented like this (simplified):
|
||||
|
||||
```cpp
|
||||
template <typename T>
|
||||
struct adl_serializer {
|
||||
static void to_json(json& j, const T& value) {
|
||||
// calls the "to_json" method in T's namespace
|
||||
}
|
||||
|
||||
static void from_json(const json& j, T& value) {
|
||||
// same thing, but with the "from_json" method
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
This serializer works fine when you have control over the type's namespace. However, what about `boost::optional`, or `std::filesystem::path` (C++17)? Hijacking the `boost` namespace is pretty bad, and it's illegal to add something other than template specializations to `std`...
|
||||
|
||||
To solve this, you need to add a specialization of `adl_serializer` to the `nlohmann` namespace, here's an example:
|
||||
|
||||
```cpp
|
||||
// partial specialization (full specialization works too)
|
||||
namespace nlohmann {
|
||||
template <typename T>
|
||||
struct adl_serializer<boost::optional<T>> {
|
||||
static void to_json(json& j, const boost::optional<T>& opt) {
|
||||
if (opt == boost::none) {
|
||||
j = nullptr;
|
||||
} else {
|
||||
j = *opt; // this will call adl_serializer<T>::to_json which will
|
||||
// find the free function to_json in T's namespace!
|
||||
}
|
||||
}
|
||||
|
||||
static void from_json(const json& j, boost::optional<T>& opt) {
|
||||
if (j.is_null()) {
|
||||
opt = boost::none;
|
||||
} else {
|
||||
opt = j.get<T>(); // same as above, but with
|
||||
// adl_serializer<T>::from_json
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
#### How can I use `get()` for non-default constructible/non-copyable types?
|
||||
|
||||
There is a way, if your type is [MoveConstructible](http://en.cppreference.com/w/cpp/concept/MoveConstructible). You will need to specialize the `adl_serializer` as well, but with a special `from_json` overload:
|
||||
|
||||
```cpp
|
||||
struct move_only_type {
|
||||
move_only_type() = delete;
|
||||
move_only_type(int ii): i(ii) {}
|
||||
move_only_type(const move_only_type&) = delete;
|
||||
move_only_type(move_only_type&&) = default;
|
||||
|
||||
int i;
|
||||
};
|
||||
|
||||
namespace nlohmann {
|
||||
template <>
|
||||
struct adl_serializer<move_only_type> {
|
||||
// note: the return type is no longer 'void', and the method only takes
|
||||
// one argument
|
||||
static move_only_type from_json(const json& j) {
|
||||
return {j.get<int>()};
|
||||
}
|
||||
|
||||
// Here's the catch! You must provide a to_json method! Otherwise you
|
||||
// will not be able to convert move_only_type to json, since you fully
|
||||
// specialized adl_serializer on that type
|
||||
static void to_json(json& j, move_only_type t) {
|
||||
j = t.i;
|
||||
}
|
||||
};
|
||||
}
|
||||
```
|
||||
|
||||
#### Can I write my own serializer? (Advanced use)
|
||||
|
||||
Yes. You might want to take a look at [`unit-udt.cpp`](https://github.com/nlohmann/json/blob/develop/test/src/unit-udt.cpp) in the test suite, to see a few examples.
|
||||
|
||||
If you write your own serializer, you'll need to do a few things:
|
||||
|
||||
* use a different `basic_json` alias than `nlohmann::json` (the last template parameter of `basic_json` is the `JSONSerializer`)
|
||||
* use your `basic_json` alias (or a template parameter) in all your `to_json`/`from_json` methods
|
||||
* use `nlohmann::to_json` and `nlohmann::from_json` when you need ADL
|
||||
|
||||
Here is an example, without simplifications, that only accepts types with a size <= 32, and uses ADL.
|
||||
|
||||
```cpp
|
||||
// You should use void as a second template argument
|
||||
// if you don't need compile-time checks on T
|
||||
template<typename T, typename SFINAE = typename std::enable_if<sizeof(T) <= 32>::type>
|
||||
struct less_than_32_serializer {
|
||||
template <typename BasicJsonType>
|
||||
static void to_json(BasicJsonType& j, T value) {
|
||||
// we want to use ADL, and call the correct to_json overload
|
||||
using nlohmann::to_json; // this method is called by adl_serializer,
|
||||
// this is where the magic happens
|
||||
to_json(j, value);
|
||||
}
|
||||
|
||||
template <typename BasicJsonType>
|
||||
static void from_json(const BasicJsonType& j, T& value) {
|
||||
// same thing here
|
||||
using nlohmann::from_json;
|
||||
from_json(j, value);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
Be **very** careful when reimplementing your serializer, you can stack overflow if you don't pay attention:
|
||||
|
||||
```cpp
|
||||
template <typename T, void>
|
||||
struct bad_serializer
|
||||
{
|
||||
template <typename BasicJsonType>
|
||||
static void to_json(BasicJsonType& j, const T& value) {
|
||||
// this calls BasicJsonType::json_serializer<T>::to_json(j, value);
|
||||
// if BasicJsonType::json_serializer == bad_serializer ... oops!
|
||||
j = value;
|
||||
}
|
||||
|
||||
template <typename BasicJsonType>
|
||||
static void to_json(const BasicJsonType& j, T& value) {
|
||||
// this calls BasicJsonType::json_serializer<T>::from_json(j, value);
|
||||
// if BasicJsonType::json_serializer == bad_serializer ... oops!
|
||||
value = j.template get<T>(); // oops!
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Binary formats (CBOR and MessagePack)
|
||||
|
||||
Though JSON is a ubiquitous data format, it is not a very compact format suitable for data exchange, for instance over a network. Hence, the library supports [CBOR](http://cbor.io) (Concise Binary Object Representation) and [MessagePack](http://msgpack.org) to efficiently encode JSON values to byte vectors and to decode such vectors.
|
||||
|
||||
```cpp
|
||||
// create a JSON value
|
||||
json j = R"({"compact": true, "schema": 0})"_json;
|
||||
|
||||
// serialize to CBOR
|
||||
std::vector<std::uint8_t> v_cbor = json::to_cbor(j);
|
||||
|
||||
// 0xa2, 0x67, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0xf5, 0x66, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x00
|
||||
|
||||
// roundtrip
|
||||
json j_from_cbor = json::from_cbor(v_cbor);
|
||||
|
||||
// serialize to MessagePack
|
||||
std::vector<std::uint8_t> v_msgpack = json::to_msgpack(j);
|
||||
|
||||
// 0x82, 0xa7, 0x63, 0x6f, 0x6d, 0x70, 0x61, 0x63, 0x74, 0xc3, 0xa6, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x00
|
||||
|
||||
// roundtrip
|
||||
json j_from_msgpack = json::from_msgpack(v_msgpack);
|
||||
```
|
||||
|
||||
|
||||
## Supported compilers
|
||||
|
||||
@@ -391,6 +707,7 @@ Though it's 2016 already, the support for C++11 is still a bit sparse. Currently
|
||||
- GCC 4.9 - 6.0 (and possibly later)
|
||||
- Clang 3.4 - 3.9 (and possibly later)
|
||||
- Microsoft Visual C++ 2015 / Build Tools 14.0.25123.0 (and possibly later)
|
||||
- Microsoft Visual C++ 2017 / Build Tools 15.1.548.43366 (and possibly later)
|
||||
|
||||
I would be happy to learn about other compilers/versions.
|
||||
|
||||
@@ -423,16 +740,14 @@ The following compilers are currently used in continuous integration at [Travis]
|
||||
| Clang 3.7.1 | Ubuntu 14.04.4 LTS | clang version 3.7.1 (tags/RELEASE_371/final) |
|
||||
| Clang 3.8.0 | Ubuntu 14.04.4 LTS | clang version 3.8.0 (tags/RELEASE_380/final) |
|
||||
| Clang 3.8.1 | Ubuntu 14.04.4 LTS | clang version 3.8.1 (tags/RELEASE_381/final) |
|
||||
| Clang Xcode 6.1 | Darwin Kernel Version 13.4.0 (OSX 10.9.5) | Apple LLVM version 6.0 (clang-600.0.54) (based on LLVM 3.5svn) |
|
||||
| Clang Xcode 6.2 | Darwin Kernel Version 13.4.0 (OSX 10.9.5) | Apple LLVM version 6.0 (clang-600.0.57) (based on LLVM 3.5svn) |
|
||||
| Clang Xcode 6.3 | Darwin Kernel Version 14.3.0 (OSX 10.10.3) | Apple LLVM version 6.1.0 (clang-602.0.49) (based on LLVM 3.6.0svn) |
|
||||
| Clang Xcode 6.4 | Darwin Kernel Version 14.3.0 (OSX 10.10.3) | Apple LLVM version 6.1.0 (clang-602.0.53) (based on LLVM 3.6.0svn) |
|
||||
| Clang Xcode 7.1 | Darwin Kernel Version 14.5.0 (OSX 10.10.5) | Apple LLVM version 7.0.0 (clang-700.1.76) |
|
||||
| Clang Xcode 7.2 | Darwin Kernel Version 15.0.0 (OSX 10.10.5) | Apple LLVM version 7.0.2 (clang-700.1.81) |
|
||||
| Clang Xcode 7.3 | Darwin Kernel Version 15.0.0 (OSX 10.10.5) | Apple LLVM version 7.3.0 (clang-703.0.29) |
|
||||
| Clang Xcode 8.0 | Darwin Kernel Version 15.6.0 (OSX 10.11.6) | Apple LLVM version 8.0.0 (clang-800.0.38) |
|
||||
| Clang Xcode 8.0 | Darwin Kernel Version 15.6.0 | Apple LLVM version 8.0.0 (clang-800.0.38) |
|
||||
| Clang Xcode 8.1 | Darwin Kernel Version 16.1.0 (macOS 10.12.1) | Apple LLVM version 8.0.0 (clang-800.0.42.1) |
|
||||
| Clang Xcode 8.2 | Darwin Kernel Version 16.1.0 (macOS 10.12.1) | Apple LLVM version 8.0.0 (clang-800.0.42.1) |
|
||||
| Clang Xcode 8.3 | Darwin Kernel Version 16.5.0 (macOS 10.12.4) | Apple LLVM version 8.1.0 (clang-802.0.38) |
|
||||
| Visual Studio 14 2015 | Windows Server 2012 R2 (x64) | Microsoft (R) Build Engine version 14.0.25123.0 |
|
||||
|
||||
| Visual Studio 2017 | Windows Server 2016 | Microsoft (R) Build Engine version 15.1.548.43366 |
|
||||
|
||||
## License
|
||||
|
||||
@@ -440,7 +755,7 @@ The following compilers are currently used in continuous integration at [Travis]
|
||||
|
||||
The class is licensed under the [MIT License](http://opensource.org/licenses/MIT):
|
||||
|
||||
Copyright © 2013-2016 [Niels Lohmann](http://nlohmann.me)
|
||||
Copyright © 2013-2017 [Niels Lohmann](http://nlohmann.me)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
@@ -465,7 +780,7 @@ I deeply appreciate the help of the following people.
|
||||
- [Eric Cornelius](https://github.com/EricMCornelius) pointed out a bug in the handling with NaN and infinity values. He also improved the performance of the string escaping.
|
||||
- [易思龙](https://github.com/likebeta) implemented a conversion from anonymous enums.
|
||||
- [kepkin](https://github.com/kepkin) patiently pushed forward the support for Microsoft Visual studio.
|
||||
- [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements.
|
||||
- [gregmarr](https://github.com/gregmarr) simplified the implementation of reverse iterators and helped with numerous hints and improvements. In particular, he pushed forward the implementation of user-defined types.
|
||||
- [Caio Luppi](https://github.com/caiovlp) fixed a bug in the Unicode handling.
|
||||
- [dariomt](https://github.com/dariomt) fixed some typos in the examples.
|
||||
- [Daniel Frey](https://github.com/d-frey) cleaned up some pointers and implemented exception-safe memory allocation.
|
||||
@@ -493,14 +808,70 @@ I deeply appreciate the help of the following people.
|
||||
- [duncanwerner](https://github.com/duncanwerner) found a really embarrassing performance regression in the 2.0.0 release.
|
||||
- [Damien](https://github.com/dtoma) fixed one of the last conversion warnings.
|
||||
- [Thomas Braun](https://github.com/t-b) fixed a warning in a test case.
|
||||
- [Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290).
|
||||
- [Théo DELRIEU](https://github.com/theodelrieu) patiently and constructively oversaw the long way toward [iterator-range parsing](https://github.com/nlohmann/json/issues/290). He also implemented the magic behind the serialization/deserialization of user-defined types.
|
||||
- [Stefan](https://github.com/5tefan) fixed a minor issue in the documentation.
|
||||
- [Vasil Dimov](https://github.com/vasild) fixed the documentation regarding conversions from `std::multiset`.
|
||||
- [ChristophJud](https://github.com/ChristophJud) overworked the CMake files to ease project inclusion.
|
||||
- [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable.
|
||||
- [Vladimir Petrigo](https://github.com/vpetrigo) made a SFINAE hack more readable and added Visual Studio 17 to the build matrix.
|
||||
- [Denis Andrejew](https://github.com/seeekr) fixed a grammar issue in the README file.
|
||||
- [Pierre-Antoine Lacaze](https://github.com/palacaze) found a subtle bug in the `dump()` function.
|
||||
- [TurpentineDistillery](https://github.com/TurpentineDistillery) pointed to [`std::locale::classic()`](http://en.cppreference.com/w/cpp/locale/locale/classic) to avoid too much locale joggling, found some nice performance improvements in the parser, improved the benchmarking code, and realized locale-independent number parsing and printing.
|
||||
- [cgzones](https://github.com/cgzones) had an idea how to fix the Coverity scan.
|
||||
- [Jared Grubb](https://github.com/jaredgrubb) silenced a nasty documentation warning.
|
||||
- [Yixin Zhang](https://github.com/qwename) fixed an integer overflow check.
|
||||
- [Bosswestfalen](https://github.com/Bosswestfalen) merged two iterator classes into a smaller one.
|
||||
- [Daniel599](https://github.com/Daniel599) helped to get Travis execute the tests with Clang's sanitizers.
|
||||
- [Jonathan Lee](https://github.com/vjon) fixed an example in the README file.
|
||||
- [gnzlbg](https://github.com/gnzlbg) supported the implementation of user-defined types.
|
||||
- [Alexej Harm](https://github.com/qis) helped to get the user-defined types working with Visual Studio.
|
||||
- [Jared Grubb](https://github.com/jaredgrubb) supported the implementation of user-defined types.
|
||||
- [EnricoBilla](https://github.com/EnricoBilla) noted a typo in an example.
|
||||
- [Martin Hořeňovský](https://github.com/horenmar) found a way for a 2x speedup for the compilation time of the test suite.
|
||||
- [ukhegg](https://github.com/ukhegg) found proposed an improvement for the examples section.
|
||||
- [rswanson-ihi](https://github.com/rswanson-ihi) noted a typo in the README.
|
||||
- [Mihai Stan](https://github.com/stanmihai4) fixed a bug in the comparison with `nullptr`s.
|
||||
- [Tushar Maheshwari](https://github.com/tusharpm) added [cotire](https://github.com/sakra/cotire) support to speed up the compilation.
|
||||
- [TedLyngmo](https://github.com/TedLyngmo) noted a typo in the README, removed unnecessary bit arithmetic, and fixed some `-Weffc++` warnings.
|
||||
- [Krzysztof Woś](https://github.com/krzysztofwos) made exceptions more visible.
|
||||
- [ftillier](https://github.com/ftillier) fixed a compiler warning.
|
||||
- [tinloaf](https://github.com/tinloaf) made sure all pushed warnings are properly popped.
|
||||
- [Fytch](https://github.com/Fytch) found a bug in the documentation.
|
||||
|
||||
Thanks a lot for helping out!
|
||||
Thanks a lot for helping out! Please [let me know](mailto:mail@nlohmann.me) if I forgot someone.
|
||||
|
||||
|
||||
## Used third-party tools
|
||||
|
||||
The library itself contains of a single header file licensed under the MIT license. However, it is built, tested, documented, and whatnot using a lot of third-party tools and services. Thanks a lot!
|
||||
|
||||
- [**American fuzzy lop**](http://lcamtuf.coredump.cx/afl/) for fuzz testing
|
||||
- [**AppVeyor**](https://www.appveyor.com) for [continuous integration](https://ci.appveyor.com/project/nlohmann/json) on Windows
|
||||
- [**Artistic Style**](http://astyle.sourceforge.net) for automatic source code identation
|
||||
- [**benchpress**](https://github.com/sbs-ableton/benchpress) to benchmark the code
|
||||
- [**Catch**](https://github.com/philsquared/Catch) for the unit tests
|
||||
- [**Clang**](http://clang.llvm.org) for compilation with code sanitizers
|
||||
- [**Cmake**](https://cmake.org) for build automation
|
||||
- [**Codacity**](https://www.codacy.com) for further [code analysis](https://www.codacy.com/app/nlohmann/json)
|
||||
- [**cotire**](https://github.com/sakra/cotire) to speed of compilation
|
||||
- [**Coveralls**](https://coveralls.io) to measure [code coverage](https://coveralls.io/github/nlohmann/json)
|
||||
- [**Coverity Scan**](https://scan.coverity.com) for [static analysis](https://scan.coverity.com/projects/nlohmann-json)
|
||||
- [**cppcheck**](http://cppcheck.sourceforge.net) for static analysis
|
||||
- [**cxxopts**](https://github.com/jarro2783/cxxopts) to let benchpress parse command-line parameters
|
||||
- [**Doxygen**](http://www.stack.nl/~dimitri/doxygen/) to generate [documentation](https://nlohmann.github.io/json/)
|
||||
- [**git-update-ghpages**](https://github.com/rstacruz/git-update-ghpages) to upload the documentation to gh-pages
|
||||
- [**Github Changelog Generator**](https://github.com/skywinder/github-changelog-generator) to generate the [ChangeLog](https://github.com/nlohmann/json/blob/develop/ChangeLog.md)
|
||||
- [**libFuzzer**](http://llvm.org/docs/LibFuzzer.html) to implement fuzz testing for OSS-Fuzz
|
||||
- [**OSS-Fuzz**](https://github.com/google/oss-fuzz) for continuous fuzz testing of the library
|
||||
- [**re2c**](http://re2c.org) to generate an automaton for the lexical analysis
|
||||
- [**send_to_wandbox**](https://github.com/nlohmann/json/blob/develop/doc/scripts/send_to_wandbox.py) to send code examples to [Wandbox](http://melpon.org/wandbox)
|
||||
- [**Travis**](https://travis-ci.org) for [continuous integration](https://travis-ci.org/nlohmann/json) on Linux and macOS
|
||||
- [**Valgrind**](http://valgrind.org) to check for correct memory management
|
||||
- [**Wandbox**](http://melpon.org/wandbox) for [online examples](http://melpon.org/wandbox/permlink/4NEU6ZZMoM9lpIex)
|
||||
|
||||
|
||||
## Projects using JSON for Modern C++
|
||||
|
||||
The library is currently used in Apple macOS Sierra and iOS 10. I am not sure what they are using the library for, but I am happy that it runs on so many devices.
|
||||
|
||||
|
||||
## Notes
|
||||
@@ -512,6 +883,10 @@ Thanks a lot for helping out!
|
||||
- Other encodings such as Latin-1, UTF-16, or UTF-32 are not supported and will yield parse errors.
|
||||
- [Unicode noncharacters](http://www.unicode.org/faq/private_use.html#nonchar1) will not be replaced by the library.
|
||||
- Invalid surrogates (e.g., incomplete pairs such as `\uDEAD`) will yield parse errors.
|
||||
- The strings stored in the library are UTF-8 encoded. When using the default string type (`std::string`), note that its length/size functions return the number of stored bytes rather than the number of characters or glyphs.
|
||||
- The code can be compiled without C++ **runtime type identification** features; that is, you can use the `-fno-rtti` compiler flag.
|
||||
- **Exceptions** are used widely within the library. They can, however, be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `JSON_NOEXCEPTION`. In this case, exceptions are replaced by an `abort()` call.
|
||||
- By default, the library does not preserve the **insertion order of object elements**. This is standards-compliant, as the [JSON standard](https://tools.ietf.org/html/rfc7159.html) defines objects as "an unordered collection of zero or more name/value pairs". If you do want to preserve the insertion order, you can specialize the object type with containers like [`tsl::ordered_map`](https://github.com/Tessil/ordered-map) or [`nlohmann::fifo_map`](https://github.com/nlohmann/fifo_map).
|
||||
|
||||
|
||||
## Execute unit tests
|
||||
@@ -519,10 +894,11 @@ Thanks a lot for helping out!
|
||||
To compile and run the tests, you need to execute
|
||||
|
||||
```sh
|
||||
$ make check
|
||||
$ make json_unit -Ctest
|
||||
$ ./test/json_unit "*"
|
||||
|
||||
===============================================================================
|
||||
All tests passed (8905491 assertions in 36 test cases)
|
||||
All tests passed (11203022 assertions in 48 test cases)
|
||||
```
|
||||
|
||||
Alternatively, you can use [CMake](https://cmake.org) and run
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
6
zto/ext/x64-salsa2012-asm/README.md
Normal file
6
zto/ext/x64-salsa2012-asm/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
Blazingly fast X64 ASM implementation of Salsa20/12
|
||||
======
|
||||
|
||||
This is ripped from the [cnacl](https://github.com/cjdelisle/cnacl) source. The actual code is by Danial J. Bernstein and is in the public domain.
|
||||
|
||||
This is included on Linux and Mac 64-bit builds and is significantly faster than the SSE intrinsics or C versions. It's used for packet encode/decode only since its use differs a bit from the regular Salsa20 C++ class. Specifically it lacks the ability to be called on multiple blocks, preferring instead to take a key and a single stream to encrypt and that's it.
|
||||
16
zto/ext/x64-salsa2012-asm/salsa2012.h
Normal file
16
zto/ext/x64-salsa2012-asm/salsa2012.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#ifndef ZT_X64_SALSA2012_ASM
|
||||
#define ZT_X64_SALSA2012_ASM
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Generates Salsa20/12 key stream
|
||||
// output, outlen, nonce, key (256-bit / 32-byte)
|
||||
extern int zt_salsa2012_amd64_xmm6(unsigned char *, unsigned long long, const unsigned char *, const unsigned char *);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
4488
zto/ext/x64-salsa2012-asm/salsa2012.s
Normal file
4488
zto/ext/x64-salsa2012-asm/salsa2012.s
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
# This requires GNU make, which is typically "gmake" on BSD systems
|
||||
|
||||
INCLUDES=
|
||||
DEFS=
|
||||
LIBS=
|
||||
@@ -28,12 +30,14 @@ endif
|
||||
|
||||
# Determine system build architecture from compiler target
|
||||
CC_MACH=$(shell $(CC) -dumpmachine | cut -d '-' -f 1)
|
||||
ZT_ARCHITECTURE=0
|
||||
ZT_ARCHITECTURE=999
|
||||
ifeq ($(CC_MACH),x86_64)
|
||||
ZT_ARCHITECTURE=2
|
||||
ZT_USE_X64_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),amd64)
|
||||
ZT_ARCHITECTURE=2
|
||||
ZT_USE_X64_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),i386)
|
||||
ZT_ARCHITECTURE=1
|
||||
@@ -43,16 +47,84 @@ ifeq ($(CC_MACH),i686)
|
||||
endif
|
||||
ifeq ($(CC_MACH),arm)
|
||||
ZT_ARCHITECTURE=3
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
ZT_USE_ARM32_NEON_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),armel)
|
||||
ZT_ARCHITECTURE=3
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
ZT_USE_ARM32_NEON_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),armhf)
|
||||
ZT_ARCHITECTURE=3
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
ZT_USE_ARM32_NEON_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),armv6)
|
||||
ZT_ARCHITECTURE=3
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
ZT_USE_ARM32_NEON_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),armv6zk)
|
||||
ZT_ARCHITECTURE=3
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
ZT_USE_ARM32_NEON_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),armv6kz)
|
||||
ZT_ARCHITECTURE=3
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
ZT_USE_ARM32_NEON_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),armv7)
|
||||
ZT_ARCHITECTURE=3
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
ZT_USE_ARM32_NEON_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),arm64)
|
||||
ZT_ARCHITECTURE=4
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
endif
|
||||
ifeq ($(CC_MACH),aarch64)
|
||||
ZT_ARCHITECTURE=4
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
endif
|
||||
ifeq ($(CC_MACH),mipsel)
|
||||
ZT_ARCHITECTURE=5
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
endif
|
||||
ifeq ($(CC_MACH),mips)
|
||||
ZT_ARCHITECTURE=5
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
endif
|
||||
ifeq ($(CC_MACH),mips64)
|
||||
ZT_ARCHITECTURE=6
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
endif
|
||||
ifeq ($(CC_MACH),mips64el)
|
||||
ZT_ARCHITECTURE=6
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
endif
|
||||
DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\""
|
||||
|
||||
CXXFLAGS+=$(CFLAGS) -fno-rtti -std=c++11 -D_GLIBCXX_USE_C99 -D_GLIBCXX_USE_C99_MATH -D_GLIBCXX_USE_C99_MATH_TR1
|
||||
# Fail if system architecture could not be determined
|
||||
ifeq ($(ZT_ARCHITECTURE),999)
|
||||
ERR=$(error FATAL: architecture could not be determined from $(CC) -dumpmachine: $CC_MACH)
|
||||
.PHONY: err
|
||||
err: ; $(ERR)
|
||||
endif
|
||||
|
||||
# Build faster crypto on some targets
|
||||
ifeq ($(ZT_USE_X64_ASM_SALSA2012),1)
|
||||
override DEFS+=-DZT_USE_X64_ASM_SALSA2012
|
||||
override OBJS+=ext/x64-salsa2012-asm/salsa2012.o
|
||||
endif
|
||||
ifeq ($(ZT_USE_ARM32_NEON_ASM_SALSA2012),1)
|
||||
override DEFS+=-DZT_USE_ARM32_NEON_ASM_SALSA2012
|
||||
override OBJS+=ext/arm32-neon-salsa2012-asm/salsa2012.o
|
||||
endif
|
||||
|
||||
override DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\""
|
||||
|
||||
CXXFLAGS+=$(CFLAGS) -fno-rtti -std=c++11 #-D_GLIBCXX_USE_C99 -D_GLIBCXX_USE_C99_MATH -D_GLIBCXX_USE_C99_MATH_TR1
|
||||
|
||||
all: one
|
||||
|
||||
@@ -67,7 +139,7 @@ selftest: $(OBJS) selftest.o
|
||||
$(STRIP) zerotier-selftest
|
||||
|
||||
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-*
|
||||
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)
|
||||
|
||||
debug: FORCE
|
||||
make -j 4 ZT_DEBUG=1
|
||||
|
||||
@@ -8,7 +8,7 @@ ifeq ($(origin CXX),default)
|
||||
endif
|
||||
|
||||
INCLUDES?=
|
||||
DEFS?=-D_FORTIFY_SOURCE=2
|
||||
DEFS?=
|
||||
LDLIBS?=
|
||||
DESTDIR?=
|
||||
|
||||
@@ -54,15 +54,16 @@ ifeq ($(ZT_RULES_ENGINE_DEBUGGING),1)
|
||||
endif
|
||||
|
||||
ifeq ($(ZT_DEBUG),1)
|
||||
DEFS+=-DZT_TRACE
|
||||
override CFLAGS+=-Wall -g -O -pthread $(INCLUDES) $(DEFS)
|
||||
override CXXFLAGS+=-Wall -g -O -std=c++11 -pthread $(INCLUDES) $(DEFS)
|
||||
override DEFS+=-DZT_TRACE
|
||||
override CFLAGS+=-Wall -g -pthread $(INCLUDES) $(DEFS)
|
||||
override CXXFLAGS+=-Wall -g -std=c++11 -pthread $(INCLUDES) $(DEFS)
|
||||
override LDFLAGS+=
|
||||
STRIP?=echo
|
||||
# The following line enables optimization for the crypto code, since
|
||||
# C25519 in particular is almost UNUSABLE in -O0 even on a 3ghz box!
|
||||
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: CXXFLAGS=-Wall -O2 -g -pthread $(INCLUDES) $(DEFS)
|
||||
else
|
||||
override DEFS+=-D_FORTIFY_SOURCE=2
|
||||
CFLAGS?=-O3 -fstack-protector
|
||||
override CFLAGS+=-Wall -fPIE -pthread $(INCLUDES) -DNDEBUG $(DEFS)
|
||||
CXXFLAGS?=-O3 -fstack-protector
|
||||
@@ -72,6 +73,10 @@ else
|
||||
STRIP+=--strip-all
|
||||
endif
|
||||
|
||||
ifeq ($(ZT_USE_TEST_TAP),1)
|
||||
override DEFS+=-DZT_USE_TEST_TAP
|
||||
endif
|
||||
|
||||
# Uncomment for gprof profile build
|
||||
#CFLAGS=-Wall -g -pg -pthread $(INCLUDES) $(DEFS)
|
||||
#CXXFLAGS=-Wall -g -pg -pthread $(INCLUDES) $(DEFS)
|
||||
@@ -80,52 +85,121 @@ endif
|
||||
|
||||
# Determine system build architecture from compiler target
|
||||
CC_MACH=$(shell $(CC) -dumpmachine | cut -d '-' -f 1)
|
||||
ZT_ARCHITECTURE=0
|
||||
ZT_ARCHITECTURE=999
|
||||
ifeq ($(CC_MACH),x86_64)
|
||||
ZT_ARCHITECTURE=2
|
||||
ZT_USE_X64_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),amd64)
|
||||
ZT_ARCHITECTURE=2
|
||||
ZT_USE_X64_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),i386)
|
||||
ZT_ARCHITECTURE=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),i486)
|
||||
ZT_ARCHITECTURE=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),i586)
|
||||
ZT_ARCHITECTURE=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),i686)
|
||||
ZT_ARCHITECTURE=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),arm)
|
||||
ZT_ARCHITECTURE=3
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
ZT_USE_ARM32_NEON_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),armel)
|
||||
ZT_ARCHITECTURE=3
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
ZT_USE_ARM32_NEON_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),armhf)
|
||||
ZT_ARCHITECTURE=3
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
ZT_USE_ARM32_NEON_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),armv6)
|
||||
ZT_ARCHITECTURE=3
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
ZT_USE_ARM32_NEON_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),armv6zk)
|
||||
ZT_ARCHITECTURE=3
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
ZT_USE_ARM32_NEON_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),armv6kz)
|
||||
ZT_ARCHITECTURE=3
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
ZT_USE_ARM32_NEON_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),armv7)
|
||||
ZT_ARCHITECTURE=3
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
ZT_USE_ARM32_NEON_ASM_SALSA2012=1
|
||||
endif
|
||||
ifeq ($(CC_MACH),arm64)
|
||||
ZT_ARCHITECTURE=4
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
endif
|
||||
ifeq ($(CC_MACH),aarch64)
|
||||
ZT_ARCHITECTURE=4
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
endif
|
||||
DEFS+=-DZT_BUILD_PLATFORM=1 -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\""
|
||||
|
||||
# Define some conservative CPU instruction set flags for arm32 since there's a ton of variation out there
|
||||
ifeq ($(ZT_ARCHITECTURE),3)
|
||||
override CFLAGS+=-march=armv6zk -mcpu=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp
|
||||
override CXXFLAGS+=-march=armv6zk -mcpu=arm1176jzf-s -mfloat-abi=hard -mfpu=vfp
|
||||
ifeq ($(CC_MACH),mipsel)
|
||||
ZT_ARCHITECTURE=5
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
endif
|
||||
ifeq ($(CC_MACH),mips)
|
||||
ZT_ARCHITECTURE=5
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
endif
|
||||
ifeq ($(CC_MACH),mips64)
|
||||
ZT_ARCHITECTURE=6
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
endif
|
||||
ifeq ($(CC_MACH),mips64el)
|
||||
ZT_ARCHITECTURE=6
|
||||
override DEFS+=-DZT_NO_TYPE_PUNNING
|
||||
endif
|
||||
|
||||
# Define this to build a static binary, which is needed to make this runnable on a few ancient Linux distros
|
||||
# Fail if system architecture could not be determined
|
||||
ifeq ($(ZT_ARCHITECTURE),999)
|
||||
ERR=$(error FATAL: architecture could not be determined from $(CC) -dumpmachine: $CC_MACH)
|
||||
.PHONY: err
|
||||
err: ; $(ERR)
|
||||
endif
|
||||
|
||||
# Disable software updates by default on Linux since that is normally done with package management
|
||||
override DEFS+=-DZT_BUILD_PLATFORM=1 -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\""
|
||||
|
||||
# Static builds, which are currently done for a number of Linux targets
|
||||
ifeq ($(ZT_STATIC),1)
|
||||
override LDFLAGS+=-static
|
||||
ifeq ($(ZT_ARCHITECTURE),3)
|
||||
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
|
||||
override CXXFLAGS+=-march=armv5te -mfloat-abi=soft -msoft-float -mno-unaligned-access -marm
|
||||
ZT_USE_ARM32_NEON_ASM_SALSA2012=0
|
||||
else
|
||||
override CFLAGS+=-march=armv6zk -mcpu=arm1176jzf-s -mfpu=vfp -mfloat-abi=hard -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
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# Build faster crypto on some targets
|
||||
ifeq ($(ZT_USE_X64_ASM_SALSA2012),1)
|
||||
override DEFS+=-DZT_USE_X64_ASM_SALSA2012
|
||||
override OBJS+=ext/x64-salsa2012-asm/salsa2012.o
|
||||
endif
|
||||
ifeq ($(ZT_USE_ARM32_NEON_ASM_SALSA2012),1)
|
||||
override DEFS+=-DZT_USE_ARM32_NEON_ASM_SALSA2012
|
||||
override OBJS+=ext/arm32-neon-salsa2012-asm/salsa2012.o
|
||||
endif
|
||||
|
||||
all: one
|
||||
|
||||
@@ -37,6 +37,10 @@ ifeq ($(ZT_ENABLE_CLUSTER),1)
|
||||
DEFS+=-DZT_ENABLE_CLUSTER
|
||||
endif
|
||||
|
||||
# Use fast ASM Salsa20/12 for x64 processors
|
||||
DEFS+=-DZT_USE_X64_ASM_SALSA2012
|
||||
OBJS+=ext/x64-salsa2012-asm/salsa2012.o
|
||||
|
||||
# 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
|
||||
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
|
||||
@@ -59,6 +63,9 @@ CXXFLAGS=$(CFLAGS) -std=c++11 -stdlib=libc++
|
||||
|
||||
all: one macui
|
||||
|
||||
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
|
||||
$(CXX) $(CXXFLAGS) -o zerotier-one $(OBJS) service/OneService.o one.o $(LIBS)
|
||||
$(STRIP) zerotier-one
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_ADDRESS_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_ARRAY_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_ATOMICCOUNTER_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_BUFFER_HPP
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
// Code taken from NaCl by D. J. Bernstein and others
|
||||
|
||||
/*
|
||||
Matthew Dempsky
|
||||
Public domain.
|
||||
@@ -7,7 +5,7 @@ Derived from public domain code by D. J. Bernstein.
|
||||
*/
|
||||
|
||||
// Modified very slightly for ZeroTier One by Adam Ierymenko
|
||||
// (no functional changes)
|
||||
// This code remains in the public domain.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_C25519_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include "Capability.hpp"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_CAPABILITY_HPP
|
||||
@@ -24,6 +32,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Credential.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "C25519.hpp"
|
||||
#include "Utils.hpp"
|
||||
@@ -58,9 +67,11 @@ class RuntimeEnvironment;
|
||||
* handed off between nodes. Limited transferrability of capabilities is
|
||||
* a feature of true capability based security.
|
||||
*/
|
||||
class Capability
|
||||
class Capability : public Credential
|
||||
{
|
||||
public:
|
||||
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_CAPABILITY; }
|
||||
|
||||
Capability()
|
||||
{
|
||||
memset(this,0,sizeof(Capability));
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include "CertificateOfMembership.hpp"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_CERTIFICATEOFMEMBERSHIP_HPP
|
||||
@@ -27,6 +35,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Credential.hpp"
|
||||
#include "Buffer.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "C25519.hpp"
|
||||
@@ -68,9 +77,11 @@ class RuntimeEnvironment;
|
||||
* This is a memcpy()'able structure and is safe (in a crash sense) to modify
|
||||
* without locks.
|
||||
*/
|
||||
class CertificateOfMembership
|
||||
class CertificateOfMembership : public Credential
|
||||
{
|
||||
public:
|
||||
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COM; }
|
||||
|
||||
/**
|
||||
* Reserved qualifier IDs
|
||||
*
|
||||
@@ -155,18 +166,23 @@ public:
|
||||
/**
|
||||
* @return True if there's something here
|
||||
*/
|
||||
inline operator bool() const throw() { return (_qualifierCount != 0); }
|
||||
inline operator bool() const { return (_qualifierCount != 0); }
|
||||
|
||||
/**
|
||||
* @return Credential ID, always 0 for COMs
|
||||
*/
|
||||
inline uint32_t id() const { return 0; }
|
||||
|
||||
/**
|
||||
* @return Timestamp for this cert and maximum delta for timestamp
|
||||
*/
|
||||
inline std::pair<uint64_t,uint64_t> timestamp() const
|
||||
inline uint64_t timestamp() const
|
||||
{
|
||||
for(unsigned int i=0;i<_qualifierCount;++i) {
|
||||
if (_qualifiers[i].id == COM_RESERVED_ID_TIMESTAMP)
|
||||
return std::pair<uint64_t,uint64_t>(_qualifiers[i].value,_qualifiers[i].maxDelta);
|
||||
return _qualifiers[i].value;
|
||||
}
|
||||
return std::pair<uint64_t,uint64_t>(0ULL,0ULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -258,12 +274,12 @@ public:
|
||||
/**
|
||||
* @return True if signed
|
||||
*/
|
||||
inline bool isSigned() const throw() { return (_signedBy); }
|
||||
inline bool isSigned() const { return (_signedBy); }
|
||||
|
||||
/**
|
||||
* @return Address that signed this certificate or null address if none
|
||||
*/
|
||||
inline const Address &signedBy() const throw() { return _signedBy; }
|
||||
inline const Address &signedBy() const { return _signedBy; }
|
||||
|
||||
template<unsigned int C>
|
||||
inline void serialize(Buffer<C> &b) const
|
||||
@@ -321,7 +337,6 @@ public:
|
||||
}
|
||||
|
||||
inline bool operator==(const CertificateOfMembership &c) const
|
||||
throw()
|
||||
{
|
||||
if (_signedBy != c._signedBy)
|
||||
return false;
|
||||
@@ -335,7 +350,7 @@ public:
|
||||
}
|
||||
return (_signature == c._signature);
|
||||
}
|
||||
inline bool operator!=(const CertificateOfMembership &c) const throw() { return (!(*this == c)); }
|
||||
inline bool operator!=(const CertificateOfMembership &c) const { return (!(*this == c)); }
|
||||
|
||||
private:
|
||||
struct _Qualifier
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include "CertificateOfOwnership.hpp"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_CERTIFICATEOFOWNERSHIP_HPP
|
||||
@@ -25,6 +33,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Credential.hpp"
|
||||
#include "C25519.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "Identity.hpp"
|
||||
@@ -45,9 +54,11 @@ class RuntimeEnvironment;
|
||||
/**
|
||||
* Certificate indicating ownership of a network identifier
|
||||
*/
|
||||
class CertificateOfOwnership
|
||||
class CertificateOfOwnership : public Credential
|
||||
{
|
||||
public:
|
||||
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COO; }
|
||||
|
||||
enum Thing
|
||||
{
|
||||
THING_NULL = 0,
|
||||
@@ -69,6 +80,8 @@ public:
|
||||
_thingCount(0),
|
||||
_issuedTo(issuedTo)
|
||||
{
|
||||
memset(_thingTypes,0,sizeof(_thingTypes));
|
||||
memset(_thingValues,0,sizeof(_thingValues));
|
||||
}
|
||||
|
||||
inline uint64_t networkId() const { return _networkId; }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,12 +14,21 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_CERTIFICATEOFREPRESENTATION_HPP
|
||||
#define ZT_CERTIFICATEOFREPRESENTATION_HPP
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Credential.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "C25519.hpp"
|
||||
#include "Identity.hpp"
|
||||
@@ -47,14 +56,17 @@ namespace ZeroTier {
|
||||
* roots can shield nodes entirely and p2p connectivity behind them can
|
||||
* be disabled. This will be desirable for a number of use cases.
|
||||
*/
|
||||
class CertificateOfRepresentation
|
||||
class CertificateOfRepresentation : public Credential
|
||||
{
|
||||
public:
|
||||
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_COR; }
|
||||
|
||||
CertificateOfRepresentation()
|
||||
{
|
||||
memset(this,0,sizeof(CertificateOfRepresentation));
|
||||
}
|
||||
|
||||
inline uint32_t id() const { return 0; }
|
||||
inline uint64_t timestamp() const { return _timestamp; }
|
||||
inline const Address &representative(const unsigned int i) const { return _reps[i]; }
|
||||
inline unsigned int repCount() const { return _repCount; }
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifdef ZT_ENABLE_CLUSTER
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_CLUSTER_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_CONSTANTS_HPP
|
||||
@@ -289,7 +297,7 @@
|
||||
#define ZT_PEER_PING_PERIOD 60000
|
||||
|
||||
/**
|
||||
* Paths are considered expired if they have not produced a real packet in this long
|
||||
* Paths are considered expired if they have not sent us a real packet in this long
|
||||
*/
|
||||
#define ZT_PEER_PATH_EXPIRATION ((ZT_PEER_PING_PERIOD * 4) + 3000)
|
||||
|
||||
|
||||
66
zto/node/Credential.hpp
Normal file
66
zto/node/Credential.hpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_CREDENTIAL_HPP
|
||||
#define ZT_CREDENTIAL_HPP
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Constants.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* Base class for credentials
|
||||
*/
|
||||
class Credential
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Do not change type code IDs -- these are used in Revocation objects and elsewhere
|
||||
*/
|
||||
enum Type
|
||||
{
|
||||
CREDENTIAL_TYPE_NULL = 0,
|
||||
CREDENTIAL_TYPE_COM = 1, // CertificateOfMembership
|
||||
CREDENTIAL_TYPE_CAPABILITY = 2,
|
||||
CREDENTIAL_TYPE_TAG = 3,
|
||||
CREDENTIAL_TYPE_COO = 4, // CertificateOfOwnership
|
||||
CREDENTIAL_TYPE_COR = 5, // CertificateOfRepresentation
|
||||
CREDENTIAL_TYPE_REVOCATION = 6
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_DICTIONARY_HPP
|
||||
@@ -91,6 +99,8 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline operator bool() const { return (_d[0] != 0); }
|
||||
|
||||
/**
|
||||
* Load a dictionary from a C-string
|
||||
*
|
||||
@@ -176,12 +186,12 @@ public:
|
||||
j = 0;
|
||||
esc = false;
|
||||
++p;
|
||||
while ((*p != 0)&&(*p != '\r')&&(*p != '\n')) {
|
||||
while ((*p != 0)&&(*p != 13)&&(*p != 10)) {
|
||||
if (esc) {
|
||||
esc = false;
|
||||
switch(*p) {
|
||||
case 'r': dest[j++] = '\r'; break;
|
||||
case 'n': dest[j++] = '\n'; break;
|
||||
case 'r': dest[j++] = 13; break;
|
||||
case 'n': dest[j++] = 10; break;
|
||||
case '0': dest[j++] = (char)0; break;
|
||||
case 'e': dest[j++] = '='; break;
|
||||
default: dest[j++] = *p; break;
|
||||
@@ -207,7 +217,7 @@ public:
|
||||
dest[j] = (char)0;
|
||||
return j;
|
||||
} else {
|
||||
while ((*p)&&(*p != '\r')&&(*p != '\n')) {
|
||||
while ((*p)&&(*p != 13)&&(*p != 10)) {
|
||||
if (++p == eof) {
|
||||
dest[0] = (char)0;
|
||||
return -1;
|
||||
@@ -299,7 +309,7 @@ public:
|
||||
unsigned int j = i;
|
||||
|
||||
if (j > 0) {
|
||||
_d[j++] = '\n';
|
||||
_d[j++] = (char)10;
|
||||
if (j == C) {
|
||||
_d[i] = (char)0;
|
||||
return false;
|
||||
@@ -326,8 +336,8 @@ public:
|
||||
while ( ((vlen < 0)&&(*p)) || (k < vlen) ) {
|
||||
switch(*p) {
|
||||
case 0:
|
||||
case '\r':
|
||||
case '\n':
|
||||
case 13:
|
||||
case 10:
|
||||
case '\\':
|
||||
case '=':
|
||||
_d[j++] = '\\';
|
||||
@@ -337,8 +347,8 @@ public:
|
||||
}
|
||||
switch(*p) {
|
||||
case 0: _d[j++] = '0'; break;
|
||||
case '\r': _d[j++] = 'r'; break;
|
||||
case '\n': _d[j++] = 'n'; break;
|
||||
case 13: _d[j++] = 'r'; break;
|
||||
case 10: _d[j++] = 'n'; break;
|
||||
case '\\': _d[j++] = '\\'; break;
|
||||
case '=': _d[j++] = 'e'; break;
|
||||
}
|
||||
@@ -416,46 +426,6 @@ public:
|
||||
return (this->get(key,tmp,2) >= 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Erase a key from this dictionary
|
||||
*
|
||||
* Use this before add() to ensure that a key is replaced if it might
|
||||
* already be present.
|
||||
*
|
||||
* @param key Key to erase
|
||||
* @return True if key was found and erased
|
||||
*/
|
||||
inline bool erase(const char *key)
|
||||
{
|
||||
char d2[C];
|
||||
char *saveptr = (char *)0;
|
||||
unsigned int d2ptr = 0;
|
||||
bool found = false;
|
||||
for(char *f=Utils::stok(_d,"\r\n",&saveptr);(f);f=Utils::stok((char *)0,"\r\n",&saveptr)) {
|
||||
if (*f) {
|
||||
const char *p = f;
|
||||
const char *k = key;
|
||||
while ((*k)&&(*p)) {
|
||||
if (*k != *p)
|
||||
break;
|
||||
++k;
|
||||
++p;
|
||||
}
|
||||
if (*k) {
|
||||
p = f;
|
||||
while (*p)
|
||||
d2[d2ptr++] = *(p++);
|
||||
d2[d2ptr++] = '\n';
|
||||
} else {
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
d2[d2ptr++] = (char)0;
|
||||
memcpy(_d,d2,d2ptr);
|
||||
return found;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Value of C template parameter
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_HASHTABLE_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -45,7 +53,7 @@ static inline void _computeMemoryHardHash(const void *publicKey,unsigned int pub
|
||||
// ordinary Salsa20 is randomly seekable. This is good for a cipher
|
||||
// but is not what we want for sequential memory-harndess.
|
||||
memset(genmem,0,ZT_IDENTITY_GEN_MEMORY);
|
||||
Salsa20 s20(digest,256,(char *)digest + 32);
|
||||
Salsa20 s20(digest,(char *)digest + 32);
|
||||
s20.crypt20((char *)genmem,(char *)genmem,64);
|
||||
for(unsigned long i=64;i<ZT_IDENTITY_GEN_MEMORY;i+=64) {
|
||||
unsigned long k = i - 64;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_IDENTITY_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -1200,16 +1208,14 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
|
||||
|
||||
switch(addrType) {
|
||||
case 4: {
|
||||
InetAddress a(field(ptr,4),4,at<uint16_t>(ptr + 4));
|
||||
|
||||
bool redundant = false;
|
||||
if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) {
|
||||
peer->setClusterOptimal(a);
|
||||
} else {
|
||||
redundant = peer->hasActivePathTo(now,a);
|
||||
}
|
||||
|
||||
if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) {
|
||||
const InetAddress a(field(ptr,4),4,at<uint16_t>(ptr + 4));
|
||||
if (
|
||||
((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget
|
||||
(!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known
|
||||
(RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path
|
||||
{
|
||||
if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0)
|
||||
peer->setClusterPreferred(a);
|
||||
if (++countPerScope[(int)a.ipScope()][0] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) {
|
||||
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);
|
||||
@@ -1219,16 +1225,14 @@ bool IncomingPacket::_doPUSH_DIRECT_PATHS(const RuntimeEnvironment *RR,void *tPt
|
||||
}
|
||||
} break;
|
||||
case 6: {
|
||||
InetAddress a(field(ptr,16),16,at<uint16_t>(ptr + 16));
|
||||
|
||||
bool redundant = false;
|
||||
if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0) {
|
||||
peer->setClusterOptimal(a);
|
||||
} else {
|
||||
redundant = peer->hasActivePathTo(now,a);
|
||||
}
|
||||
|
||||
if ( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && (!redundant) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) {
|
||||
const InetAddress a(field(ptr,16),16,at<uint16_t>(ptr + 16));
|
||||
if (
|
||||
((flags & ZT_PUSH_DIRECT_PATHS_FLAG_FORGET_PATH) == 0) && // not being told to forget
|
||||
(!( ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) == 0) && (peer->hasActivePathTo(now,a)) )) && // not already known
|
||||
(RR->node->shouldUsePathForZeroTierTraffic(tPtr,peer->address(),_path->localAddress(),a)) ) // should use path
|
||||
{
|
||||
if ((flags & ZT_PUSH_DIRECT_PATHS_FLAG_CLUSTER_REDIRECT) != 0)
|
||||
peer->setClusterPreferred(a);
|
||||
if (++countPerScope[(int)a.ipScope()][1] <= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) {
|
||||
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);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_INCOMINGPACKET_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -302,7 +310,7 @@ InetAddress InetAddress::network() const
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool InetAddress::containsAddress(const InetAddress &addr) const
|
||||
{
|
||||
if (addr.ss_family == ss_family) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_INETADDRESS_HPP
|
||||
@@ -347,16 +355,16 @@ struct InetAddress : public sockaddr_storage
|
||||
*/
|
||||
InetAddress network() const;
|
||||
|
||||
#ifdef ZT_SDK
|
||||
/**
|
||||
#ifdef ZT_SDK
|
||||
/**
|
||||
* Test whether this IPv6 prefix matches the prefix of a given IPv6 address
|
||||
*
|
||||
* @param addr Address to check
|
||||
* @return True if this IPv6 prefix matches the prefix of a given IPv6 address
|
||||
*/
|
||||
bool isEqualPrefix(const InetAddress &addr) const;
|
||||
bool isEqualPrefix(const InetAddress &addr) const;
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* Test whether this IP/netmask contains this address
|
||||
*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_MAC_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
@@ -33,11 +41,13 @@ namespace ZeroTier {
|
||||
Membership::Membership() :
|
||||
_lastUpdatedMulticast(0),
|
||||
_lastPushedCom(0),
|
||||
_comRevocationThreshold(0)
|
||||
_comRevocationThreshold(0),
|
||||
_revocations(4),
|
||||
_remoteTags(4),
|
||||
_remoteCaps(4),
|
||||
_remoteCoos(4)
|
||||
{
|
||||
for(unsigned int i=0;i<ZT_MAX_NETWORK_TAGS;++i) _remoteTags[i] = &(_tagMem[i]);
|
||||
for(unsigned int i=0;i<ZT_MAX_NETWORK_CAPABILITIES;++i) _remoteCaps[i] = &(_capMem[i]);
|
||||
for(unsigned int i=0;i<ZT_MAX_CERTIFICATES_OF_OWNERSHIP;++i) _remoteCoos[i] = &(_cooMem[i]);
|
||||
resetPushState();
|
||||
}
|
||||
|
||||
void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force)
|
||||
@@ -47,18 +57,16 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const u
|
||||
const Capability *sendCap;
|
||||
if (localCapabilityIndex >= 0) {
|
||||
sendCap = &(nconf.capabilities[localCapabilityIndex]);
|
||||
if ( (_localCaps[localCapabilityIndex].id != sendCap->id()) || ((now - _localCaps[localCapabilityIndex].lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) {
|
||||
_localCaps[localCapabilityIndex].lastPushed = now;
|
||||
_localCaps[localCapabilityIndex].id = sendCap->id();
|
||||
} else sendCap = (const Capability *)0;
|
||||
if ( ((now - _localCredLastPushed.cap[localCapabilityIndex]) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) )
|
||||
_localCredLastPushed.cap[localCapabilityIndex] = now;
|
||||
else sendCap = (const Capability *)0;
|
||||
} else sendCap = (const Capability *)0;
|
||||
|
||||
const Tag *sendTags[ZT_MAX_NETWORK_TAGS];
|
||||
unsigned int sendTagCount = 0;
|
||||
for(unsigned int t=0;t<nconf.tagCount;++t) {
|
||||
if ( (_localTags[t].id != nconf.tags[t].id()) || ((now - _localTags[t].lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) {
|
||||
_localTags[t].lastPushed = now;
|
||||
_localTags[t].id = nconf.tags[t].id();
|
||||
if ( ((now - _localCredLastPushed.tag[t]) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) {
|
||||
_localCredLastPushed.tag[t] = now;
|
||||
sendTags[sendTagCount++] = &(nconf.tags[t]);
|
||||
}
|
||||
}
|
||||
@@ -66,9 +74,8 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const u
|
||||
const CertificateOfOwnership *sendCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP];
|
||||
unsigned int sendCooCount = 0;
|
||||
for(unsigned int c=0;c<nconf.certificateOfOwnershipCount;++c) {
|
||||
if ( (_localCoos[c].id != nconf.certificatesOfOwnership[c].id()) || ((now - _localCoos[c].lastPushed) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) {
|
||||
_localCoos[c].lastPushed = now;
|
||||
_localCoos[c].id = nconf.certificatesOfOwnership[c].id();
|
||||
if ( ((now - _localCredLastPushed.coo[c]) >= ZT_CREDENTIAL_PUSH_EVERY) || (force) ) {
|
||||
_localCredLastPushed.coo[c] = now;
|
||||
sendCoos[sendCooCount++] = &(nconf.certificatesOfOwnership[c]);
|
||||
}
|
||||
}
|
||||
@@ -117,21 +124,15 @@ void Membership::pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const u
|
||||
}
|
||||
}
|
||||
|
||||
const Tag *Membership::getTag(const NetworkConfig &nconf,const uint32_t id) const
|
||||
{
|
||||
const _RemoteCredential<Tag> *const *t = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)id,_RemoteCredentialComp<Tag>());
|
||||
return ( ((t != &(_remoteTags[ZT_MAX_NETWORK_CAPABILITIES]))&&((*t)->id == (uint64_t)id)) ? ((((*t)->lastReceived)&&(_isCredentialTimestampValid(nconf,**t))) ? &((*t)->credential) : (const Tag *)0) : (const Tag *)0);
|
||||
}
|
||||
|
||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfMembership &com)
|
||||
{
|
||||
const uint64_t newts = com.timestamp().first;
|
||||
const uint64_t newts = com.timestamp();
|
||||
if (newts <= _comRevocationThreshold) {
|
||||
TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (revoked)",com.issuedTo().toString().c_str(),com.networkId());
|
||||
return ADD_REJECTED;
|
||||
}
|
||||
|
||||
const uint64_t oldts = _com.timestamp().first;
|
||||
const uint64_t oldts = _com.timestamp();
|
||||
if (newts < oldts) {
|
||||
TRACE("addCredential(CertificateOfMembership) for %s on %.16llx REJECTED (older than current)",com.issuedTo().toString().c_str(),com.networkId());
|
||||
return ADD_REJECTED;
|
||||
@@ -154,84 +155,73 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
|
||||
}
|
||||
}
|
||||
|
||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag)
|
||||
// Template out addCredential() for many cred types to avoid copypasta
|
||||
template<typename C>
|
||||
static Membership::AddCredentialResult _addCredImpl(Hashtable<uint32_t,C> &remoteCreds,const Hashtable<uint64_t,uint64_t> &revocations,const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const C &cred)
|
||||
{
|
||||
_RemoteCredential<Tag> *const *htmp = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)tag.id(),_RemoteCredentialComp<Tag>());
|
||||
_RemoteCredential<Tag> *have = ((htmp != &(_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*htmp)->id == (uint64_t)tag.id())) ? *htmp : (_RemoteCredential<Tag> *)0;
|
||||
if (have) {
|
||||
if ( (!_isCredentialTimestampValid(nconf,*have)) || (have->credential.timestamp() > tag.timestamp()) ) {
|
||||
TRACE("addCredential(Tag) for %s on %.16llx REJECTED (revoked or too old)",tag.issuedTo().toString().c_str(),tag.networkId());
|
||||
return ADD_REJECTED;
|
||||
C *rc = remoteCreds.get(cred.id());
|
||||
if (rc) {
|
||||
if (rc->timestamp() > cred.timestamp()) {
|
||||
TRACE("addCredential(type==%d) for %s on %.16llx REJECTED (older than credential we have)",(int)C::credentialType(),cred.issuedTo().toString().c_str(),cred.networkId());
|
||||
return Membership::ADD_REJECTED;
|
||||
}
|
||||
if (have->credential == tag) {
|
||||
TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (redundant)",tag.issuedTo().toString().c_str(),tag.networkId());
|
||||
return ADD_ACCEPTED_REDUNDANT;
|
||||
if (*rc == cred) {
|
||||
//TRACE("addCredential(type==%d) for %s on %.16llx ACCEPTED (redundant)",(int)C::credentialType(),cred.issuedTo().toString().c_str(),cred.networkId());
|
||||
return Membership::ADD_ACCEPTED_REDUNDANT;
|
||||
}
|
||||
}
|
||||
|
||||
switch(tag.verify(RR,tPtr)) {
|
||||
const uint64_t *const rt = revocations.get(Membership::credentialKey(C::credentialType(),cred.id()));
|
||||
if ((rt)&&(*rt >= cred.timestamp())) {
|
||||
TRACE("addCredential(type==%d) for %s on %.16llx REJECTED (timestamp below revocation threshold)",(int)C::credentialType(),cred.issuedTo().toString().c_str(),cred.networkId());
|
||||
return Membership::ADD_REJECTED;
|
||||
}
|
||||
|
||||
switch(cred.verify(RR,tPtr)) {
|
||||
default:
|
||||
TRACE("addCredential(Tag) for %s on %.16llx REJECTED (invalid)",tag.issuedTo().toString().c_str(),tag.networkId());
|
||||
return ADD_REJECTED;
|
||||
TRACE("addCredential(type==%d) for %s on %.16llx REJECTED (invalid)",(int)C::credentialType(),cred.issuedTo().toString().c_str(),cred.networkId());
|
||||
return Membership::ADD_REJECTED;
|
||||
case 0:
|
||||
TRACE("addCredential(Tag) for %s on %.16llx ACCEPTED (new)",tag.issuedTo().toString().c_str(),tag.networkId());
|
||||
if (!have) have = _newTag(tag.id());
|
||||
have->lastReceived = RR->node->now();
|
||||
have->credential = tag;
|
||||
return ADD_ACCEPTED_NEW;
|
||||
TRACE("addCredential(type==%d) for %s on %.16llx ACCEPTED (new)",(int)C::credentialType(),cred.issuedTo().toString().c_str(),cred.networkId());
|
||||
if (!rc)
|
||||
rc = &(remoteCreds[cred.id()]);
|
||||
*rc = cred;
|
||||
return Membership::ADD_ACCEPTED_NEW;
|
||||
case 1:
|
||||
return ADD_DEFERRED_FOR_WHOIS;
|
||||
return Membership::ADD_DEFERRED_FOR_WHOIS;
|
||||
}
|
||||
}
|
||||
|
||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap)
|
||||
{
|
||||
_RemoteCredential<Capability> *const *htmp = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)cap.id(),_RemoteCredentialComp<Capability>());
|
||||
_RemoteCredential<Capability> *have = ((htmp != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*htmp)->id == (uint64_t)cap.id())) ? *htmp : (_RemoteCredential<Capability> *)0;
|
||||
if (have) {
|
||||
if ( (!_isCredentialTimestampValid(nconf,*have)) || (have->credential.timestamp() > cap.timestamp()) ) {
|
||||
TRACE("addCredential(Capability) for %s on %.16llx REJECTED (revoked or too old)",cap.issuedTo().toString().c_str(),cap.networkId());
|
||||
return ADD_REJECTED;
|
||||
}
|
||||
if (have->credential == cap) {
|
||||
TRACE("addCredential(Capability) for %s on %.16llx ACCEPTED (redundant)",cap.issuedTo().toString().c_str(),cap.networkId());
|
||||
return ADD_ACCEPTED_REDUNDANT;
|
||||
}
|
||||
}
|
||||
|
||||
switch(cap.verify(RR,tPtr)) {
|
||||
default:
|
||||
TRACE("addCredential(Capability) for %s on %.16llx REJECTED (invalid)",cap.issuedTo().toString().c_str(),cap.networkId());
|
||||
return ADD_REJECTED;
|
||||
case 0:
|
||||
TRACE("addCredential(Capability) for %s on %.16llx ACCEPTED (new)",cap.issuedTo().toString().c_str(),cap.networkId());
|
||||
if (!have) have = _newCapability(cap.id());
|
||||
have->lastReceived = RR->node->now();
|
||||
have->credential = cap;
|
||||
return ADD_ACCEPTED_NEW;
|
||||
case 1:
|
||||
return ADD_DEFERRED_FOR_WHOIS;
|
||||
}
|
||||
}
|
||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Tag &tag) { return _addCredImpl<Tag>(_remoteTags,_revocations,RR,tPtr,nconf,tag); }
|
||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Capability &cap) { return _addCredImpl<Capability>(_remoteCaps,_revocations,RR,tPtr,nconf,cap); }
|
||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo) { return _addCredImpl<CertificateOfOwnership>(_remoteCoos,_revocations,RR,tPtr,nconf,coo); }
|
||||
|
||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev)
|
||||
{
|
||||
uint64_t *rt;
|
||||
switch(rev.verify(RR,tPtr)) {
|
||||
default:
|
||||
return ADD_REJECTED;
|
||||
case 0: {
|
||||
const uint64_t now = RR->node->now();
|
||||
switch(rev.type()) {
|
||||
const Credential::Type ct = rev.type();
|
||||
switch(ct) {
|
||||
case Credential::CREDENTIAL_TYPE_COM:
|
||||
if (rev.threshold() > _comRevocationThreshold) {
|
||||
_comRevocationThreshold = rev.threshold();
|
||||
return ADD_ACCEPTED_NEW;
|
||||
}
|
||||
return ADD_ACCEPTED_REDUNDANT;
|
||||
case Credential::CREDENTIAL_TYPE_CAPABILITY:
|
||||
case Credential::CREDENTIAL_TYPE_TAG:
|
||||
case Credential::CREDENTIAL_TYPE_COO:
|
||||
rt = &(_revocations[credentialKey(ct,rev.credentialId())]);
|
||||
if (*rt < rev.threshold()) {
|
||||
*rt = rev.threshold();
|
||||
return ADD_ACCEPTED_NEW;
|
||||
}
|
||||
return ADD_ACCEPTED_REDUNDANT;
|
||||
default:
|
||||
return ADD_REJECTED;
|
||||
case Revocation::CREDENTIAL_TYPE_COM:
|
||||
return (_revokeCom(rev) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT);
|
||||
case Revocation::CREDENTIAL_TYPE_CAPABILITY:
|
||||
return (_revokeCap(rev,now) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT);
|
||||
case Revocation::CREDENTIAL_TYPE_TAG:
|
||||
return (_revokeTag(rev,now) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT);
|
||||
case Revocation::CREDENTIAL_TYPE_COO:
|
||||
return (_revokeCoo(rev,now) ? ADD_ACCEPTED_NEW : ADD_ACCEPTED_REDUNDANT);
|
||||
}
|
||||
}
|
||||
case 1:
|
||||
@@ -239,157 +229,11 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
|
||||
}
|
||||
}
|
||||
|
||||
Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo)
|
||||
void Membership::clean(const uint64_t now,const NetworkConfig &nconf)
|
||||
{
|
||||
_RemoteCredential<CertificateOfOwnership> *const *htmp = std::lower_bound(&(_remoteCoos[0]),&(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]),(uint64_t)coo.id(),_RemoteCredentialComp<CertificateOfOwnership>());
|
||||
_RemoteCredential<CertificateOfOwnership> *have = ((htmp != &(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]))&&((*htmp)->id == (uint64_t)coo.id())) ? *htmp : (_RemoteCredential<CertificateOfOwnership> *)0;
|
||||
if (have) {
|
||||
if ( (!_isCredentialTimestampValid(nconf,*have)) || (have->credential.timestamp() > coo.timestamp()) ) {
|
||||
TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx REJECTED (revoked or too old)",coo.issuedTo().toString().c_str(),coo.networkId());
|
||||
return ADD_REJECTED;
|
||||
}
|
||||
if (have->credential == coo) {
|
||||
TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx ACCEPTED (redundant)",coo.issuedTo().toString().c_str(),coo.networkId());
|
||||
return ADD_ACCEPTED_REDUNDANT;
|
||||
}
|
||||
}
|
||||
|
||||
switch(coo.verify(RR,tPtr)) {
|
||||
default:
|
||||
TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx REJECTED (invalid)",coo.issuedTo().toString().c_str(),coo.networkId());
|
||||
return ADD_REJECTED;
|
||||
case 0:
|
||||
TRACE("addCredential(CertificateOfOwnership) for %s on %.16llx ACCEPTED (new)",coo.issuedTo().toString().c_str(),coo.networkId());
|
||||
if (!have) have = _newCoo(coo.id());
|
||||
have->lastReceived = RR->node->now();
|
||||
have->credential = coo;
|
||||
return ADD_ACCEPTED_NEW;
|
||||
case 1:
|
||||
return ADD_DEFERRED_FOR_WHOIS;
|
||||
}
|
||||
}
|
||||
|
||||
Membership::_RemoteCredential<Tag> *Membership::_newTag(const uint64_t id)
|
||||
{
|
||||
_RemoteCredential<Tag> *t = NULL;
|
||||
uint64_t minlr = 0xffffffffffffffffULL;
|
||||
for(unsigned int i=0;i<ZT_MAX_NETWORK_TAGS;++i) {
|
||||
if (_remoteTags[i]->id == ZT_MEMBERSHIP_CRED_ID_UNUSED) {
|
||||
t = _remoteTags[i];
|
||||
break;
|
||||
} else if (_remoteTags[i]->lastReceived <= minlr) {
|
||||
t = _remoteTags[i];
|
||||
minlr = _remoteTags[i]->lastReceived;
|
||||
}
|
||||
}
|
||||
|
||||
if (t) {
|
||||
t->id = id;
|
||||
t->lastReceived = 0;
|
||||
t->revocationThreshold = 0;
|
||||
t->credential = Tag();
|
||||
}
|
||||
|
||||
std::sort(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),_RemoteCredentialComp<Tag>());
|
||||
return t;
|
||||
}
|
||||
|
||||
Membership::_RemoteCredential<Capability> *Membership::_newCapability(const uint64_t id)
|
||||
{
|
||||
_RemoteCredential<Capability> *c = NULL;
|
||||
uint64_t minlr = 0xffffffffffffffffULL;
|
||||
for(unsigned int i=0;i<ZT_MAX_NETWORK_CAPABILITIES;++i) {
|
||||
if (_remoteCaps[i]->id == ZT_MEMBERSHIP_CRED_ID_UNUSED) {
|
||||
c = _remoteCaps[i];
|
||||
break;
|
||||
} else if (_remoteCaps[i]->lastReceived <= minlr) {
|
||||
c = _remoteCaps[i];
|
||||
minlr = _remoteCaps[i]->lastReceived;
|
||||
}
|
||||
}
|
||||
|
||||
if (c) {
|
||||
c->id = id;
|
||||
c->lastReceived = 0;
|
||||
c->revocationThreshold = 0;
|
||||
c->credential = Capability();
|
||||
}
|
||||
|
||||
std::sort(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),_RemoteCredentialComp<Capability>());
|
||||
return c;
|
||||
}
|
||||
|
||||
Membership::_RemoteCredential<CertificateOfOwnership> *Membership::_newCoo(const uint64_t id)
|
||||
{
|
||||
_RemoteCredential<CertificateOfOwnership> *c = NULL;
|
||||
uint64_t minlr = 0xffffffffffffffffULL;
|
||||
for(unsigned int i=0;i<ZT_MAX_CERTIFICATES_OF_OWNERSHIP;++i) {
|
||||
if (_remoteCoos[i]->id == ZT_MEMBERSHIP_CRED_ID_UNUSED) {
|
||||
c = _remoteCoos[i];
|
||||
break;
|
||||
} else if (_remoteCoos[i]->lastReceived <= minlr) {
|
||||
c = _remoteCoos[i];
|
||||
minlr = _remoteCoos[i]->lastReceived;
|
||||
}
|
||||
}
|
||||
|
||||
if (c) {
|
||||
c->id = id;
|
||||
c->lastReceived = 0;
|
||||
c->revocationThreshold = 0;
|
||||
c->credential = CertificateOfOwnership();
|
||||
}
|
||||
|
||||
std::sort(&(_remoteCoos[0]),&(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]),_RemoteCredentialComp<CertificateOfOwnership>());
|
||||
return c;
|
||||
}
|
||||
|
||||
bool Membership::_revokeCom(const Revocation &rev)
|
||||
{
|
||||
if (rev.threshold() > _comRevocationThreshold) {
|
||||
_comRevocationThreshold = rev.threshold();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Membership::_revokeCap(const Revocation &rev,const uint64_t now)
|
||||
{
|
||||
_RemoteCredential<Capability> *const *htmp = std::lower_bound(&(_remoteCaps[0]),&(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]),(uint64_t)rev.credentialId(),_RemoteCredentialComp<Capability>());
|
||||
_RemoteCredential<Capability> *have = ((htmp != &(_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteCredential<Capability> *)0;
|
||||
if (!have) have = _newCapability(rev.credentialId());
|
||||
if (rev.threshold() > have->revocationThreshold) {
|
||||
have->lastReceived = now;
|
||||
have->revocationThreshold = rev.threshold();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Membership::_revokeTag(const Revocation &rev,const uint64_t now)
|
||||
{
|
||||
_RemoteCredential<Tag> *const *htmp = std::lower_bound(&(_remoteTags[0]),&(_remoteTags[ZT_MAX_NETWORK_TAGS]),(uint64_t)rev.credentialId(),_RemoteCredentialComp<Tag>());
|
||||
_RemoteCredential<Tag> *have = ((htmp != &(_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteCredential<Tag> *)0;
|
||||
if (!have) have = _newTag(rev.credentialId());
|
||||
if (rev.threshold() > have->revocationThreshold) {
|
||||
have->lastReceived = now;
|
||||
have->revocationThreshold = rev.threshold();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Membership::_revokeCoo(const Revocation &rev,const uint64_t now)
|
||||
{
|
||||
_RemoteCredential<CertificateOfOwnership> *const *htmp = std::lower_bound(&(_remoteCoos[0]),&(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]),(uint64_t)rev.credentialId(),_RemoteCredentialComp<CertificateOfOwnership>());
|
||||
_RemoteCredential<CertificateOfOwnership> *have = ((htmp != &(_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP]))&&((*htmp)->id == (uint64_t)rev.credentialId())) ? *htmp : (_RemoteCredential<CertificateOfOwnership> *)0;
|
||||
if (!have) have = _newCoo(rev.credentialId());
|
||||
if (rev.threshold() > have->revocationThreshold) {
|
||||
have->lastReceived = now;
|
||||
have->revocationThreshold = rev.threshold();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
_cleanCredImpl<Tag>(nconf,_remoteTags);
|
||||
_cleanCredImpl<Capability>(nconf,_remoteCaps);
|
||||
_cleanCredImpl<CertificateOfOwnership>(nconf,_remoteCoos);
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_MEMBERSHIP_HPP
|
||||
@@ -23,6 +31,8 @@
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "../include/ZeroTierOne.h"
|
||||
#include "Credential.hpp"
|
||||
#include "Hashtable.hpp"
|
||||
#include "CertificateOfMembership.hpp"
|
||||
#include "Capability.hpp"
|
||||
#include "Tag.hpp"
|
||||
@@ -45,35 +55,6 @@ class Network;
|
||||
*/
|
||||
class Membership
|
||||
{
|
||||
private:
|
||||
template<typename T>
|
||||
struct _RemoteCredential
|
||||
{
|
||||
_RemoteCredential() : id(ZT_MEMBERSHIP_CRED_ID_UNUSED),lastReceived(0),revocationThreshold(0) {}
|
||||
uint64_t id;
|
||||
uint64_t lastReceived; // last time we got this credential
|
||||
uint64_t revocationThreshold; // credentials before this time are invalid
|
||||
T credential;
|
||||
inline bool operator<(const _RemoteCredential &c) const { return (id < c.id); }
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct _RemoteCredentialComp
|
||||
{
|
||||
inline bool operator()(const _RemoteCredential<T> *a,const _RemoteCredential<T> *b) const { return (a->id < b->id); }
|
||||
inline bool operator()(const uint64_t a,const _RemoteCredential<T> *b) const { return (a < b->id); }
|
||||
inline bool operator()(const _RemoteCredential<T> *a,const uint64_t b) const { return (a->id < b); }
|
||||
inline bool operator()(const uint64_t a,const uint64_t b) const { return (a < b); }
|
||||
};
|
||||
|
||||
// Used to track push state for network config tags[] and capabilities[] entries
|
||||
struct _LocalCredentialPushState
|
||||
{
|
||||
_LocalCredentialPushState() : lastPushed(0),id(0) {}
|
||||
uint64_t lastPushed; // last time we sent our own copy of this credential
|
||||
uint64_t id;
|
||||
};
|
||||
|
||||
public:
|
||||
enum AddCredentialResult
|
||||
{
|
||||
@@ -83,72 +64,6 @@ public:
|
||||
ADD_DEFERRED_FOR_WHOIS
|
||||
};
|
||||
|
||||
/**
|
||||
* Iterator to scan forward through capabilities in ascending order of ID
|
||||
*/
|
||||
class CapabilityIterator
|
||||
{
|
||||
public:
|
||||
CapabilityIterator(const Membership &m,const NetworkConfig &nconf) :
|
||||
_m(&m),
|
||||
_c(&nconf),
|
||||
_i(&(m._remoteCaps[0])) {}
|
||||
|
||||
inline const Capability *next()
|
||||
{
|
||||
for(;;) {
|
||||
if ((_i != &(_m->_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES]))&&((*_i)->id != ZT_MEMBERSHIP_CRED_ID_UNUSED)) {
|
||||
const Capability *tmp = &((*_i)->credential);
|
||||
if (_m->_isCredentialTimestampValid(*_c,**_i)) {
|
||||
++_i;
|
||||
return tmp;
|
||||
} else ++_i;
|
||||
} else {
|
||||
return (const Capability *)0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const Membership *_m;
|
||||
const NetworkConfig *_c;
|
||||
const _RemoteCredential<Capability> *const *_i;
|
||||
};
|
||||
friend class CapabilityIterator;
|
||||
|
||||
/**
|
||||
* Iterator to scan forward through tags in ascending order of ID
|
||||
*/
|
||||
class TagIterator
|
||||
{
|
||||
public:
|
||||
TagIterator(const Membership &m,const NetworkConfig &nconf) :
|
||||
_m(&m),
|
||||
_c(&nconf),
|
||||
_i(&(m._remoteTags[0])) {}
|
||||
|
||||
inline const Tag *next()
|
||||
{
|
||||
for(;;) {
|
||||
if ((_i != &(_m->_remoteTags[ZT_MAX_NETWORK_TAGS]))&&((*_i)->id != ZT_MEMBERSHIP_CRED_ID_UNUSED)) {
|
||||
const Tag *tmp = &((*_i)->credential);
|
||||
if (_m->_isCredentialTimestampValid(*_c,**_i)) {
|
||||
++_i;
|
||||
return tmp;
|
||||
} else ++_i;
|
||||
} else {
|
||||
return (const Tag *)0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
const Membership *_m;
|
||||
const NetworkConfig *_c;
|
||||
const _RemoteCredential<Tag> *const *_i;
|
||||
};
|
||||
friend class TagIterator;
|
||||
|
||||
Membership();
|
||||
|
||||
/**
|
||||
@@ -168,19 +83,19 @@ public:
|
||||
void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const uint64_t now,const Address &peerAddress,const NetworkConfig &nconf,int localCapabilityIndex,const bool force);
|
||||
|
||||
/**
|
||||
* Check whether we should push MULTICAST_LIKEs to this peer
|
||||
* Check whether we should push MULTICAST_LIKEs to this peer, and update last sent time if true
|
||||
*
|
||||
* @param now Current time
|
||||
* @return True if we should update multicasts
|
||||
*/
|
||||
inline bool shouldLikeMulticasts(const uint64_t now) const { return ((now - _lastUpdatedMulticast) >= ZT_MULTICAST_ANNOUNCE_PERIOD); }
|
||||
|
||||
/**
|
||||
* Set time we last updated multicasts for this peer
|
||||
*
|
||||
* @param now Current time
|
||||
*/
|
||||
inline void likingMulticasts(const uint64_t now) { _lastUpdatedMulticast = now; }
|
||||
inline bool multicastLikeGate(const uint64_t now)
|
||||
{
|
||||
if ((now - _lastUpdatedMulticast) >= ZT_MULTICAST_ANNOUNCE_PERIOD) {
|
||||
_lastUpdatedMulticast = now;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the peer represented by this Membership should be allowed on this network at all
|
||||
@@ -190,10 +105,8 @@ public:
|
||||
*/
|
||||
inline bool isAllowedOnNetwork(const NetworkConfig &nconf) const
|
||||
{
|
||||
if (nconf.isPublic())
|
||||
return true;
|
||||
if (_com.timestamp().first <= _comRevocationThreshold)
|
||||
return false;
|
||||
if (nconf.isPublic()) return true;
|
||||
if (_com.timestamp() <= _comRevocationThreshold) return false;
|
||||
return nconf.com.agreesWith(_com);
|
||||
}
|
||||
|
||||
@@ -208,21 +121,28 @@ public:
|
||||
template<typename T>
|
||||
inline bool hasCertificateOfOwnershipFor(const NetworkConfig &nconf,const T &r) const
|
||||
{
|
||||
for(unsigned int i=0;i<ZT_MAX_CERTIFICATES_OF_OWNERSHIP;++i) {
|
||||
if (_remoteCoos[i]->id == ZT_MEMBERSHIP_CRED_ID_UNUSED)
|
||||
break;
|
||||
if ((_isCredentialTimestampValid(nconf,*_remoteCoos[i]))&&(_remoteCoos[i]->credential.owns(r)))
|
||||
uint32_t *k = (uint32_t *)0;
|
||||
CertificateOfOwnership *v = (CertificateOfOwnership *)0;
|
||||
Hashtable< uint32_t,CertificateOfOwnership >::Iterator i(*(const_cast< Hashtable< uint32_t,CertificateOfOwnership> *>(&_remoteCoos)));
|
||||
while (i.next(k,v)) {
|
||||
if (_isCredentialTimestampValid(nconf,*v)&&(v->owns(r)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a remote member's tag (if we have it)
|
||||
*
|
||||
* @param nconf Network configuration
|
||||
* @param id Tag ID
|
||||
* @return Pointer to tag or NULL if not found
|
||||
*/
|
||||
const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const;
|
||||
inline const Tag *getTag(const NetworkConfig &nconf,const uint32_t id) const
|
||||
{
|
||||
const Tag *const t = _remoteTags.get(id);
|
||||
return (((t)&&(_isCredentialTimestampValid(nconf,*t))) ? t : (Tag *)0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate and add a credential if signature is okay and it's otherwise good
|
||||
@@ -242,29 +162,59 @@ public:
|
||||
/**
|
||||
* Validate and add a credential if signature is okay and it's otherwise good
|
||||
*/
|
||||
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev);
|
||||
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo);
|
||||
|
||||
/**
|
||||
* Validate and add a credential if signature is okay and it's otherwise good
|
||||
*/
|
||||
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const CertificateOfOwnership &coo);
|
||||
AddCredentialResult addCredential(const RuntimeEnvironment *RR,void *tPtr,const NetworkConfig &nconf,const Revocation &rev);
|
||||
|
||||
/**
|
||||
* Clean internal databases of stale entries
|
||||
*
|
||||
* @param now Current time
|
||||
* @param nconf Current network configuration
|
||||
*/
|
||||
void clean(const uint64_t now,const NetworkConfig &nconf);
|
||||
|
||||
/**
|
||||
* Reset last pushed time for local credentials
|
||||
*
|
||||
* This is done when we update our network configuration and our credentials have changed
|
||||
*/
|
||||
inline void resetPushState()
|
||||
{
|
||||
_lastPushedCom = 0;
|
||||
memset(&_localCredLastPushed,0,sizeof(_localCredLastPushed));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a key for the internal use in indexing credentials by type and credential ID
|
||||
*/
|
||||
static uint64_t credentialKey(const Credential::Type &t,const uint32_t i) { return (((uint64_t)t << 32) | (uint64_t)i); }
|
||||
|
||||
private:
|
||||
_RemoteCredential<Tag> *_newTag(const uint64_t id);
|
||||
_RemoteCredential<Capability> *_newCapability(const uint64_t id);
|
||||
_RemoteCredential<CertificateOfOwnership> *_newCoo(const uint64_t id);
|
||||
bool _revokeCom(const Revocation &rev);
|
||||
bool _revokeCap(const Revocation &rev,const uint64_t now);
|
||||
bool _revokeTag(const Revocation &rev,const uint64_t now);
|
||||
bool _revokeCoo(const Revocation &rev,const uint64_t now);
|
||||
template<typename C>
|
||||
inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const C &remoteCredential) const
|
||||
{
|
||||
const uint64_t ts = remoteCredential.timestamp();
|
||||
if (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) {
|
||||
const uint64_t *threshold = _revocations.get(credentialKey(C::credentialType(),remoteCredential.id()));
|
||||
return ((!threshold)||(ts > *threshold));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename C>
|
||||
inline bool _isCredentialTimestampValid(const NetworkConfig &nconf,const _RemoteCredential<C> &remoteCredential) const
|
||||
void _cleanCredImpl(const NetworkConfig &nconf,Hashtable<uint32_t,C> &remoteCreds)
|
||||
{
|
||||
if (!remoteCredential.lastReceived)
|
||||
return false;
|
||||
const uint64_t ts = remoteCredential.credential.timestamp();
|
||||
return ( (((ts >= nconf.timestamp) ? (ts - nconf.timestamp) : (nconf.timestamp - ts)) <= nconf.credentialTimeMaxDelta) && (ts > remoteCredential.revocationThreshold) );
|
||||
uint32_t *k = (uint32_t *)0;
|
||||
C *v = (C *)0;
|
||||
typename Hashtable<uint32_t,C>::Iterator i(remoteCreds);
|
||||
while (i.next(k,v)) {
|
||||
if (!_isCredentialTimestampValid(nconf,*v))
|
||||
remoteCreds.erase(*k);
|
||||
}
|
||||
}
|
||||
|
||||
// Last time we pushed MULTICAST_LIKE(s)
|
||||
@@ -279,20 +229,50 @@ private:
|
||||
// Remote member's latest network COM
|
||||
CertificateOfMembership _com;
|
||||
|
||||
// Sorted (in ascending order of ID) arrays of pointers to remote credentials
|
||||
_RemoteCredential<Tag> *_remoteTags[ZT_MAX_NETWORK_TAGS];
|
||||
_RemoteCredential<Capability> *_remoteCaps[ZT_MAX_NETWORK_CAPABILITIES];
|
||||
_RemoteCredential<CertificateOfOwnership> *_remoteCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP];
|
||||
// Revocations by credentialKey()
|
||||
Hashtable< uint64_t,uint64_t > _revocations;
|
||||
|
||||
// This is the RAM allocated for remote credential cache objects
|
||||
_RemoteCredential<Tag> _tagMem[ZT_MAX_NETWORK_TAGS];
|
||||
_RemoteCredential<Capability> _capMem[ZT_MAX_NETWORK_CAPABILITIES];
|
||||
_RemoteCredential<CertificateOfOwnership> _cooMem[ZT_MAX_CERTIFICATES_OF_OWNERSHIP];
|
||||
// Remote credentials that we have received from this member (and that are valid)
|
||||
Hashtable< uint32_t,Tag > _remoteTags;
|
||||
Hashtable< uint32_t,Capability > _remoteCaps;
|
||||
Hashtable< uint32_t,CertificateOfOwnership > _remoteCoos;
|
||||
|
||||
// Local credential push state tracking
|
||||
_LocalCredentialPushState _localTags[ZT_MAX_NETWORK_TAGS];
|
||||
_LocalCredentialPushState _localCaps[ZT_MAX_NETWORK_CAPABILITIES];
|
||||
_LocalCredentialPushState _localCoos[ZT_MAX_CERTIFICATES_OF_OWNERSHIP];
|
||||
// Time we last pushed our local credentials to this member
|
||||
struct {
|
||||
uint64_t tag[ZT_MAX_NETWORK_TAGS];
|
||||
uint64_t cap[ZT_MAX_NETWORK_CAPABILITIES];
|
||||
uint64_t coo[ZT_MAX_CERTIFICATES_OF_OWNERSHIP];
|
||||
} _localCredLastPushed;
|
||||
|
||||
public:
|
||||
class CapabilityIterator
|
||||
{
|
||||
public:
|
||||
CapabilityIterator(Membership &m,const NetworkConfig &nconf) :
|
||||
_hti(m._remoteCaps),
|
||||
_k((uint32_t *)0),
|
||||
_c((Capability *)0),
|
||||
_m(m),
|
||||
_nconf(nconf)
|
||||
{
|
||||
}
|
||||
|
||||
inline Capability *next()
|
||||
{
|
||||
while (_hti.next(_k,_c)) {
|
||||
if (_m._isCredentialTimestampValid(_nconf,*_c))
|
||||
return _c;
|
||||
}
|
||||
return (Capability *)0;
|
||||
}
|
||||
|
||||
private:
|
||||
Hashtable< uint32_t,Capability >::Iterator _hti;
|
||||
uint32_t *_k;
|
||||
Capability *_c;
|
||||
Membership &_m;
|
||||
const NetworkConfig &_nconf;
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_MULTICASTGROUP_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_MULTICASTER_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_MUTEX_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -534,9 +542,9 @@ static _doZtFilterResult _doZtFilter(
|
||||
}
|
||||
if (inbound) {
|
||||
if (membership) {
|
||||
if ((src)&&(membership->hasCertificateOfOwnershipFor(nconf,src)))
|
||||
if ((src)&&(membership->hasCertificateOfOwnershipFor<InetAddress>(nconf,src)))
|
||||
ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_IP_AUTHENTICATED;
|
||||
if (membership->hasCertificateOfOwnershipFor(nconf,macSource))
|
||||
if (membership->hasCertificateOfOwnershipFor<MAC>(nconf,macSource))
|
||||
ownershipVerificationMask |= ZT_RULE_PACKET_CHARACTERISTICS_SENDER_MAC_AUTHENTICATED;
|
||||
}
|
||||
} else {
|
||||
@@ -729,7 +737,8 @@ Network::~Network()
|
||||
|
||||
char n[128];
|
||||
if (_destroyed) {
|
||||
RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp);
|
||||
// This is done in Node::leave() so we can pass tPtr
|
||||
//RR->node->configureVirtualNetworkPort((void *)0,_id,&_uPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp);
|
||||
Utils::snprintf(n,sizeof(n),"networks.d/%.16llx.conf",_id);
|
||||
RR->node->dataStoreDelete((void *)0,n);
|
||||
} else {
|
||||
@@ -993,6 +1002,9 @@ void Network::multicastUnsubscribe(const MulticastGroup &mg)
|
||||
|
||||
uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer<ZT_PROTO_MAX_PACKET_LENGTH> &chunk,unsigned int ptr)
|
||||
{
|
||||
if (_destroyed)
|
||||
return 0;
|
||||
|
||||
const unsigned int start = ptr;
|
||||
|
||||
ptr += 8; // skip network ID, which is already obviously known
|
||||
@@ -1140,24 +1152,37 @@ uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Add
|
||||
|
||||
int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToDisk)
|
||||
{
|
||||
if (_destroyed)
|
||||
return 0;
|
||||
|
||||
// _lock is NOT locked when this is called
|
||||
try {
|
||||
if ((nconf.issuedTo != RR->identity.address())||(nconf.networkId != _id))
|
||||
return 0;
|
||||
return 0; // invalid config that is not for us or not for this network
|
||||
if (_config == nconf)
|
||||
return 1; // OK config, but duplicate of what we already have
|
||||
|
||||
ZT_VirtualNetworkConfig ctmp;
|
||||
bool oldPortInitialized;
|
||||
{
|
||||
{ // do things that require lock here, but unlock before calling callbacks
|
||||
Mutex::Lock _l(_lock);
|
||||
|
||||
_config = nconf;
|
||||
_lastConfigUpdate = RR->node->now();
|
||||
_netconfFailure = NETCONF_FAILURE_NONE;
|
||||
|
||||
oldPortInitialized = _portInitialized;
|
||||
_portInitialized = true;
|
||||
|
||||
_externalConfig(&ctmp);
|
||||
|
||||
Address *a = (Address *)0;
|
||||
Membership *m = (Membership *)0;
|
||||
Hashtable<Address,Membership>::Iterator i(_memberships);
|
||||
while (i.next(a,m))
|
||||
m->resetPushState();
|
||||
}
|
||||
|
||||
_portError = RR->node->configureVirtualNetworkPort(tPtr,_id,&_uPtr,(oldPortInitialized) ? ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_CONFIG_UPDATE : ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_UP,&ctmp);
|
||||
|
||||
if (saveToDisk) {
|
||||
@@ -1180,6 +1205,9 @@ int Network::setConfiguration(void *tPtr,const NetworkConfig &nconf,bool saveToD
|
||||
|
||||
void Network::requestConfiguration(void *tPtr)
|
||||
{
|
||||
if (_destroyed)
|
||||
return;
|
||||
|
||||
/* ZeroTier addresses can't begin with 0xff, so this is used to mark controllerless
|
||||
* network IDs. Controllerless network IDs only support unicast IPv6 using the 6plane
|
||||
* addressing scheme and have the following format: 0xffSSSSEEEE000000 where SSSS
|
||||
@@ -1299,10 +1327,9 @@ bool Network::gate(void *tPtr,const SharedPtr<Peer> &peer)
|
||||
if ( (_config.isPublic()) || ((m)&&(m->isAllowedOnNetwork(_config))) ) {
|
||||
if (!m)
|
||||
m = &(_membership(peer->address()));
|
||||
if (m->shouldLikeMulticasts(now)) {
|
||||
if (m->multicastLikeGate(now)) {
|
||||
m->pushCredentials(RR,tPtr,now,peer->address(),_config,-1,false);
|
||||
_announceMulticastGroupsTo(tPtr,peer->address(),_allMulticastGroups());
|
||||
m->likingMulticasts(now);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1338,6 +1365,7 @@ void Network::clean()
|
||||
while (i.next(a,m)) {
|
||||
if (!RR->topology->getPeerNoCache(*a))
|
||||
_memberships.erase(*a);
|
||||
else m->clean(now,_config);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1546,8 +1574,7 @@ void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMu
|
||||
}
|
||||
|
||||
// Make sure that all "network anchors" have Membership records so we will
|
||||
// push multicasts to them. Note that _membership() also does this but in a
|
||||
// piecemeal on-demand fashion.
|
||||
// push multicasts to them.
|
||||
const std::vector<Address> anchors(_config.anchors());
|
||||
for(std::vector<Address>::const_iterator a(anchors.begin());a!=anchors.end();++a)
|
||||
_membership(*a);
|
||||
@@ -1559,11 +1586,8 @@ void Network::_sendUpdatesToMembers(void *tPtr,const MulticastGroup *const newMu
|
||||
Hashtable<Address,Membership>::Iterator i(_memberships);
|
||||
while (i.next(a,m)) {
|
||||
m->pushCredentials(RR,tPtr,now,*a,_config,-1,false);
|
||||
if ( ((newMulticastGroup)||(m->shouldLikeMulticasts(now))) && (m->isAllowedOnNetwork(_config)) ) {
|
||||
if (!newMulticastGroup)
|
||||
m->likingMulticasts(now);
|
||||
if ( ( m->multicastLikeGate(now) || (newMulticastGroup) ) && (m->isAllowedOnNetwork(_config)) )
|
||||
_announceMulticastGroupsTo(tPtr,*a,groups);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_NETWORK_HPP
|
||||
@@ -344,9 +352,8 @@ public:
|
||||
/**
|
||||
* Destroy this network
|
||||
*
|
||||
* This causes the network to disable itself, destroy its tap device, and on
|
||||
* delete to delete all trace of itself on disk and remove any persistent tap
|
||||
* device instances. Call this when a network is being removed from the system.
|
||||
* This sets the network to completely remove itself on delete. This also prevents the
|
||||
* call of the normal port shutdown event on delete.
|
||||
*/
|
||||
void destroy();
|
||||
|
||||
@@ -364,7 +371,7 @@ public:
|
||||
/**
|
||||
* @return Externally usable pointer-to-pointer exported via the core API
|
||||
*/
|
||||
inline void **userPtr() throw() { return &_uPtr; }
|
||||
inline void **userPtr() { return &_uPtr; }
|
||||
|
||||
private:
|
||||
ZT_VirtualNetworkStatus _status() const;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_NETWORKCONFIG_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_NETWORKCONFIGMASTER_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@@ -50,7 +58,6 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6
|
||||
_RR(this),
|
||||
RR(&_RR),
|
||||
_uPtr(uptr),
|
||||
_prngStreamPtr(0),
|
||||
_now(now),
|
||||
_lastPingCheck(0),
|
||||
_lastHousekeepingRun(0)
|
||||
@@ -59,19 +66,14 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6
|
||||
throw std::runtime_error("callbacks struct version mismatch");
|
||||
memcpy(&_cb,callbacks,sizeof(ZT_Node_Callbacks));
|
||||
|
||||
Utils::getSecureRandom((void *)_prngState,sizeof(_prngState));
|
||||
|
||||
_online = false;
|
||||
|
||||
memset(_expectingRepliesToBucketPtr,0,sizeof(_expectingRepliesToBucketPtr));
|
||||
memset(_expectingRepliesTo,0,sizeof(_expectingRepliesTo));
|
||||
memset(_lastIdentityVerification,0,sizeof(_lastIdentityVerification));
|
||||
|
||||
// Use Salsa20 alone as a high-quality non-crypto PRNG
|
||||
char foo[32];
|
||||
Utils::getSecureRandom(foo,32);
|
||||
_prng.init(foo,256,foo);
|
||||
memset(_prngStream,0,sizeof(_prngStream));
|
||||
_prng.crypt12(_prngStream,_prngStream,sizeof(_prngStream));
|
||||
|
||||
std::string idtmp(dataStoreGet(tptr,"identity.secret"));
|
||||
if ((!idtmp.length())||(!RR->identity.fromString(idtmp))||(!RR->identity.hasPrivate())) {
|
||||
TRACE("identity.secret not found, generating...");
|
||||
@@ -305,26 +307,35 @@ ZT_ResultCode Node::join(uint64_t nwid,void *uptr,void *tptr)
|
||||
{
|
||||
Mutex::Lock _l(_networks_m);
|
||||
SharedPtr<Network> nw = _network(nwid);
|
||||
if(!nw)
|
||||
_networks.push_back(std::pair< uint64_t,SharedPtr<Network> >(nwid,SharedPtr<Network>(new Network(RR,tptr,nwid,uptr))));
|
||||
std::sort(_networks.begin(),_networks.end()); // will sort by nwid since it's the first in a pair<>
|
||||
if(!nw) {
|
||||
const std::pair< uint64_t,SharedPtr<Network> > nn(nwid,SharedPtr<Network>(new Network(RR,tptr,nwid,uptr)));
|
||||
_networks.insert(std::upper_bound(_networks.begin(),_networks.end(),nn),nn);
|
||||
}
|
||||
return ZT_RESULT_OK;
|
||||
}
|
||||
|
||||
ZT_ResultCode Node::leave(uint64_t nwid,void **uptr,void *tptr)
|
||||
{
|
||||
ZT_VirtualNetworkConfig ctmp;
|
||||
std::vector< std::pair< uint64_t,SharedPtr<Network> > > newn;
|
||||
void **nUserPtr = (void **)0;
|
||||
Mutex::Lock _l(_networks_m);
|
||||
|
||||
for(std::vector< std::pair< uint64_t,SharedPtr<Network> > >::const_iterator n(_networks.begin());n!=_networks.end();++n) {
|
||||
if (n->first != nwid)
|
||||
if (n->first != nwid) {
|
||||
newn.push_back(*n);
|
||||
else {
|
||||
} else {
|
||||
if (uptr)
|
||||
*uptr = n->second->userPtr();
|
||||
*uptr = *n->second->userPtr();
|
||||
n->second->destroy();
|
||||
nUserPtr = n->second->userPtr();
|
||||
}
|
||||
}
|
||||
_networks.swap(newn);
|
||||
|
||||
if (nUserPtr)
|
||||
RR->node->configureVirtualNetworkPort(tptr,nwid,nUserPtr,ZT_VIRTUAL_NETWORK_CONFIG_OPERATION_DESTROY,&ctmp);
|
||||
|
||||
return ZT_RESULT_OK;
|
||||
}
|
||||
|
||||
@@ -398,17 +409,17 @@ ZT_PeerList *Node::peers() const
|
||||
p->latency = pi->second->latency();
|
||||
p->role = RR->topology->role(pi->second->identity().address());
|
||||
|
||||
std::vector< std::pair< SharedPtr<Path>,bool > > paths(pi->second->paths(_now));
|
||||
std::vector< SharedPtr<Path> > paths(pi->second->paths(_now));
|
||||
SharedPtr<Path> bestp(pi->second->getBestPath(_now,false));
|
||||
p->pathCount = 0;
|
||||
for(std::vector< std::pair< SharedPtr<Path>,bool > >::iterator path(paths.begin());path!=paths.end();++path) {
|
||||
memcpy(&(p->paths[p->pathCount].address),&(path->first->address()),sizeof(struct sockaddr_storage));
|
||||
p->paths[p->pathCount].lastSend = path->first->lastOut();
|
||||
p->paths[p->pathCount].lastReceive = path->first->lastIn();
|
||||
p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust(path->first->address());
|
||||
p->paths[p->pathCount].linkQuality = (int)path->first->linkQuality();
|
||||
p->paths[p->pathCount].expired = path->second;
|
||||
p->paths[p->pathCount].preferred = (path->first == bestp) ? 1 : 0;
|
||||
for(std::vector< SharedPtr<Path> >::iterator path(paths.begin());path!=paths.end();++path) {
|
||||
memcpy(&(p->paths[p->pathCount].address),&((*path)->address()),sizeof(struct sockaddr_storage));
|
||||
p->paths[p->pathCount].lastSend = (*path)->lastOut();
|
||||
p->paths[p->pathCount].lastReceive = (*path)->lastIn();
|
||||
p->paths[p->pathCount].trustedPathId = RR->topology->getOutboundPathTrust((*path)->address());
|
||||
p->paths[p->pathCount].linkQuality = (int)(*path)->linkQuality();
|
||||
p->paths[p->pathCount].expired = 0;
|
||||
p->paths[p->pathCount].preferred = ((*path) == bestp) ? 1 : 0;
|
||||
++p->pathCount;
|
||||
}
|
||||
}
|
||||
@@ -487,7 +498,8 @@ int Node::sendUserMessage(void *tptr,uint64_t dest,uint64_t typeId,const void *d
|
||||
void Node::setNetconfMaster(void *networkControllerInstance)
|
||||
{
|
||||
RR->localNetworkController = reinterpret_cast<NetworkController *>(networkControllerInstance);
|
||||
RR->localNetworkController->init(RR->identity,this);
|
||||
if (networkControllerInstance)
|
||||
RR->localNetworkController->init(RR->identity,this);
|
||||
}
|
||||
|
||||
ZT_ResultCode Node::circuitTestBegin(void *tptr,ZT_CircuitTest *test,void (*reportCallback)(ZT_Node *,ZT_CircuitTest *,const ZT_CircuitTestReport *))
|
||||
@@ -692,10 +704,14 @@ void Node::postTrace(const char *module,unsigned int line,const char *fmt,...)
|
||||
|
||||
uint64_t Node::prng()
|
||||
{
|
||||
unsigned int p = (++_prngStreamPtr % ZT_NODE_PRNG_BUF_SIZE);
|
||||
if (!p)
|
||||
_prng.crypt12(_prngStream,_prngStream,sizeof(_prngStream));
|
||||
return _prngStream[p];
|
||||
// https://en.wikipedia.org/wiki/Xorshift#xorshift.2B
|
||||
uint64_t x = _prngState[0];
|
||||
const uint64_t y = _prngState[1];
|
||||
_prngState[0] = y;
|
||||
x ^= x << 23;
|
||||
const uint64_t z = x ^ y ^ (x >> 17) ^ (y >> 26);
|
||||
_prngState[1] = z;
|
||||
return z + y;
|
||||
}
|
||||
|
||||
void Node::postCircuitTestReport(const ZT_CircuitTestReport *report)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_NODE_HPP
|
||||
@@ -50,9 +58,6 @@
|
||||
#define ZT_EXPECTING_REPLIES_BUCKET_MASK1 255
|
||||
#define ZT_EXPECTING_REPLIES_BUCKET_MASK2 31
|
||||
|
||||
// Size of PRNG stream buffer
|
||||
#define ZT_NODE_PRNG_BUF_SIZE 64
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
class World;
|
||||
@@ -312,13 +317,10 @@ private:
|
||||
|
||||
Mutex _backgroundTasksLock;
|
||||
|
||||
unsigned int _prngStreamPtr;
|
||||
Salsa20 _prng;
|
||||
uint64_t _prngStream[ZT_NODE_PRNG_BUF_SIZE]; // repeatedly encrypted with _prng to yield a high-quality non-crypto PRNG stream
|
||||
|
||||
uint64_t _now;
|
||||
uint64_t _lastPingCheck;
|
||||
uint64_t _lastHousekeepingRun;
|
||||
volatile uint64_t _prngState[2];
|
||||
bool _online;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_NONCOPYABLE_HPP__
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include "Constants.hpp"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_OUTBOUNDMULTICAST_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
@@ -24,6 +32,13 @@
|
||||
|
||||
#include "Packet.hpp"
|
||||
|
||||
#ifdef ZT_USE_X64_ASM_SALSA2012
|
||||
#include "../ext/x64-salsa2012-asm/salsa2012.h"
|
||||
#endif
|
||||
#ifdef ZT_USE_ARM32_NEON_ASM_SALSA2012
|
||||
#include "../ext/arm32-neon-salsa2012-asm/salsa2012.h"
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define FORCE_INLINE static __forceinline
|
||||
#include <intrin.h>
|
||||
@@ -36,6 +51,34 @@
|
||||
namespace ZeroTier {
|
||||
|
||||
/************************************************************************** */
|
||||
|
||||
/* Set up macros for fast single-pass ASM Salsa20/12 crypto, if we have it */
|
||||
|
||||
// x64 SSE crypto
|
||||
#ifdef ZT_USE_X64_ASM_SALSA2012
|
||||
#define ZT_HAS_FAST_CRYPTO() (true)
|
||||
#define ZT_FAST_SINGLE_PASS_SALSA2012(b,l,n,k) zt_salsa2012_amd64_xmm6(reinterpret_cast<unsigned char *>(b),(l),reinterpret_cast<const unsigned char *>(n),reinterpret_cast<const unsigned char *>(k))
|
||||
#endif
|
||||
|
||||
// ARM (32-bit) NEON crypto (must be detected)
|
||||
#ifdef ZT_USE_ARM32_NEON_ASM_SALSA2012
|
||||
class _FastCryptoChecker
|
||||
{
|
||||
public:
|
||||
_FastCryptoChecker() : canHas(zt_arm_has_neon()) {}
|
||||
bool canHas;
|
||||
};
|
||||
static const _FastCryptoChecker _ZT_FAST_CRYPTO_CHECK;
|
||||
#define ZT_HAS_FAST_CRYPTO() (_ZT_FAST_CRYPTO_CHECK.canHas)
|
||||
#define ZT_FAST_SINGLE_PASS_SALSA2012(b,l,n,k) zt_salsa2012_armneon3_xor(reinterpret_cast<unsigned char *>(b),(const unsigned char *)0,(l),reinterpret_cast<const unsigned char *>(n),reinterpret_cast<const unsigned char *>(k))
|
||||
#endif
|
||||
|
||||
// No fast crypto available
|
||||
#ifndef ZT_HAS_FAST_CRYPTO
|
||||
#define ZT_HAS_FAST_CRYPTO() (false)
|
||||
#define ZT_FAST_SINGLE_PASS_SALSA2012(b,l,n,k) {}
|
||||
#endif
|
||||
|
||||
/************************************************************************** */
|
||||
|
||||
/* LZ4 is shipped encapsulated into Packet in an anonymous namespace.
|
||||
@@ -1064,7 +1107,7 @@ const char *Packet::errorString(ErrorCode e)
|
||||
|
||||
void Packet::armor(const void *key,bool encryptPayload,unsigned int counter)
|
||||
{
|
||||
uint8_t mangledKey[32],macKey[32],mac[16];
|
||||
uint8_t mangledKey[32];
|
||||
uint8_t *const data = reinterpret_cast<uint8_t *>(unsafeData());
|
||||
|
||||
// Mask least significant 3 bits of packet ID with counter to embed packet send counter for QoS use
|
||||
@@ -1074,23 +1117,35 @@ void Packet::armor(const void *key,bool encryptPayload,unsigned int counter)
|
||||
setCipher(encryptPayload ? ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012 : ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE);
|
||||
|
||||
_salsa20MangleKey((const unsigned char *)key,mangledKey);
|
||||
Salsa20 s20(mangledKey,256,data + ZT_PACKET_IDX_IV);
|
||||
|
||||
// MAC key is always the first 32 bytes of the Salsa20 key stream
|
||||
// This is the same construction DJB's NaCl library uses
|
||||
s20.crypt12(ZERO_KEY,macKey,sizeof(macKey));
|
||||
|
||||
uint8_t *const payload = data + ZT_PACKET_IDX_VERB;
|
||||
const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB;
|
||||
if (encryptPayload)
|
||||
s20.crypt12(payload,payload,payloadLen);
|
||||
Poly1305::compute(mac,payload,payloadLen,macKey);
|
||||
memcpy(data + ZT_PACKET_IDX_MAC,mac,8);
|
||||
if (ZT_HAS_FAST_CRYPTO()) {
|
||||
const unsigned int encryptLen = (encryptPayload) ? (size() - ZT_PACKET_IDX_VERB) : 0;
|
||||
uint64_t keyStream[(ZT_PROTO_MAX_PACKET_LENGTH + 64 + 8) / 8];
|
||||
ZT_FAST_SINGLE_PASS_SALSA2012(keyStream,encryptLen + 64,(data + ZT_PACKET_IDX_IV),mangledKey);
|
||||
Salsa20::memxor(data + ZT_PACKET_IDX_VERB,reinterpret_cast<const uint8_t *>(keyStream + 8),encryptLen);
|
||||
uint64_t mac[2];
|
||||
Poly1305::compute(mac,data + ZT_PACKET_IDX_VERB,size() - ZT_PACKET_IDX_VERB,keyStream);
|
||||
#ifdef ZT_NO_TYPE_PUNNING
|
||||
memcpy(data + ZT_PACKET_IDX_MAC,mac,8);
|
||||
#else
|
||||
(*reinterpret_cast<uint64_t *>(data + ZT_PACKET_IDX_MAC)) = mac[0];
|
||||
#endif
|
||||
} else {
|
||||
Salsa20 s20(mangledKey,data + ZT_PACKET_IDX_IV);
|
||||
uint64_t macKey[4];
|
||||
s20.crypt12(ZERO_KEY,macKey,sizeof(macKey));
|
||||
uint8_t *const payload = data + ZT_PACKET_IDX_VERB;
|
||||
const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB;
|
||||
if (encryptPayload)
|
||||
s20.crypt12(payload,payload,payloadLen);
|
||||
uint64_t mac[2];
|
||||
Poly1305::compute(mac,payload,payloadLen,macKey);
|
||||
memcpy(data + ZT_PACKET_IDX_MAC,mac,8);
|
||||
}
|
||||
}
|
||||
|
||||
bool Packet::dearmor(const void *key)
|
||||
{
|
||||
uint8_t mangledKey[32],macKey[32],mac[16];
|
||||
uint8_t mangledKey[32];
|
||||
uint8_t *const data = reinterpret_cast<uint8_t *>(unsafeData());
|
||||
const unsigned int payloadLen = size() - ZT_PACKET_IDX_VERB;
|
||||
unsigned char *const payload = data + ZT_PACKET_IDX_VERB;
|
||||
@@ -1098,15 +1153,36 @@ bool Packet::dearmor(const void *key)
|
||||
|
||||
if ((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)||(cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)) {
|
||||
_salsa20MangleKey((const unsigned char *)key,mangledKey);
|
||||
Salsa20 s20(mangledKey,256,data + ZT_PACKET_IDX_IV);
|
||||
|
||||
s20.crypt12(ZERO_KEY,macKey,sizeof(macKey));
|
||||
Poly1305::compute(mac,payload,payloadLen,macKey);
|
||||
if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8))
|
||||
return false; // MAC failed, packet is corrupt, modified, or is not from the sender
|
||||
|
||||
if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)
|
||||
s20.crypt12(payload,payload,payloadLen);
|
||||
if (ZT_HAS_FAST_CRYPTO()) {
|
||||
uint64_t keyStream[(ZT_PROTO_MAX_PACKET_LENGTH + 64 + 8) / 8];
|
||||
ZT_FAST_SINGLE_PASS_SALSA2012(keyStream,((cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012) ? (payloadLen + 64) : 64),(data + ZT_PACKET_IDX_IV),mangledKey);
|
||||
uint64_t mac[2];
|
||||
Poly1305::compute(mac,payload,payloadLen,keyStream);
|
||||
#ifdef ZT_NO_TYPE_PUNNING
|
||||
if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8))
|
||||
return false;
|
||||
#else
|
||||
if ((*reinterpret_cast<const uint64_t *>(data + ZT_PACKET_IDX_MAC)) != mac[0]) // also secure, constant time
|
||||
return false;
|
||||
#endif
|
||||
if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)
|
||||
Salsa20::memxor(data + ZT_PACKET_IDX_VERB,reinterpret_cast<const uint8_t *>(keyStream + 8),payloadLen);
|
||||
} else {
|
||||
Salsa20 s20(mangledKey,data + ZT_PACKET_IDX_IV);
|
||||
uint64_t macKey[4];
|
||||
s20.crypt12(ZERO_KEY,macKey,sizeof(macKey));
|
||||
uint64_t mac[2];
|
||||
Poly1305::compute(mac,payload,payloadLen,macKey);
|
||||
#ifdef ZT_NO_TYPE_PUNNING
|
||||
if (!Utils::secureEq(mac,data + ZT_PACKET_IDX_MAC,8))
|
||||
return false;
|
||||
#else
|
||||
if ((*reinterpret_cast<const uint64_t *>(data + ZT_PACKET_IDX_MAC)) != mac[0]) // also secure, constant time
|
||||
return false;
|
||||
#endif
|
||||
if (cs == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_SALSA2012)
|
||||
s20.crypt12(payload,payload,payloadLen);
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
@@ -1120,7 +1196,7 @@ void Packet::cryptField(const void *key,unsigned int start,unsigned int len)
|
||||
uint8_t iv[8];
|
||||
for(int i=0;i<8;++i) iv[i] = data[i];
|
||||
iv[7] &= 0xf8; // mask off least significant 3 bits of packet ID / IV since this is unset when this function gets called
|
||||
Salsa20 s20(key,256,iv);
|
||||
Salsa20 s20(key,iv);
|
||||
s20.crypt12(data + start,data + start,len);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_N_PACKET_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include "Path.hpp"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_PATH_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include "../version.h"
|
||||
@@ -27,14 +35,6 @@
|
||||
#include "Cluster.hpp"
|
||||
#include "Packet.hpp"
|
||||
|
||||
#ifndef AF_MAX
|
||||
#if AF_INET > AF_INET6
|
||||
#define AF_MAX AF_INET
|
||||
#else
|
||||
#define AF_MAX AF_INET6
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Identity &peerIdentity) :
|
||||
@@ -51,18 +51,15 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
|
||||
_lastComRequestSent(0),
|
||||
_lastCredentialsReceived(0),
|
||||
_lastTrustEstablishedPacketReceived(0),
|
||||
_remoteClusterOptimal4(0),
|
||||
_vProto(0),
|
||||
_vMajor(0),
|
||||
_vMinor(0),
|
||||
_vRevision(0),
|
||||
_id(peerIdentity),
|
||||
_numPaths(0),
|
||||
_latency(0),
|
||||
_directPathPushCutoffCount(0),
|
||||
_credentialsCutoffCount(0)
|
||||
{
|
||||
memset(_remoteClusterOptimal6,0,sizeof(_remoteClusterOptimal6));
|
||||
if (!myIdentity.agree(peerIdentity,_key,ZT_PEER_SECRET_KEY_LENGTH))
|
||||
throw std::runtime_error("new peer identity key agreement failed");
|
||||
}
|
||||
@@ -80,7 +77,7 @@ void Peer::received(
|
||||
const uint64_t now = RR->node->now();
|
||||
|
||||
#ifdef ZT_ENABLE_CLUSTER
|
||||
bool suboptimalPath = false;
|
||||
bool isClusterSuboptimalPath = false;
|
||||
if ((RR->cluster)&&(hops == 0)) {
|
||||
// Note: findBetterEndpoint() is first since we still want to check
|
||||
// for a better endpoint even if we don't actually send a redirect.
|
||||
@@ -120,7 +117,7 @@ void Peer::received(
|
||||
outp.armor(_key,true,path->nextOutgoingCounter());
|
||||
path->send(RR,tPtr,outp.data(),outp.size(),now);
|
||||
}
|
||||
suboptimalPath = true;
|
||||
isClusterSuboptimalPath = true;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -146,78 +143,71 @@ void Peer::received(
|
||||
path->updateLinkQuality((unsigned int)(packetId & 7));
|
||||
|
||||
if (hops == 0) {
|
||||
bool pathIsConfirmed = false;
|
||||
bool pathAlreadyKnown = false;
|
||||
{
|
||||
Mutex::Lock _l(_paths_m);
|
||||
for(unsigned int p=0;p<_numPaths;++p) {
|
||||
if (_paths[p].path->address() == path->address()) {
|
||||
_paths[p].lastReceive = now;
|
||||
_paths[p].path = path; // local address may have changed!
|
||||
if ((path->address().ss_family == AF_INET)&&(_v4Path.p)) {
|
||||
const struct sockaddr_in *const r = reinterpret_cast<const struct sockaddr_in *>(&(path->address()));
|
||||
const struct sockaddr_in *const l = reinterpret_cast<const struct sockaddr_in *>(&(_v4Path.p->address()));
|
||||
const struct sockaddr_in *const rl = reinterpret_cast<const struct sockaddr_in *>(&(path->localAddress()));
|
||||
const struct sockaddr_in *const ll = reinterpret_cast<const struct sockaddr_in *>(&(_v4Path.p->localAddress()));
|
||||
if ((r->sin_addr.s_addr == l->sin_addr.s_addr)&&(r->sin_port == l->sin_port)&&(rl->sin_addr.s_addr == ll->sin_addr.s_addr)&&(rl->sin_port == ll->sin_port)) {
|
||||
_v4Path.lr = now;
|
||||
#ifdef ZT_ENABLE_CLUSTER
|
||||
_paths[p].localClusterSuboptimal = suboptimalPath;
|
||||
_v4Path.localClusterSuboptimal = isClusterSuboptimalPath;
|
||||
#endif
|
||||
pathIsConfirmed = true;
|
||||
break;
|
||||
pathAlreadyKnown = true;
|
||||
}
|
||||
} else if ((path->address().ss_family == AF_INET6)&&(_v6Path.p)) {
|
||||
const struct sockaddr_in6 *const r = reinterpret_cast<const struct sockaddr_in6 *>(&(path->address()));
|
||||
const struct sockaddr_in6 *const l = reinterpret_cast<const struct sockaddr_in6 *>(&(_v6Path.p->address()));
|
||||
const struct sockaddr_in6 *const rl = reinterpret_cast<const struct sockaddr_in6 *>(&(path->localAddress()));
|
||||
const struct sockaddr_in6 *const ll = reinterpret_cast<const struct sockaddr_in6 *>(&(_v6Path.p->localAddress()));
|
||||
if ((!memcmp(r->sin6_addr.s6_addr,l->sin6_addr.s6_addr,16))&&(r->sin6_port == l->sin6_port)&&(!memcmp(rl->sin6_addr.s6_addr,ll->sin6_addr.s6_addr,16))&&(rl->sin6_port == ll->sin6_port)) {
|
||||
_v6Path.lr = now;
|
||||
#ifdef ZT_ENABLE_CLUSTER
|
||||
_v6Path.localClusterSuboptimal = isClusterSuboptimalPath;
|
||||
#endif
|
||||
pathAlreadyKnown = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( (!pathIsConfirmed) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localAddress(),path->address())) ) {
|
||||
if (verb == Packet::VERB_OK) {
|
||||
Mutex::Lock _l(_paths_m);
|
||||
|
||||
// Since this is a new path, figure out where to put it (possibly replacing an old/dead one)
|
||||
unsigned int slot;
|
||||
if (_numPaths < ZT_MAX_PEER_NETWORK_PATHS) {
|
||||
slot = _numPaths++;
|
||||
} else {
|
||||
// First try to replace the worst within the same address family, if possible
|
||||
int worstSlot = -1;
|
||||
uint64_t worstScore = 0xffffffffffffffffULL;
|
||||
for(unsigned int p=0;p<_numPaths;++p) {
|
||||
if (_paths[p].path->address().ss_family == path->address().ss_family) {
|
||||
const uint64_t s = _pathScore(p,now);
|
||||
if (s < worstScore) {
|
||||
worstScore = s;
|
||||
worstSlot = (int)p;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (worstSlot >= 0) {
|
||||
slot = (unsigned int)worstSlot;
|
||||
} else {
|
||||
// If we can't find one with the same family, replace the worst of any family
|
||||
slot = ZT_MAX_PEER_NETWORK_PATHS - 1;
|
||||
for(unsigned int p=0;p<_numPaths;++p) {
|
||||
const uint64_t s = _pathScore(p,now);
|
||||
if (s < worstScore) {
|
||||
worstScore = s;
|
||||
slot = p;
|
||||
}
|
||||
}
|
||||
}
|
||||
if ( (!pathAlreadyKnown) && (RR->node->shouldUsePathForZeroTierTraffic(tPtr,_id.address(),path->localAddress(),path->address())) ) {
|
||||
Mutex::Lock _l(_paths_m);
|
||||
_PeerPath *potentialNewPeerPath = (_PeerPath *)0;
|
||||
if (path->address().ss_family == AF_INET) {
|
||||
if ( (!_v4Path.p) || (!_v4Path.p->alive(now)) || ((_v4Path.p->address() != _v4ClusterPreferred)&&(path->preferenceRank() >= _v4Path.p->preferenceRank())) ) {
|
||||
potentialNewPeerPath = &_v4Path;
|
||||
}
|
||||
|
||||
_paths[slot].lastReceive = now;
|
||||
_paths[slot].path = path;
|
||||
} else if (path->address().ss_family == AF_INET6) {
|
||||
if ( (!_v6Path.p) || (!_v6Path.p->alive(now)) || ((_v6Path.p->address() != _v6ClusterPreferred)&&(path->preferenceRank() >= _v6Path.p->preferenceRank())) ) {
|
||||
potentialNewPeerPath = &_v6Path;
|
||||
}
|
||||
}
|
||||
if (potentialNewPeerPath) {
|
||||
if (verb == Packet::VERB_OK) {
|
||||
potentialNewPeerPath->lr = now;
|
||||
potentialNewPeerPath->p = path;
|
||||
#ifdef ZT_ENABLE_CLUSTER
|
||||
_paths[slot].localClusterSuboptimal = suboptimalPath;
|
||||
if (RR->cluster)
|
||||
RR->cluster->broadcastHavePeer(_id);
|
||||
potentialNewPeerPath->localClusterSuboptimal = isClusterSuboptimalPath;
|
||||
if (RR->cluster)
|
||||
RR->cluster->broadcastHavePeer(_id);
|
||||
#endif
|
||||
} else {
|
||||
TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str());
|
||||
attemptToContactAt(tPtr,path->localAddress(),path->address(),now,true,path->nextOutgoingCounter());
|
||||
path->sent(now);
|
||||
} else {
|
||||
TRACE("got %s via unknown path %s(%s), confirming...",Packet::verbString(verb),_id.address().toString().c_str(),path->address().toString().c_str());
|
||||
attemptToContactAt(tPtr,path->localAddress(),path->address(),now,true,path->nextOutgoingCounter());
|
||||
path->sent(now);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (this->trustEstablished(now)) {
|
||||
// Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership)
|
||||
#ifdef ZT_ENABLE_CLUSTER
|
||||
// Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection
|
||||
const bool haveCluster = (RR->cluster);
|
||||
// Cluster mode disables normal PUSH_DIRECT_PATHS in favor of cluster-based peer redirection
|
||||
const bool haveCluster = (RR->cluster);
|
||||
#else
|
||||
const bool haveCluster = false;
|
||||
const bool haveCluster = false;
|
||||
#endif
|
||||
if ( ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) && (!haveCluster) ) {
|
||||
_lastDirectPathPushSent = now;
|
||||
@@ -290,60 +280,50 @@ void Peer::received(
|
||||
}
|
||||
}
|
||||
|
||||
bool Peer::hasActivePathTo(uint64_t now,const InetAddress &addr) const
|
||||
{
|
||||
Mutex::Lock _l(_paths_m);
|
||||
for(unsigned int p=0;p<_numPaths;++p) {
|
||||
if ( (_paths[p].path->address() == addr) && ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)) )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead)
|
||||
bool Peer::sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force)
|
||||
{
|
||||
Mutex::Lock _l(_paths_m);
|
||||
|
||||
int bestp = -1;
|
||||
uint64_t best = 0ULL;
|
||||
for(unsigned int p=0;p<_numPaths;++p) {
|
||||
if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)||(forceEvenIfDead)) ) {
|
||||
const uint64_t s = _pathScore(p,now);
|
||||
if (s >= best) {
|
||||
best = s;
|
||||
bestp = (int)p;
|
||||
}
|
||||
uint64_t v6lr = 0;
|
||||
if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) )
|
||||
v6lr = _v6Path.p->lastIn();
|
||||
uint64_t v4lr = 0;
|
||||
if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) )
|
||||
v4lr = _v4Path.p->lastIn();
|
||||
|
||||
if ( (v6lr > v4lr) && ((now - v6lr) < ZT_PATH_ALIVE_TIMEOUT) ) {
|
||||
return _v6Path.p->send(RR,tPtr,data,len,now);
|
||||
} else if ((now - v4lr) < ZT_PATH_ALIVE_TIMEOUT) {
|
||||
return _v4Path.p->send(RR,tPtr,data,len,now);
|
||||
} else if (force) {
|
||||
if (v6lr > v4lr) {
|
||||
return _v6Path.p->send(RR,tPtr,data,len,now);
|
||||
} else if (v4lr) {
|
||||
return _v4Path.p->send(RR,tPtr,data,len,now);
|
||||
}
|
||||
}
|
||||
|
||||
if (bestp >= 0) {
|
||||
return _paths[bestp].path->send(RR,tPtr,data,len,now);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
SharedPtr<Path> Peer::getBestPath(uint64_t now,bool includeExpired)
|
||||
{
|
||||
Mutex::Lock _l(_paths_m);
|
||||
|
||||
int bestp = -1;
|
||||
uint64_t best = 0ULL;
|
||||
for(unsigned int p=0;p<_numPaths;++p) {
|
||||
if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) || (includeExpired) ) {
|
||||
const uint64_t s = _pathScore(p,now);
|
||||
if (s >= best) {
|
||||
best = s;
|
||||
bestp = (int)p;
|
||||
}
|
||||
}
|
||||
uint64_t v6lr = 0;
|
||||
if ( ( includeExpired || ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) ) && (_v6Path.p) )
|
||||
v6lr = _v6Path.p->lastIn();
|
||||
uint64_t v4lr = 0;
|
||||
if ( ( includeExpired || ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) ) && (_v4Path.p) )
|
||||
v4lr = _v4Path.p->lastIn();
|
||||
|
||||
if (v6lr > v4lr) {
|
||||
return _v6Path.p;
|
||||
} else if (v4lr) {
|
||||
return _v4Path.p;
|
||||
}
|
||||
|
||||
if (bestp >= 0) {
|
||||
return _paths[bestp].path;
|
||||
} else {
|
||||
return SharedPtr<Path>();
|
||||
}
|
||||
return SharedPtr<Path>();
|
||||
}
|
||||
|
||||
void Peer::sendHELLO(void *tPtr,const InetAddress &localAddr,const InetAddress &atAddress,uint64_t now,unsigned int counter)
|
||||
@@ -420,79 +400,44 @@ bool Peer::doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily)
|
||||
{
|
||||
Mutex::Lock _l(_paths_m);
|
||||
|
||||
int bestp = -1;
|
||||
uint64_t best = 0ULL;
|
||||
for(unsigned int p=0;p<_numPaths;++p) {
|
||||
if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && ((inetAddressFamily < 0)||((int)_paths[p].path->address().ss_family == inetAddressFamily)) ) {
|
||||
const uint64_t s = _pathScore(p,now);
|
||||
if (s >= best) {
|
||||
best = s;
|
||||
bestp = (int)p;
|
||||
if (inetAddressFamily < 0) {
|
||||
uint64_t v6lr = 0;
|
||||
if ( ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v6Path.p) )
|
||||
v6lr = _v6Path.p->lastIn();
|
||||
uint64_t v4lr = 0;
|
||||
if ( ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) && (_v4Path.p) )
|
||||
v4lr = _v4Path.p->lastIn();
|
||||
|
||||
if (v6lr > v4lr) {
|
||||
if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) {
|
||||
attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter());
|
||||
_v6Path.p->sent(now);
|
||||
return true;
|
||||
}
|
||||
} else if (v4lr) {
|
||||
if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) {
|
||||
attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter());
|
||||
_v4Path.p->sent(now);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if ( (inetAddressFamily == AF_INET) && ((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION) ) {
|
||||
if ( ((now - _v4Path.lr) >= ZT_PEER_PING_PERIOD) || (_v4Path.p->needsHeartbeat(now)) ) {
|
||||
attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter());
|
||||
_v4Path.p->sent(now);
|
||||
return true;
|
||||
}
|
||||
} else if ( (inetAddressFamily == AF_INET6) && ((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION) ) {
|
||||
if ( ((now - _v6Path.lr) >= ZT_PEER_PING_PERIOD) || (_v6Path.p->needsHeartbeat(now)) ) {
|
||||
attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter());
|
||||
_v6Path.p->sent(now);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestp >= 0) {
|
||||
if ( ((now - _paths[bestp].lastReceive) >= ZT_PEER_PING_PERIOD) || (_paths[bestp].path->needsHeartbeat(now)) ) {
|
||||
attemptToContactAt(tPtr,_paths[bestp].path->localAddress(),_paths[bestp].path->address(),now,false,_paths[bestp].path->nextOutgoingCounter());
|
||||
_paths[bestp].path->sent(now);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Peer::hasActiveDirectPath(uint64_t now) const
|
||||
{
|
||||
Mutex::Lock _l(_paths_m);
|
||||
for(unsigned int p=0;p<_numPaths;++p) {
|
||||
if (((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION)&&(_paths[p].path->alive(now)))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Peer::resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now)
|
||||
{
|
||||
Mutex::Lock _l(_paths_m);
|
||||
for(unsigned int p=0;p<_numPaths;++p) {
|
||||
if ( (_paths[p].path->address().ss_family == inetAddressFamily) && (_paths[p].path->address().ipScope() == scope) ) {
|
||||
attemptToContactAt(tPtr,_paths[p].path->localAddress(),_paths[p].path->address(),now,false,_paths[p].path->nextOutgoingCounter());
|
||||
_paths[p].path->sent(now);
|
||||
_paths[p].lastReceive = 0; // path will not be used unless it speaks again
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Peer::getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const
|
||||
{
|
||||
Mutex::Lock _l(_paths_m);
|
||||
|
||||
int bestp4 = -1,bestp6 = -1;
|
||||
uint64_t best4 = 0ULL,best6 = 0ULL;
|
||||
for(unsigned int p=0;p<_numPaths;++p) {
|
||||
if ( ((now - _paths[p].lastReceive) <= ZT_PEER_PATH_EXPIRATION) && (_paths[p].path->alive(now)) ) {
|
||||
if (_paths[p].path->address().ss_family == AF_INET) {
|
||||
const uint64_t s = _pathScore(p,now);
|
||||
if (s >= best4) {
|
||||
best4 = s;
|
||||
bestp4 = (int)p;
|
||||
}
|
||||
} else if (_paths[p].path->address().ss_family == AF_INET6) {
|
||||
const uint64_t s = _pathScore(p,now);
|
||||
if (s >= best6) {
|
||||
best6 = s;
|
||||
bestp6 = (int)p;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (bestp4 >= 0)
|
||||
v4 = _paths[bestp4].path->address();
|
||||
if (bestp6 >= 0)
|
||||
v6 = _paths[bestp6].path->address();
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_PEER_HPP
|
||||
@@ -108,20 +116,10 @@ public:
|
||||
* @param addr Remote address
|
||||
* @return True if we have an active path to this destination
|
||||
*/
|
||||
bool hasActivePathTo(uint64_t now,const InetAddress &addr) const;
|
||||
|
||||
/**
|
||||
* Set which known path for an address family is optimal
|
||||
*
|
||||
* @param addr Address to make exclusive
|
||||
*/
|
||||
inline void setClusterOptimal(const InetAddress &addr)
|
||||
inline bool hasActivePathTo(uint64_t now,const InetAddress &addr) const
|
||||
{
|
||||
if (addr.ss_family == AF_INET) {
|
||||
_remoteClusterOptimal4 = (uint32_t)reinterpret_cast<const struct sockaddr_in *>(&addr)->sin_addr.s_addr;
|
||||
} else if (addr.ss_family == AF_INET6) {
|
||||
memcpy(_remoteClusterOptimal6,reinterpret_cast<const struct sockaddr_in6 *>(&addr)->sin6_addr.s6_addr,16);
|
||||
}
|
||||
Mutex::Lock _l(_paths_m);
|
||||
return ( ((addr.ss_family == AF_INET)&&(_v4Path.p)&&(_v4Path.p->address() == addr)&&(_v4Path.p->alive(now))) || ((addr.ss_family == AF_INET6)&&(_v6Path.p)&&(_v6Path.p->address() == addr)&&(_v6Path.p->alive(now))) );
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,14 +129,17 @@ public:
|
||||
* @param data Packet data
|
||||
* @param len Packet length
|
||||
* @param now Current time
|
||||
* @param forceEvenIfDead If true, send even if the path is not 'alive'
|
||||
* @param force If true, send even if path is not alive
|
||||
* @return True if we actually sent something
|
||||
*/
|
||||
bool sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool forceEvenIfDead);
|
||||
bool sendDirect(void *tPtr,const void *data,unsigned int len,uint64_t now,bool force);
|
||||
|
||||
/**
|
||||
* Get the best current direct path
|
||||
*
|
||||
* This does not check Path::alive(), but does return the most recently
|
||||
* active path and does check expiration (which is a longer timeout).
|
||||
*
|
||||
* @param now Current time
|
||||
* @param includeExpired If true, include even expired paths
|
||||
* @return Best current path or NULL if none
|
||||
@@ -192,12 +193,6 @@ public:
|
||||
*/
|
||||
bool doPingAndKeepalive(void *tPtr,uint64_t now,int inetAddressFamily);
|
||||
|
||||
/**
|
||||
* @param now Current time
|
||||
* @return True if this peer has at least one active and alive direct path
|
||||
*/
|
||||
bool hasActiveDirectPath(uint64_t now) const;
|
||||
|
||||
/**
|
||||
* Reset paths within a given IP scope and address family
|
||||
*
|
||||
@@ -209,30 +204,61 @@ public:
|
||||
* @param inetAddressFamily Family e.g. AF_INET
|
||||
* @param now Current time
|
||||
*/
|
||||
void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now);
|
||||
inline void resetWithinScope(void *tPtr,InetAddress::IpScope scope,int inetAddressFamily,uint64_t now)
|
||||
{
|
||||
Mutex::Lock _l(_paths_m);
|
||||
if ((inetAddressFamily == AF_INET)&&(_v4Path.lr)&&(_v4Path.p->address().ipScope() == scope)) {
|
||||
attemptToContactAt(tPtr,_v4Path.p->localAddress(),_v4Path.p->address(),now,false,_v4Path.p->nextOutgoingCounter());
|
||||
_v4Path.p->sent(now);
|
||||
_v4Path.lr = 0; // path will not be used unless it speaks again
|
||||
} else if ((inetAddressFamily == AF_INET6)&&(_v6Path.lr)&&(_v6Path.p->address().ipScope() == scope)) {
|
||||
attemptToContactAt(tPtr,_v6Path.p->localAddress(),_v6Path.p->address(),now,false,_v6Path.p->nextOutgoingCounter());
|
||||
_v6Path.p->sent(now);
|
||||
_v6Path.lr = 0; // path will not be used unless it speaks again
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get most recently active path addresses for IPv4 and/or IPv6
|
||||
* Indicate that the given address was provided by a cluster as a preferred destination
|
||||
*
|
||||
* Note that v4 and v6 are not modified if they are not found, so
|
||||
* initialize these to a NULL address to be able to check.
|
||||
* @param addr Address cluster prefers that we use
|
||||
*/
|
||||
inline void setClusterPreferred(const InetAddress &addr)
|
||||
{
|
||||
if (addr.ss_family == AF_INET)
|
||||
_v4ClusterPreferred = addr;
|
||||
else if (addr.ss_family == AF_INET6)
|
||||
_v6ClusterPreferred = addr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill parameters with V4 and V6 addresses if known and alive
|
||||
*
|
||||
* @param now Current time
|
||||
* @param v4 Result parameter to receive active IPv4 address, if any
|
||||
* @param v6 Result parameter to receive active IPv6 address, if any
|
||||
*/
|
||||
void getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const;
|
||||
inline void getRendezvousAddresses(uint64_t now,InetAddress &v4,InetAddress &v6) const
|
||||
{
|
||||
Mutex::Lock _l(_paths_m);
|
||||
if (((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v4Path.p->alive(now)))
|
||||
v4 = _v4Path.p->address();
|
||||
if (((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v6Path.p->alive(now)))
|
||||
v6 = _v6Path.p->address();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param now Current time
|
||||
* @return All known direct paths to this peer and whether they are expired (true == expired)
|
||||
* @return All known paths to this peer
|
||||
*/
|
||||
inline std::vector< std::pair< SharedPtr<Path>,bool > > paths(const uint64_t now) const
|
||||
inline std::vector< SharedPtr<Path> > paths(const uint64_t now) const
|
||||
{
|
||||
std::vector< std::pair< SharedPtr<Path>,bool > > pp;
|
||||
std::vector< SharedPtr<Path> > pp;
|
||||
Mutex::Lock _l(_paths_m);
|
||||
for(unsigned int p=0,np=_numPaths;p<np;++p)
|
||||
pp.push_back(std::pair< SharedPtr<Path>,bool >(_paths[p].path,(now - _paths[p].lastReceive) > ZT_PEER_PATH_EXPIRATION));
|
||||
if (((now - _v4Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v4Path.p->alive(now)))
|
||||
pp.push_back(_v4Path.p);
|
||||
if (((now - _v6Path.lr) < ZT_PEER_PATH_EXPIRATION)&&(_v6Path.p->alive(now)))
|
||||
pp.push_back(_v6Path.p);
|
||||
return pp;
|
||||
}
|
||||
|
||||
@@ -298,11 +324,8 @@ public:
|
||||
*/
|
||||
inline bool hasLocalClusterOptimalPath(uint64_t now) const
|
||||
{
|
||||
for(unsigned int p=0,np=_numPaths;p<np;++p) {
|
||||
if ( (_paths[p].path->alive(now)) && (!_paths[p].localClusterSuboptimal) )
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
Mutex::Lock _l(_paths_m);
|
||||
return ( ((_v4Path.p)&&(_v4Path.p->alive(now))&&(!_v4Path.localClusterSuboptimal)) || ((_v6Path.p)&&(_v6Path.p->alive(now))&&(!_v6Path.localClusterSuboptimal)) );
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -424,32 +447,19 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
inline uint64_t _pathScore(const unsigned int p,const uint64_t now) const
|
||||
struct _PeerPath
|
||||
{
|
||||
uint64_t s = ZT_PEER_PING_PERIOD + _paths[p].lastReceive + (uint64_t)(_paths[p].path->preferenceRank() * (ZT_PEER_PING_PERIOD / ZT_PATH_MAX_PREFERENCE_RANK));
|
||||
|
||||
if (_paths[p].path->address().ss_family == AF_INET) {
|
||||
s += (uint64_t)(ZT_PEER_PING_PERIOD * (unsigned long)(reinterpret_cast<const struct sockaddr_in *>(&(_paths[p].path->address()))->sin_addr.s_addr == _remoteClusterOptimal4));
|
||||
} else if (_paths[p].path->address().ss_family == AF_INET6) {
|
||||
uint64_t clusterWeight = ZT_PEER_PING_PERIOD;
|
||||
const uint8_t *a = reinterpret_cast<const uint8_t *>(reinterpret_cast<const struct sockaddr_in6 *>(&(_paths[p].path->address()))->sin6_addr.s6_addr);
|
||||
for(long i=0;i<16;++i) {
|
||||
if (a[i] != _remoteClusterOptimal6[i]) {
|
||||
clusterWeight = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
s += clusterWeight;
|
||||
}
|
||||
|
||||
s += (ZT_PEER_PING_PERIOD / 2) * (uint64_t)_paths[p].path->alive(now);
|
||||
|
||||
#ifdef ZT_ENABLE_CLUSTER
|
||||
s -= ZT_PEER_PING_PERIOD * (uint64_t)_paths[p].localClusterSuboptimal;
|
||||
_PeerPath() : lr(0),p(),localClusterSuboptimal(false) {}
|
||||
#else
|
||||
_PeerPath() : lr(0),p() {}
|
||||
#endif
|
||||
|
||||
return s;
|
||||
}
|
||||
uint64_t lr; // time of last valid ZeroTier packet
|
||||
SharedPtr<Path> p;
|
||||
#ifdef ZT_ENABLE_CLUSTER
|
||||
bool localClusterSuboptimal; // true if our cluster has determined that we should not be serving this peer
|
||||
#endif
|
||||
};
|
||||
|
||||
uint8_t _key[ZT_PEER_SECRET_KEY_LENGTH];
|
||||
|
||||
@@ -468,26 +478,20 @@ private:
|
||||
uint64_t _lastCredentialsReceived;
|
||||
uint64_t _lastTrustEstablishedPacketReceived;
|
||||
|
||||
uint8_t _remoteClusterOptimal6[16];
|
||||
uint32_t _remoteClusterOptimal4;
|
||||
|
||||
uint16_t _vProto;
|
||||
uint16_t _vMajor;
|
||||
uint16_t _vMinor;
|
||||
uint16_t _vRevision;
|
||||
|
||||
Identity _id;
|
||||
InetAddress _v4ClusterPreferred;
|
||||
InetAddress _v6ClusterPreferred;
|
||||
|
||||
struct {
|
||||
uint64_t lastReceive;
|
||||
SharedPtr<Path> path;
|
||||
#ifdef ZT_ENABLE_CLUSTER
|
||||
bool localClusterSuboptimal;
|
||||
#endif
|
||||
} _paths[ZT_MAX_PEER_NETWORK_PATHS];
|
||||
_PeerPath _v4Path; // IPv4 direct path
|
||||
_PeerPath _v6Path; // IPv6 direct path
|
||||
Mutex _paths_m;
|
||||
|
||||
unsigned int _numPaths;
|
||||
Identity _id;
|
||||
|
||||
unsigned int _latency;
|
||||
unsigned int _directPathPushCutoffCount;
|
||||
unsigned int _credentialsCutoffCount;
|
||||
|
||||
@@ -135,11 +135,12 @@ typedef struct poly1305_context {
|
||||
unsigned char opaque[136];
|
||||
} poly1305_context;
|
||||
|
||||
#if (defined(_MSC_VER) || defined(__GNUC__)) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__))
|
||||
#if (defined(_MSC_VER) || defined(__GNUC__)) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64))
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
// 128-bit implementation for MSC and GCC from Poly1305-donna
|
||||
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
|
||||
@@ -183,9 +184,9 @@ typedef struct poly1305_state_internal_t {
|
||||
unsigned char final;
|
||||
} poly1305_state_internal_t;
|
||||
|
||||
/* interpret eight 8 bit unsigned integers as a 64 bit unsigned integer in little endian */
|
||||
static inline unsigned long long
|
||||
U8TO64(const unsigned char *p) {
|
||||
#if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN)
|
||||
static inline unsigned long long U8TO64(const unsigned char *p)
|
||||
{
|
||||
return
|
||||
(((unsigned long long)(p[0] & 0xff) ) |
|
||||
((unsigned long long)(p[1] & 0xff) << 8) |
|
||||
@@ -196,10 +197,13 @@ U8TO64(const unsigned char *p) {
|
||||
((unsigned long long)(p[6] & 0xff) << 48) |
|
||||
((unsigned long long)(p[7] & 0xff) << 56));
|
||||
}
|
||||
#else
|
||||
#define U8TO64(p) (*reinterpret_cast<const unsigned long long *>(p))
|
||||
#endif
|
||||
|
||||
/* store a 64 bit unsigned integer as eight 8 bit unsigned integers in little endian */
|
||||
static inline void
|
||||
U64TO8(unsigned char *p, unsigned long long v) {
|
||||
#if defined(ZT_NO_TYPE_PUNNING) || (__BYTE_ORDER != __LITTLE_ENDIAN)
|
||||
static inline void U64TO8(unsigned char *p, unsigned long long v)
|
||||
{
|
||||
p[0] = (v ) & 0xff;
|
||||
p[1] = (v >> 8) & 0xff;
|
||||
p[2] = (v >> 16) & 0xff;
|
||||
@@ -209,6 +213,9 @@ U64TO8(unsigned char *p, unsigned long long v) {
|
||||
p[6] = (v >> 48) & 0xff;
|
||||
p[7] = (v >> 56) & 0xff;
|
||||
}
|
||||
#else
|
||||
#define U64TO8(p,v) ((*reinterpret_cast<unsigned long long *>(p)) = (v))
|
||||
#endif
|
||||
|
||||
static inline void
|
||||
poly1305_init(poly1305_context *ctx, const unsigned char key[32]) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_POLY1305_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include "Revocation.hpp"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_REVOCATION_HPP
|
||||
@@ -26,6 +34,7 @@
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "../include/ZeroTierOne.h"
|
||||
#include "Credential.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "C25519.hpp"
|
||||
#include "Utils.hpp"
|
||||
@@ -44,20 +53,10 @@ class RuntimeEnvironment;
|
||||
/**
|
||||
* Revocation certificate to instantaneously revoke a COM, capability, or tag
|
||||
*/
|
||||
class Revocation
|
||||
class Revocation : public Credential
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Credential type being revoked
|
||||
*/
|
||||
enum CredentialType
|
||||
{
|
||||
CREDENTIAL_TYPE_NULL = 0,
|
||||
CREDENTIAL_TYPE_COM = 1, // CertificateOfMembership
|
||||
CREDENTIAL_TYPE_CAPABILITY = 2,
|
||||
CREDENTIAL_TYPE_TAG = 3,
|
||||
CREDENTIAL_TYPE_COO = 4 // CertificateOfOwnership
|
||||
};
|
||||
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_REVOCATION; }
|
||||
|
||||
Revocation()
|
||||
{
|
||||
@@ -73,23 +72,23 @@ public:
|
||||
* @param tgt Target node whose credential(s) are being revoked
|
||||
* @param ct Credential type being revoked
|
||||
*/
|
||||
Revocation(const uint64_t i,const uint64_t nwid,const uint64_t cid,const uint64_t thr,const uint64_t fl,const Address &tgt,const CredentialType ct) :
|
||||
Revocation(const uint32_t i,const uint64_t nwid,const uint32_t cid,const uint64_t thr,const uint64_t fl,const Address &tgt,const Credential::Type ct) :
|
||||
_id(i),
|
||||
_networkId(nwid),
|
||||
_credentialId(cid),
|
||||
_networkId(nwid),
|
||||
_threshold(thr),
|
||||
_flags(fl),
|
||||
_target(tgt),
|
||||
_signedBy(),
|
||||
_type(ct) {}
|
||||
|
||||
inline uint64_t id() const { return _id; }
|
||||
inline uint32_t id() const { return _id; }
|
||||
inline uint32_t credentialId() const { return _credentialId; }
|
||||
inline uint64_t networkId() const { return _networkId; }
|
||||
inline uint64_t credentialId() const { return _credentialId; }
|
||||
inline uint64_t threshold() const { return _threshold; }
|
||||
inline const Address &target() const { return _target; }
|
||||
inline const Address &signer() const { return _signedBy; }
|
||||
inline CredentialType type() const { return _type; }
|
||||
inline Credential::Type type() const { return _type; }
|
||||
|
||||
inline bool fastPropagate() const { return ((_flags & ZT_REVOCATION_FLAG_FAST_PROPAGATE) != 0); }
|
||||
|
||||
@@ -123,8 +122,10 @@ public:
|
||||
{
|
||||
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
|
||||
|
||||
b.append((uint32_t)0); // 4 unused bytes, currently set to 0
|
||||
b.append(_id);
|
||||
b.append(_networkId);
|
||||
b.append((uint32_t)0); // 4 unused bytes, currently set to 0
|
||||
b.append(_credentialId);
|
||||
b.append(_threshold);
|
||||
b.append(_flags);
|
||||
@@ -151,14 +152,16 @@ public:
|
||||
|
||||
unsigned int p = startAt;
|
||||
|
||||
_id = b.template at<uint64_t>(p); p += 8;
|
||||
p += 4; // 4 bytes, currently unused
|
||||
_id = b.template at<uint32_t>(p); p += 4;
|
||||
_networkId = b.template at<uint64_t>(p); p += 8;
|
||||
_credentialId = b.template at<uint64_t>(p); p += 8;
|
||||
p += 4; // 4 bytes, currently unused
|
||||
_credentialId = b.template at<uint32_t>(p); p += 4;
|
||||
_threshold = b.template at<uint64_t>(p); p += 8;
|
||||
_flags = b.template at<uint64_t>(p); p += 8;
|
||||
_target.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
|
||||
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
|
||||
_type = (CredentialType)b[p++];
|
||||
_type = (Credential::Type)b[p++];
|
||||
|
||||
if (b[p++] == 1) {
|
||||
if (b.template at<uint16_t>(p) == ZT_C25519_SIGNATURE_LEN) {
|
||||
@@ -178,14 +181,14 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
uint64_t _id;
|
||||
uint32_t _id;
|
||||
uint32_t _credentialId;
|
||||
uint64_t _networkId;
|
||||
uint64_t _credentialId;
|
||||
uint64_t _threshold;
|
||||
uint64_t _flags;
|
||||
Address _target;
|
||||
Address _signedBy;
|
||||
CredentialType _type;
|
||||
Credential::Type _type;
|
||||
C25519::Signature _signature;
|
||||
};
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_RUNTIMEENVIRONMENT_HPP
|
||||
|
||||
@@ -1,20 +1,11 @@
|
||||
// Code taken from NaCl by D. J. Bernstein and others
|
||||
// Public domain
|
||||
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
20080913
|
||||
D. J. Bernstein
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
@@ -25,18 +16,6 @@
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Code taken from NaCl by D. J. Bernstein and others
|
||||
// Public domain
|
||||
|
||||
/*
|
||||
20080913
|
||||
D. J. Bernstein
|
||||
Public domain.
|
||||
*/
|
||||
|
||||
#define uint64 uint64_t
|
||||
|
||||
#ifdef ZT_NO_TYPE_PUNNING
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_SHA512_HPP
|
||||
|
||||
@@ -66,65 +66,49 @@ static const _s20sseconsts _S20SSECONSTANTS;
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
void Salsa20::init(const void *key,unsigned int kbits,const void *iv)
|
||||
throw()
|
||||
void Salsa20::init(const void *key,const void *iv)
|
||||
{
|
||||
#ifdef ZT_SALSA20_SSE
|
||||
const uint32_t *k = (const uint32_t *)key;
|
||||
|
||||
const uint32_t *const k = (const uint32_t *)key;
|
||||
_state.i[0] = 0x61707865;
|
||||
_state.i[1] = 0x3320646e;
|
||||
_state.i[2] = 0x79622d32;
|
||||
_state.i[3] = 0x6b206574;
|
||||
_state.i[13] = k[0];
|
||||
_state.i[10] = k[1];
|
||||
_state.i[7] = k[2];
|
||||
_state.i[4] = k[3];
|
||||
if (kbits == 256) {
|
||||
k += 4;
|
||||
_state.i[1] = 0x3320646e;
|
||||
_state.i[2] = 0x79622d32;
|
||||
} else {
|
||||
_state.i[1] = 0x3120646e;
|
||||
_state.i[2] = 0x79622d36;
|
||||
}
|
||||
_state.i[15] = k[0];
|
||||
_state.i[12] = k[1];
|
||||
_state.i[9] = k[2];
|
||||
_state.i[6] = k[3];
|
||||
_state.i[14] = ((const uint32_t *)iv)[0];
|
||||
_state.i[11] = ((const uint32_t *)iv)[1];
|
||||
_state.i[5] = 0;
|
||||
_state.i[6] = k[7];
|
||||
_state.i[7] = k[2];
|
||||
_state.i[8] = 0;
|
||||
_state.i[9] = k[6];
|
||||
_state.i[10] = k[1];
|
||||
_state.i[11] = ((const uint32_t *)iv)[1];
|
||||
_state.i[12] = k[5];
|
||||
_state.i[13] = k[0];
|
||||
_state.i[14] = ((const uint32_t *)iv)[0];
|
||||
_state.i[15] = k[4];
|
||||
#else
|
||||
const char *constants;
|
||||
const uint8_t *k = (const uint8_t *)key;
|
||||
|
||||
const char *const constants = "expand 32-byte k";
|
||||
const uint8_t *const k = (const uint8_t *)key;
|
||||
_state.i[0] = U8TO32_LITTLE(constants + 0);
|
||||
_state.i[1] = U8TO32_LITTLE(k + 0);
|
||||
_state.i[2] = U8TO32_LITTLE(k + 4);
|
||||
_state.i[3] = U8TO32_LITTLE(k + 8);
|
||||
_state.i[4] = U8TO32_LITTLE(k + 12);
|
||||
if (kbits == 256) { /* recommended */
|
||||
k += 16;
|
||||
constants = "expand 32-byte k";
|
||||
} else { /* kbits == 128 */
|
||||
constants = "expand 16-byte k";
|
||||
}
|
||||
_state.i[5] = U8TO32_LITTLE(constants + 4);
|
||||
_state.i[6] = U8TO32_LITTLE(((const uint8_t *)iv) + 0);
|
||||
_state.i[7] = U8TO32_LITTLE(((const uint8_t *)iv) + 4);
|
||||
_state.i[8] = 0;
|
||||
_state.i[9] = 0;
|
||||
_state.i[10] = U8TO32_LITTLE(constants + 8);
|
||||
_state.i[11] = U8TO32_LITTLE(k + 0);
|
||||
_state.i[12] = U8TO32_LITTLE(k + 4);
|
||||
_state.i[13] = U8TO32_LITTLE(k + 8);
|
||||
_state.i[14] = U8TO32_LITTLE(k + 12);
|
||||
_state.i[11] = U8TO32_LITTLE(k + 16);
|
||||
_state.i[12] = U8TO32_LITTLE(k + 20);
|
||||
_state.i[13] = U8TO32_LITTLE(k + 24);
|
||||
_state.i[14] = U8TO32_LITTLE(k + 28);
|
||||
_state.i[15] = U8TO32_LITTLE(constants + 12);
|
||||
_state.i[0] = U8TO32_LITTLE(constants + 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
void Salsa20::crypt12(const void *in,void *out,unsigned int bytes)
|
||||
throw()
|
||||
{
|
||||
uint8_t tmp[64];
|
||||
const uint8_t *m = (const uint8_t *)in;
|
||||
@@ -624,7 +608,6 @@ void Salsa20::crypt12(const void *in,void *out,unsigned int bytes)
|
||||
}
|
||||
|
||||
void Salsa20::crypt20(const void *in,void *out,unsigned int bytes)
|
||||
throw()
|
||||
{
|
||||
uint8_t tmp[64];
|
||||
const uint8_t *m = (const uint8_t *)in;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Utils.hpp"
|
||||
@@ -30,30 +31,101 @@ namespace ZeroTier {
|
||||
class Salsa20
|
||||
{
|
||||
public:
|
||||
Salsa20() throw() {}
|
||||
|
||||
Salsa20() {}
|
||||
~Salsa20() { Utils::burn(&_state,sizeof(_state)); }
|
||||
|
||||
/**
|
||||
* @param key Key bits
|
||||
* @param kbits Number of key bits: 128 or 256 (recommended)
|
||||
* XOR d with s
|
||||
*
|
||||
* This is done efficiently using e.g. SSE if available. It's used when
|
||||
* alternative Salsa20 implementations are used in Packet and is here
|
||||
* since this is where all the SSE stuff is already included.
|
||||
*
|
||||
* @param d Destination to XOR
|
||||
* @param s Source bytes to XOR with destination
|
||||
* @param len Length of s and d
|
||||
*/
|
||||
static inline void memxor(uint8_t *d,const uint8_t *s,unsigned int len)
|
||||
{
|
||||
#ifdef ZT_SALSA20_SSE
|
||||
while (len >= 128) {
|
||||
__m128i s0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s));
|
||||
__m128i s1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 16));
|
||||
__m128i s2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 32));
|
||||
__m128i s3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 48));
|
||||
__m128i s4 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 64));
|
||||
__m128i s5 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 80));
|
||||
__m128i s6 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 96));
|
||||
__m128i s7 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(s + 112));
|
||||
__m128i d0 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d));
|
||||
__m128i d1 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 16));
|
||||
__m128i d2 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 32));
|
||||
__m128i d3 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 48));
|
||||
__m128i d4 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 64));
|
||||
__m128i d5 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 80));
|
||||
__m128i d6 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 96));
|
||||
__m128i d7 = _mm_loadu_si128(reinterpret_cast<__m128i *>(d + 112));
|
||||
d0 = _mm_xor_si128(d0,s0);
|
||||
d1 = _mm_xor_si128(d1,s1);
|
||||
d2 = _mm_xor_si128(d2,s2);
|
||||
d3 = _mm_xor_si128(d3,s3);
|
||||
d4 = _mm_xor_si128(d4,s4);
|
||||
d5 = _mm_xor_si128(d5,s5);
|
||||
d6 = _mm_xor_si128(d6,s6);
|
||||
d7 = _mm_xor_si128(d7,s7);
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i *>(d),d0);
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 16),d1);
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 32),d2);
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 48),d3);
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 64),d4);
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 80),d5);
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 96),d6);
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i *>(d + 112),d7);
|
||||
s += 128;
|
||||
d += 128;
|
||||
len -= 128;
|
||||
}
|
||||
while (len >= 16) {
|
||||
_mm_storeu_si128(reinterpret_cast<__m128i *>(d),_mm_xor_si128(_mm_loadu_si128(reinterpret_cast<__m128i *>(d)),_mm_loadu_si128(reinterpret_cast<const __m128i *>(s))));
|
||||
s += 16;
|
||||
d += 16;
|
||||
len -= 16;
|
||||
}
|
||||
#else
|
||||
#ifndef ZT_NO_TYPE_PUNNING
|
||||
while (len >= 16) {
|
||||
(*reinterpret_cast<uint64_t *>(d)) ^= (*reinterpret_cast<const uint64_t *>(s));
|
||||
s += 8;
|
||||
d += 8;
|
||||
(*reinterpret_cast<uint64_t *>(d)) ^= (*reinterpret_cast<const uint64_t *>(s));
|
||||
s += 8;
|
||||
d += 8;
|
||||
len -= 16;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
while (len) {
|
||||
--len;
|
||||
*(d++) ^= *(s++);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param key 256-bit (32 byte) key
|
||||
* @param iv 64-bit initialization vector
|
||||
*/
|
||||
Salsa20(const void *key,unsigned int kbits,const void *iv)
|
||||
throw()
|
||||
Salsa20(const void *key,const void *iv)
|
||||
{
|
||||
init(key,kbits,iv);
|
||||
init(key,iv);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize cipher
|
||||
*
|
||||
* @param key Key bits
|
||||
* @param kbits Number of key bits: 128 or 256 (recommended)
|
||||
* @param iv 64-bit initialization vector
|
||||
*/
|
||||
void init(const void *key,unsigned int kbits,const void *iv)
|
||||
throw();
|
||||
void init(const void *key,const void *iv);
|
||||
|
||||
/**
|
||||
* Encrypt/decrypt data using Salsa20/12
|
||||
@@ -62,8 +134,7 @@ public:
|
||||
* @param out Output buffer
|
||||
* @param bytes Length of data
|
||||
*/
|
||||
void crypt12(const void *in,void *out,unsigned int bytes)
|
||||
throw();
|
||||
void crypt12(const void *in,void *out,unsigned int bytes);
|
||||
|
||||
/**
|
||||
* Encrypt/decrypt data using Salsa20/20
|
||||
@@ -72,8 +143,7 @@ public:
|
||||
* @param out Output buffer
|
||||
* @param bytes Length of data
|
||||
*/
|
||||
void crypt20(const void *in,void *out,unsigned int bytes)
|
||||
throw();
|
||||
void crypt20(const void *in,void *out,unsigned int bytes);
|
||||
|
||||
private:
|
||||
union {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_SELFAWARENESS_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_SHAREDPTR_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_N_SWITCH_HPP
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include "Tag.hpp"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#ifndef ZT_TAG_HPP
|
||||
@@ -25,6 +33,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Credential.hpp"
|
||||
#include "C25519.hpp"
|
||||
#include "Address.hpp"
|
||||
#include "Identity.hpp"
|
||||
@@ -51,9 +60,11 @@ class RuntimeEnvironment;
|
||||
* Unlike capabilities tags are signed only by the issuer and are never
|
||||
* transferrable.
|
||||
*/
|
||||
class Tag
|
||||
class Tag : public Credential
|
||||
{
|
||||
public:
|
||||
static inline Credential::Type credentialType() { return Credential::CREDENTIAL_TYPE_TAG; }
|
||||
|
||||
Tag()
|
||||
{
|
||||
memset(this,0,sizeof(Tag));
|
||||
@@ -67,19 +78,19 @@ public:
|
||||
* @param value Tag value
|
||||
*/
|
||||
Tag(const uint64_t nwid,const uint64_t ts,const Address &issuedTo,const uint32_t id,const uint32_t value) :
|
||||
_networkId(nwid),
|
||||
_ts(ts),
|
||||
_id(id),
|
||||
_value(value),
|
||||
_networkId(nwid),
|
||||
_ts(ts),
|
||||
_issuedTo(issuedTo),
|
||||
_signedBy()
|
||||
{
|
||||
}
|
||||
|
||||
inline uint64_t networkId() const { return _networkId; }
|
||||
inline uint64_t timestamp() const { return _ts; }
|
||||
inline uint32_t id() const { return _id; }
|
||||
inline const uint32_t &value() const { return _value; }
|
||||
inline uint64_t networkId() const { return _networkId; }
|
||||
inline uint64_t timestamp() const { return _ts; }
|
||||
inline const Address &issuedTo() const { return _issuedTo; }
|
||||
inline const Address &signedBy() const { return _signedBy; }
|
||||
|
||||
@@ -115,11 +126,9 @@ public:
|
||||
{
|
||||
if (forSign) b.append((uint64_t)0x7f7f7f7f7f7f7f7fULL);
|
||||
|
||||
// These are the same between Tag and Capability
|
||||
b.append(_networkId);
|
||||
b.append(_ts);
|
||||
b.append(_id);
|
||||
|
||||
b.append(_value);
|
||||
|
||||
_issuedTo.appendTo(b);
|
||||
@@ -187,10 +196,10 @@ public:
|
||||
};
|
||||
|
||||
private:
|
||||
uint64_t _networkId;
|
||||
uint64_t _ts;
|
||||
uint32_t _id;
|
||||
uint32_t _value;
|
||||
uint64_t _networkId;
|
||||
uint64_t _ts;
|
||||
Address _issuedTo;
|
||||
Address _signedBy;
|
||||
C25519::Signature _signature;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
* ZeroTier One - Network Virtualization Everywhere
|
||||
* Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/
|
||||
* Copyright (C) 2011-2017 ZeroTier, Inc. https://www.zerotier.com/
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
@@ -14,6 +14,14 @@
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* --
|
||||
*
|
||||
* You can be released from the requirements of the license by purchasing
|
||||
* a commercial license. Buying such a license is mandatory as soon as you
|
||||
* develop commercial closed-source software that incorporates or links
|
||||
* directly against ZeroTier software without disclosing the source code
|
||||
* of your own application.
|
||||
*/
|
||||
|
||||
#include "Constants.hpp"
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user