From 48d20176290bcdaeb6ce288dfd5599f312d80a60 Mon Sep 17 00:00:00 2001 From: Dezhi “Andy” Fang Date: Sun, 6 Aug 2017 02:06:00 -0700 Subject: Add `ppc64le` arch I've only tested locally, on a power8 box running Ubuntu 16.10, but everything (and earth) checks out. Let me know if more testing infrastructure is needed. --- make-linux.mk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/make-linux.mk b/make-linux.mk index 7017d31e..8b0082aa 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -99,6 +99,9 @@ ifeq ($(CC_MACH),amd64) ZT_ARCHITECTURE=2 ZT_USE_X64_ASM_SALSA2012=1 endif +ifeq ($(CC_MACH),powerpc64le) + ZT_ARCHITECTURE=2 +endif ifeq ($(CC_MACH),i386) ZT_ARCHITECTURE=1 endif -- cgit v1.2.3 From 2c682b4d1cdfd64d3a5b931bd0a67abb1f8b731e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 9 Aug 2017 14:37:19 -0700 Subject: Small controller revisions, first run of controller API model JavaScript. --- controller/EmbeddedNetworkController.cpp | 101 ++---- controller/EmbeddedNetworkController.hpp | 5 +- controller/controller-api-model.js | 546 +++++++++++++++++++++++++++++++ 3 files changed, 577 insertions(+), 75 deletions(-) create mode 100644 controller/controller-api-model.js diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 72d47622..764b5c20 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -638,14 +638,10 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( if (newAuth != OSUtils::jsonBool(member["authorized"],false)) { member["authorized"] = newAuth; member[((newAuth) ? "lastAuthorizedTime" : "lastDeauthorizedTime")] = now; - - json ah; - ah["a"] = newAuth; - ah["by"] = "api"; - ah["ts"] = now; - ah["ct"] = json(); - ah["c"] = json(); - member["authHistory"].push_back(ah); + if (newAuth) { + member["lastAuthorizedCredentialType"] = "api"; + member["lastAuthorizedCredential"] = json(); + } // Member is being de-authorized, so spray Revocation objects to all online members if (!newAuth) { @@ -896,22 +892,15 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( if (b.count("authTokens")) { json &authTokens = b["authTokens"]; - if (authTokens.is_array()) { - json nat = json::array(); - for(unsigned long i=0;i 0) { - json t = json::object(); - t["token"] = tstr; - t["expires"] = OSUtils::jsonInt(token["expires"],0ULL); - t["maxUsesPerMember"] = OSUtils::jsonInt(token["maxUsesPerMember"],0ULL); - nat.push_back(t); - } - } + if (authTokens.is_object()) { + json nat; + for(json::iterator t(authTokens.begin());t!=authTokens.end();++t) { + if ((t.value().is_number())&&(t.value() >= 0)) + nat[t.key()] = t.value(); } network["authTokens"] = nat; + } else { + network["authTokens"] = {{}}; } } @@ -1268,56 +1257,29 @@ void EmbeddedNetworkController::_request( } // Determine whether and how member is authorized - const char *authorizedBy = (const char *)0; + bool authorized = false; bool autoAuthorized = false; json autoAuthCredentialType,autoAuthCredential; if (OSUtils::jsonBool(member["authorized"],false)) { - authorizedBy = "memberIsAuthorized"; + authorized = true; } else if (!OSUtils::jsonBool(network["private"],true)) { - authorizedBy = "networkIsPublic"; - json &ahist = member["authHistory"]; - if ((!ahist.is_array())||(ahist.size() == 0)) - autoAuthorized = true; + authorized = true; + autoAuthorized = true; + autoAuthCredentialType = "public"; } else { char presentedAuth[512]; if (metaData.get(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_AUTH,presentedAuth,sizeof(presentedAuth)) > 0) { presentedAuth[511] = (char)0; // sanity check - - // Check for bearer token presented by member if ((strlen(presentedAuth) > 6)&&(!strncmp(presentedAuth,"token:",6))) { const char *const presentedToken = presentedAuth + 6; - - json &authTokens = network["authTokens"]; - if (authTokens.is_array()) { - for(unsigned long i=0;i now))&&(tstr == presentedToken)) { - bool usable = (maxUses == 0); - if (!usable) { - uint64_t useCount = 0; - json &ahist = member["authHistory"]; - if (ahist.is_array()) { - for(unsigned long j=0;j now)) { + authorized = true; + autoAuthorized = true; + autoAuthCredentialType = "token"; + autoAuthCredential = presentedToken; } } } @@ -1325,23 +1287,16 @@ void EmbeddedNetworkController::_request( } // If we auto-authorized, update member record - if ((autoAuthorized)&&(authorizedBy)) { + if ((autoAuthorized)&&(authorized)) { member["authorized"] = true; member["lastAuthorizedTime"] = now; - - json ah; - ah["a"] = true; - ah["by"] = authorizedBy; - ah["ts"] = now; - ah["ct"] = autoAuthCredentialType; - ah["c"] = autoAuthCredential; - member["authHistory"].push_back(ah); - + member["lastAuthorizedCredentialType"] = autoAuthCredentialType; + member["lastAuthorizedCredential"] = autoAuthCredential; json &revj = member["revision"]; member["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); } - if (authorizedBy) { + if (authorized) { // 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); diff --git a/controller/EmbeddedNetworkController.hpp b/controller/EmbeddedNetworkController.hpp index 8752922e..590a8b48 100644 --- a/controller/EmbeddedNetworkController.hpp +++ b/controller/EmbeddedNetworkController.hpp @@ -129,7 +129,6 @@ private: inline void _initMember(nlohmann::json &member) { 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("activeBridge")) member["activeBridge"] = false; if (!member.count("tags")) member["tags"] = nlohmann::json::array(); @@ -139,6 +138,8 @@ 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("lastAuthorizedCredentialType")) member["lastAuthorizedCredentialType"] = nlohmann::json(); + if (!member.count("lastAuthorizedCredential")) member["lastAuthorizedCredential"] = nlohmann::json(); if (!member.count("vMajor")) member["vMajor"] = -1; if (!member.count("vMinor")) member["vMinor"] = -1; if (!member.count("vRev")) member["vRev"] = -1; @@ -156,7 +157,7 @@ private: if (!network.count("enableBroadcast")) network["enableBroadcast"] = true; if (!network.count("v4AssignMode")) network["v4AssignMode"] = {{"zt",false}}; if (!network.count("v6AssignMode")) network["v6AssignMode"] = {{"rfc4193",false},{"zt",false},{"6plane",false}}; - if (!network.count("authTokens")) network["authTokens"] = nlohmann::json::array(); + if (!network.count("authTokens")) network["authTokens"] = {{}}; if (!network.count("capabilities")) network["capabilities"] = nlohmann::json::array(); if (!network.count("tags")) network["tags"] = nlohmann::json::array(); if (!network.count("routes")) network["routes"] = nlohmann::json::array(); diff --git a/controller/controller-api-model.js b/controller/controller-api-model.js new file mode 100644 index 00000000..7b61dff4 --- /dev/null +++ b/controller/controller-api-model.js @@ -0,0 +1,546 @@ +/* + * A JavaScript class based model for the ZeroTier controller microservice API + * 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 . + * + * -- + * + * 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. + */ + +'use strict'; + +/** + * Goes through a rule set array and makes sure it's valid, returning a canonicalized version + * + * @param {array[object]} rules Array of ZeroTier rules + * @return New array of canonicalized rules + * @throws {Error} Rule set is invalid + */ +function formatRuleSetArray(rules) +{ +} +exports.formatRuleSetArray = formatRuleSetArray; + +/** + * @param {string} IP with optional /netmask|port section + * @return 4, 6, or 0 if invalid + */ +function ipClassify(ip) +{ + if ((!ip)||(typeof ip !== 'string')) + return 0; + let ips = ip.split('/'); + if (ips.length > 0) { + if (ips.length > 1) { + if (ips[1].length === 0) + return 0; + for(let i=0;i 0) { + for(let i=0;i 0) { + for(let i=0;i= 0) { + r += c; + if (r.length === l) + break; + } + } + + while (r.length < l) + r = '0' + r; + + return r; +}; +exports.formatZeroTierIdentifier = formatZeroTierIdentifier; + +// Internal container classes +class _V4AssignMode +{ + get zt() { return (this._zt)||false; } + set zt(b) { this._zt = !!b; } + toJSON() + { + return { zt: this.zt }; + } +}; +class _v6AssignMode +{ + get ['6plane'] { return (this._6plane)||false; } + set ['6plane'](b) { this._6plane = !!b; } + get zt() { return (this._zt)||false; } + set zt(b) { this._zt = !!b; } + get rfc4193() { return (this._rfc4193)||false; } + set rfc4193(b) { this._rfc4193 = !!b; } + toJSON() + { + return { + zt: this.zt, + rfc4193: this.rfc4193, + '6plane': this['6plane'] + }; + } +} + +class Network +{ + constructor(obj) + { + this.clear(); + this.patch(obj); + } + + get objtype() { return 'network'; } + + get id() { return this._id; } + set id(x) { return (this._id = formatZeroTierIdentifier(x,16)); } + + get nwid() { return this._id; } // legacy + + get authTokens() { return this._authTokens; } + set authTokens(at) + { + this._authTokens = {}; + if ((at)&&(typeof at === 'object')&&(!Array.isArray(at))) { + for(let k in at) { + let exp = parseInt(at[k])||0; + if (exp >= 0) + this._authTokens[k] = exp; + } + } + return this._authTokens; + } + + get capabilities() { return this._capabilities; } + set capabilities(c) + { + let ca = []; + let ids = {}; + if ((c)&&(Array.isArray(c))) { + for(let a=0;a= 0)&&(capId <= 0xffffffff)&&(!ids[capId])) { + ids[capId] = true; + let capDefault = !!cap['default']; + let capRules = formatRuleSetArray(cap.rules); + ca.push({ + id: capId, + 'default': capDefault, + rules: capRules + }); + } + } + } + } + ca.sort(function(a,b) { + a = a.id; + b = b.id; + return ((a > b) ? 1 : ((a < b) ? -1 : 0)); + }); + this._capabilities = ca; + return ca; + } + + get ipAssignmentPools() return { this._ipAssignmentPools; } + set ipAssignmentPools(ipp) + { + let pa = []; + let ranges = {}; + if ((ipp)&&(Array.isArray(ipp))) { + for(let a=0;a 0)&&(stype === ipClassify(end))&&(!ranges[start+'_'+end])) { + ranges[start+'_'+end] = true; + pa.push({ ipRangeStart: start, ipRangeEnd: end }); + } + } + } + } + } + pa.sort(function(a,b) { return a.ipRangeStart.localeCompare(b.ipRangeStart); }); + this._ipAssignmentPools = pa; + return pa; + } + + get multicastLimit() return { this._multicastLimit; } + set multicastLimit(n) + { + try { + let nn = parseInt(n)||0; + this._multicastLimit = (nn >= 0) ? nn : 0; + } catch (e) { + this._multicastLimit = 0; + } + return this._multicastLimit; + } + + get routes() return { this._routes; } + set routes(r) + { + let ra = []; + let targets = {}; + if ((r)&&(Array.isArray(r))) { + for(let a=0;a 0)&&((routeVia === null)||(ipClassify(routeVia) === rtt))&&(!targets[routeTarget])) { + targets[routeTarget] = true; + ra.push({ target: routeTarget, via: routeVia }); + } + } + } + } + ra.sort(function(a,b) { return a.routeTarget.localeCompare(b.routeTarget); }); + this._routes = ra; + return ra; + } + + get tags() return { this._tags; } + set tags(t) + { + let ta = []; + if ((t)&&(Array.isArray(t))) { + for(let a=0;a= 0)||(tagId <= 0xffffffff)) { + let tagDefault = tag.default; + if (typeof tagDefault !== 'number') + tagDefault = parseInt(tagDefault)||null; + if ((tagDefault < 0)||(tagDefault > 0xffffffff)) + tagDefault = null; + ta.push({ 'id': tagId, 'default': tagDefault }); + } + } + } + } + ta.sort(function(a,b) { + a = a.id; + b = b.id; + return ((a > b) ? 1 : ((a < b) ? -1 : 0)); + }); + this._tags = ta; + return ta; + } + + get v4AssignMode() return { this._v4AssignMode; } + set v4AssignMode(m) + { + if ((m)&&(typeof m === 'object')&&(!Array.isArray(m))) { + this._v4AssignMode.zt = m.zt; + } else if (m === 'zt') { // legacy + this._v4AssignMode.zt = true; + } else { + this._v4AssignMode.zt = false; + } + } + + get v6AssignMode() return { this._v6AssignMode; } + set v6AssignMode(m) + { + if ((m)&&(typeof m === 'object')&&(!Array.isArray(m))) { + this._v6AssignMode.zt = m.zt; + this._v6AssignMode.rfc4193 = m.rfc4193; + this._v6AssignMode['6plane'] = m['6plane']; + } else if (typeof m === 'string') { // legacy + let ms = m.split(','); + this._v6AssignMode.zt = false; + this._v6AssignMode.rfc4193 = false; + this._v6AssignMode['6plane'] = false; + for(let i=0;i= 10000) mtu = 10000; // maximum as per ZT spec + this._mtu = mtu; + } + + get name() { return this._name; } + set name(n) + { + if (typeof n === 'string') + this._name = n; + else if (typeof n === 'number') + this._name = n.toString(); + else this._name = ''; + } + + get private() { return this._private; } + set private(b) + { + // This is really meaningful for security, so make true unless explicitly set to false. + this._private = (b !== false); + } + + get activeMemberCount() { return this.__activeMemberCount; } + get authorizedMemberCount() { return this.__authorizedMemberCount; } + get totalMemberCount() { return this.__totalMemberCount; } + get clock() { return this.__clock; } + get creationTime() { return this.__creationTime; } + get revision() { return this.__revision; } + + toJSONExcludeControllerGenerated() + { + return { + id: this.id, + objtype: 'network', + nwid: this.nwid, + authTokens: this.authTokens, + capabilities: this.capabilities, + ipAssignmentPools: this.ipAssignmentPools, + multicastLimit: this.multicastLimit, + routes: this.routes, + tags: this.tags, + v4AssignMode: this._v4AssignMode.toJSON(), + v6AssignMode: this._v6AssignMode.toJSON(), + rules: this.rules, + enableBroadcast: this.enableBroadcast, + mtu: this.mtu, + name: this.name, + 'private': this['private'] + }; + } + + toJSON() + { + var j = this.toJSONExcludeControllerGenerated(); + j.activeMemberCount = this.activeMemberCount; + j.authorizedMemberCount = this.authorizedMemberCount; + j.totalMemberCount = this.totalMemberCount; + j.clock = this.clock; + j.creationTime = this.creationTime; + j.revision = this.revision; + return j; + } + + clear() + { + this._id = ''; + this._authTokens = {}; + this._capabilities = []; + this._ipAssignmentPools = []; + this._multicastLimit = 32; + this._routes = []; + this._tags = []; + this._v4AssignMode = new _V4AssignMode(); + this._v6AssignMode = new _v6AssignMode(); + this._rules = []; + this._enableBroadcast = true; + this._mtu = 2800; + this._name = ''; + this._private = true; + + this.__activeMemberCount = 0; + this.__authorizedMemberCount = 0; + this.__totalMemberCount = 0; + this.__clock = 0; + this.__creationTime = 0; + this.__revision = 0; + } + + patch(obj) + { + if (obj instanceof Network) + obj = obj.toJSON(); + if ((obj)&&(typeof obj === 'object')&&(!Array.isArray(obj))) { + for(var k in obj) { + try { + switch(k) { + case 'id': + case 'authTokens': + case 'capabilities': + case 'ipAssignmentPools': + case 'multicastLimit': + case 'routes': + case 'tags': + case 'rules': + case 'enableBroadcast': + case 'mtu': + case 'name': + case 'private': + case 'v4AssignMode': + case 'v6AssignMode': + this[k] = obj[k]; + break; + + case 'activeMemberCount': + case 'authorizedMemberCount': + case 'totalMemberCount': + case 'clock': + case 'creationTime': + case 'revision': + this['__'+k] = parseInt(obj[k])||0; + break; + } + } catch (e) {} + } + } + } +}; +exports.Network = Network; + +class Member +{ + constructor(obj) + { + this.clear(); + this.patch(obj); + } + + get objtype() { return 'member'; } + + get id() { return this._id; } + set id(x) { this._id = formatZeroTierIdentifier((typeof x === 'number') ? x.toString(16) : x,10); } + + get address() { return this._id; } // legacy + + get nwid() { return this._nwid; } + set nwid(x) { this._nwid = formatZeroTierIdentifier(x,16); } + + get controllerId() { return this.nwid.substr(0,10); } + + get authorized() { return this._authorized; } + set authorized(b) { this._authorized = (b === true); } // security critical so require explicit set to true + + get activeBridge() { return this._activeBridge; } + set activeBridge(b) { this._activeBridge = !!b; } + + get capabilities() { return this._capabilities; } + set capabilities(c) + { + } + + get identity() { return this._identity; } + set identity(istr) + { + if ((istr)&&(typeof istr === 'string')) + this._identity = istr; + else this._identity = null; + } + + get ipAssignments() { return this._ipAssignments; } + set ipAssignments(ipa) + { + } + + get noAutoAssignIps() { return this._noAutoAssignIps; } + set noAutoAssignIps(b) { this._noAutoAssignIps = !!b; } + + get tags() { return this._tags; } + set tags(t) + { + } + + clear() + { + this._id = ''; + this._nwid = ''; + this._authorized = false; + this._activeBridge = false; + this._capabilities = []; + this._identity = ''; + this._ipAssignments = []; + this._noAutoAssignIps = false; + this._tags = []; + + this.__creationTime = 0; + this.__lastAuthorizedTime = 0; + this.__lastAuthorizedCredentialType = null; + this.__lastAuthorizedCredential = null; + this.__lastDeauthorizedTime = 0; + this.__physicalAddr = ''; + this.__revision = 0; + this.__vMajor = 0; + this.__vMinor = 0; + this.__vRev = 0; + this.__vProto = 0; + } +}; +exports.Member = Member; -- cgit v1.2.3 From 1c04cc0485c58f4f84e75d090025ead2c0f8202d Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 9 Aug 2017 17:42:35 -0700 Subject: . --- controller/controller-api-model.js | 286 ++++++++++++++++++++++++++++++++++--- 1 file changed, 267 insertions(+), 19 deletions(-) diff --git a/controller/controller-api-model.js b/controller/controller-api-model.js index 7b61dff4..fbc808c0 100644 --- a/controller/controller-api-model.js +++ b/controller/controller-api-model.js @@ -26,18 +26,6 @@ 'use strict'; -/** - * Goes through a rule set array and makes sure it's valid, returning a canonicalized version - * - * @param {array[object]} rules Array of ZeroTier rules - * @return New array of canonicalized rules - * @throws {Error} Rule set is invalid - */ -function formatRuleSetArray(rules) -{ -} -exports.formatRuleSetArray = formatRuleSetArray; - /** * @param {string} IP with optional /netmask|port section * @return 4, 6, or 0 if invalid @@ -103,6 +91,135 @@ function formatZeroTierIdentifier(x,l) }; exports.formatZeroTierIdentifier = formatZeroTierIdentifier; +/** + * Goes through a rule set array and makes sure it's valid, returning a canonicalized version + * + * @param {array[object]} rules Array of ZeroTier rules + * @return New array of canonicalized rules + * @throws {Error} Rule set is invalid + */ +function formatRuleSetArray(rules) +{ + let r = []; + if ((rules)&&(Array.isArray(rules))) { + for(let a=0;a= 0)&&(capId <= 0xffffffff)&&(!caps[capId])) { + caps[capId] = true; + ca.push(capId); + } + } + } + ca.sort(); + this._capabilities = ca; + return ca; } get identity() { return this._identity; } @@ -508,6 +639,17 @@ class Member get ipAssignments() { return this._ipAssignments; } set ipAssignments(ipa) { + let ips = {}; + if ((ipa)&&(Array.isArray(ipa))) { + for(let a=0;a 0) + ips[ip] = true; + } + } + this._ipAssignments = Object.keys(ips); + this._ipAssignments.sort(); + return this._ipAssignments; } get noAutoAssignIps() { return this._noAutoAssignIps; } @@ -516,6 +658,73 @@ class Member get tags() { return this._tags; } set tags(t) { + let ta = []; + let pairs = {}; + if ((t)&&(Array.isArray(t))) { + for(let a=0;a= 0)&&(tagId <= 0xffffffff)&&(tagValue >= 0)&&(tagValue <= 0xffffffff)&&(!pairs[pk])) { + pairs[pk] = true; + ta.push([ tagId,tagValue ]); + } + } + } + } + ta.sort(function(a,b) { + return ((a[0] < b[0]) ? -1 : ((a[0] > b[0]) ? 1 : 0)); + }); + this._tags = ta; + return ta; + } + + get creationTime() { return this.__creationTime; } + get lastAuthorizedTime() { return this.__lastAuthorizedTime; } + get lastAuthorizedCredentialType() { return this.__lastAuthorizedCredentialType; } + get lastAuthorizedCredential() { return this.__lastAuthorizedCredential; } + get lastDeauthorizedTime() { return this.__lastDeauthorizedTime; } + get physicalAddr() { return this.__physicalAddr; } + get revision() { return this.__revision; } + get vMajor() { return this.__vMajor; } + get vMinor() { return this.__vMinor; } + get vRev() { return this.__vRev; } + get vProto() { return this.__vProto; } + + toJSONExcludeControllerGenerated() + { + return { + id: this.id, + nwid: this.nwid, + objtype: 'member', + address: this.id, + authorized: this.authorized, + activeBridge: this.activeBridge, + capabilities: this.capabilities, + identity: this.identity, + ipAssignments: this.ipAssignments, + noAutoAssignIps: this.noAutoAssignIps, + tags: this.tags + }; + } + + toJSON() + { + let j = this.toJSONExcludeControllerGenerated(); + j.creationTime = this.creationTime; + j.lastAuthorizedTime = this.lastAuthorizedTime; + j.lastAuthorizedCredentialType = this.lastAuthorizedCredentialType; + j.lastAuthorizedCredential = this.lastAuthorizedCredential; + j.lastDeauthorizedTime = this.lastDeauthorizedTime; + j.physicalAddr = this.physicalAddr; + j.revision = this.revision; + j.vMajor = this.vMajor; + j.vMinor = this.vMinor; + j.vRev = this.vRev; + j.vProto = this.vProto; + return j; } clear() @@ -542,5 +751,44 @@ class Member this.__vRev = 0; this.__vProto = 0; } + + patch(obj) + { + if (obj instanceof Member) + obj = obj.toJSON(); + if ((obj)&&(typeof obj === 'object')&&(!Array.isArray(obj))) { + for(var k in obj) { + try { + switch(k) { + case 'id': + case 'nwid': + case 'authorized': + case 'activeBridge': + case 'capabilities': + case 'identity': + case 'ipAssignments': + case 'noAutoAssignIps': + case 'tags': + this[k] = obj[k]; + break; + + case 'creationTime': + case 'lastAuthorizedTime': + case 'lastAuthorizedCredentialType': + case 'lastAuthorizedCredential': + case 'lastDeauthorizedTime': + case 'physicalAddr': + case 'revision': + case 'vMajor': + case 'vMinor': + case 'vRev': + case 'vProto': + this['__'+k] = parseInt(obj[k])||0; + break; + } + } catch (e) {} + } + } + } }; exports.Member = Member; -- cgit v1.2.3 From ee1dc16e8ffc5c5cc8f3b5da97cf2d01c7604ab7 Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Thu, 10 Aug 2017 00:59:15 -0700 Subject: Added getRoutes() for libzt --- service/OneService.cpp | 26 ++++++-------------------- service/OneService.hpp | 3 +-- 2 files changed, 7 insertions(+), 22 deletions(-) diff --git a/service/OneService.cpp b/service/OneService.cpp index 27f2ef3c..ab3b8d73 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -925,29 +925,15 @@ public: return _homePath; } - virtual EthernetTap * getTap(uint64_t nwid) + std::vector *getRoutes(uint64_t nwid) { Mutex::Lock _l(_nets_m); - std::map::const_iterator n(_nets.find(nwid)); - if (n == _nets.end()) - return NULL; - return n->second.tap; - } - - virtual EthernetTap *getTap(InetAddress &addr) - { - Mutex::Lock _l(_nets_m); - std::map::iterator it; - for(it = _nets.begin(); it != _nets.end(); it++) { - if(it->second.tap) { - for(int j=0; jsecond.tap->_ips.size(); j++) { - if(it->second.tap->_ips[j].isEqualPrefix(addr) || it->second.tap->_ips[j].ipsEqual(addr) || it->second.tap->_ips[j].containsAddress(addr)) { - return it->second.tap; - } - } - } + NetworkState &n = _nets[nwid]; + std::vector *routes = new std::vector(); + for(int i=0; ipush_back(n.config.routes[i]); } - return NULL; + return routes; } virtual Node *getNode() diff --git a/service/OneService.hpp b/service/OneService.hpp index eba10ca0..0d37ec63 100644 --- a/service/OneService.hpp +++ b/service/OneService.hpp @@ -150,10 +150,9 @@ public: virtual void leave(const char *hp) = 0; virtual void join(const char *hp) = 0; virtual std::string givenHomePath() = 0; - virtual EthernetTap * getTap(uint64_t nwid) = 0; - virtual EthernetTap * getTap(InetAddress &addr) = 0; virtual Node * getNode() = 0; virtual void removeNets() = 0; + virtual std::vector *getRoutes(uint64_t nwid) = 0; #endif /** -- cgit v1.2.3 From a4bc40542bf11a6688b5e0e8aa0e06a7bc4fe544 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 14 Aug 2017 11:43:39 -0700 Subject: GCC/G++ build fixes, GitHub issue #563 --- node/AtomicCounter.hpp | 2 +- node/Node.cpp | 2 +- osdep/Binder.hpp | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/node/AtomicCounter.hpp b/node/AtomicCounter.hpp index abb342fe..34b58e91 100644 --- a/node/AtomicCounter.hpp +++ b/node/AtomicCounter.hpp @@ -50,7 +50,7 @@ public: inline int load() const { #ifdef __GNUC__ - return __sync_or_and_fetch(&_v,0); + return __sync_or_and_fetch(const_cast(&_v),0); #else return _v.load(); #endif diff --git a/node/Node.cpp b/node/Node.cpp index 0df3a97a..366ddbf0 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -100,7 +100,7 @@ Node::Node(void *uptr,void *tptr,const struct ZT_Node_Callbacks *callbacks,uint6 } else { idtmp[0] = RR->identity.address().toInt(); idtmp[1] = 0; n = stateObjectGet(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,tmp,sizeof(tmp) - 1); - if ((n > 0)&&(n < sizeof(RR->publicIdentityStr))&&(n < sizeof(tmp))) { + if ((n > 0)&&(n < (int)sizeof(RR->publicIdentityStr))&&(n < (int)sizeof(tmp))) { if (memcmp(tmp,RR->publicIdentityStr,n)) stateObjectPut(tptr,ZT_STATE_OBJECT_IDENTITY_PUBLIC,idtmp,RR->publicIdentityStr,(unsigned int)strlen(RR->publicIdentityStr)); } diff --git a/osdep/Binder.hpp b/osdep/Binder.hpp index 17a0fbf6..e3c2dc02 100644 --- a/osdep/Binder.hpp +++ b/osdep/Binder.hpp @@ -227,7 +227,7 @@ public: case InetAddress::IP_SCOPE_GLOBAL: case InetAddress::IP_SCOPE_SHARED: case InetAddress::IP_SCOPE_PRIVATE: - for(int x=0;x(ip,std::string(devname))); } @@ -268,7 +268,7 @@ public: case InetAddress::IP_SCOPE_GLOBAL: case InetAddress::IP_SCOPE_SHARED: case InetAddress::IP_SCOPE_PRIVATE: - for(int x=0;x(ip,ifname)); } @@ -302,7 +302,7 @@ public: case InetAddress::IP_SCOPE_GLOBAL: case InetAddress::IP_SCOPE_SHARED: case InetAddress::IP_SCOPE_PRIVATE: - for(int x=0;x(ip,std::string(ifa->ifa_name))); } -- cgit v1.2.3 From 23fe8975e722ec0141be9c9bea9437b59e6088fa Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Mon, 14 Aug 2017 11:44:07 -0700 Subject: . --- controller/controller-api-model.js | 794 ------------------------------------- 1 file changed, 794 deletions(-) delete mode 100644 controller/controller-api-model.js diff --git a/controller/controller-api-model.js b/controller/controller-api-model.js deleted file mode 100644 index fbc808c0..00000000 --- a/controller/controller-api-model.js +++ /dev/null @@ -1,794 +0,0 @@ -/* - * A JavaScript class based model for the ZeroTier controller microservice API - * 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 . - * - * -- - * - * 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. - */ - -'use strict'; - -/** - * @param {string} IP with optional /netmask|port section - * @return 4, 6, or 0 if invalid - */ -function ipClassify(ip) -{ - if ((!ip)||(typeof ip !== 'string')) - return 0; - let ips = ip.split('/'); - if (ips.length > 0) { - if (ips.length > 1) { - if (ips[1].length === 0) - return 0; - for(let i=0;i 0) { - for(let i=0;i 0) { - for(let i=0;i= 0) { - r += c; - if (r.length === l) - break; - } - } - - while (r.length < l) - r = '0' + r; - - return r; -}; -exports.formatZeroTierIdentifier = formatZeroTierIdentifier; - -/** - * Goes through a rule set array and makes sure it's valid, returning a canonicalized version - * - * @param {array[object]} rules Array of ZeroTier rules - * @return New array of canonicalized rules - * @throws {Error} Rule set is invalid - */ -function formatRuleSetArray(rules) -{ - let r = []; - if ((rules)&&(Array.isArray(rules))) { - for(let a=0;a= 0) - this._authTokens[k] = exp; - } - } - return this._authTokens; - } - - get capabilities() { return this._capabilities; } - set capabilities(c) - { - let ca = []; - let ids = {}; - if ((c)&&(Array.isArray(c))) { - for(let a=0;a= 0)&&(capId <= 0xffffffff)&&(!ids[capId])) { - ids[capId] = true; - let capDefault = !!cap['default']; - let capRules = formatRuleSetArray(cap.rules); - ca.push({ - id: capId, - 'default': capDefault, - rules: capRules - }); - } - } - } - } - ca.sort(function(a,b) { - a = a.id; - b = b.id; - return ((a > b) ? 1 : ((a < b) ? -1 : 0)); - }); - this._capabilities = ca; - return ca; - } - - get ipAssignmentPools() { return this._ipAssignmentPools; } - set ipAssignmentPools(ipp) - { - let pa = []; - let ranges = {}; - if ((ipp)&&(Array.isArray(ipp))) { - for(let a=0;a 0)&&(stype === ipClassify(end))&&(!ranges[start+'_'+end])) { - ranges[start+'_'+end] = true; - pa.push({ ipRangeStart: start, ipRangeEnd: end }); - } - } - } - } - } - pa.sort(function(a,b) { return a.ipRangeStart.localeCompare(b.ipRangeStart); }); - this._ipAssignmentPools = pa; - return pa; - } - - get multicastLimit() { return this._multicastLimit; } - set multicastLimit(n) - { - try { - let nn = parseInt(n)||0; - this._multicastLimit = (nn >= 0) ? nn : 0; - } catch (e) { - this._multicastLimit = 0; - } - return this._multicastLimit; - } - - get routes() { return this._routes; } - set routes(r) - { - let ra = []; - let targets = {}; - if ((r)&&(Array.isArray(r))) { - for(let a=0;a 0)&&((routeVia === null)||(ipClassify(routeVia) === rtt))&&(!targets[routeTarget])) { - targets[routeTarget] = true; - ra.push({ target: routeTarget, via: routeVia }); - } - } - } - } - ra.sort(function(a,b) { return a.routeTarget.localeCompare(b.routeTarget); }); - this._routes = ra; - return ra; - } - - get tags() { return this._tags; } - set tags(t) - { - let ta = []; - if ((t)&&(Array.isArray(t))) { - for(let a=0;a= 0)||(tagId <= 0xffffffff)) { - let tagDefault = tag.default; - if (typeof tagDefault !== 'number') - tagDefault = parseInt(tagDefault)||null; - if ((tagDefault < 0)||(tagDefault > 0xffffffff)) - tagDefault = null; - ta.push({ 'id': tagId, 'default': tagDefault }); - } - } - } - } - ta.sort(function(a,b) { - a = a.id; - b = b.id; - return ((a > b) ? 1 : ((a < b) ? -1 : 0)); - }); - this._tags = ta; - return ta; - } - - get v4AssignMode() { return this._v4AssignMode; } - set v4AssignMode(m) - { - if ((m)&&(typeof m === 'object')&&(!Array.isArray(m))) { - this._v4AssignMode.zt = m.zt; - } else if (m === 'zt') { // legacy - this._v4AssignMode.zt = true; - } else { - this._v4AssignMode.zt = false; - } - } - - get v6AssignMode() { return this._v6AssignMode; } - set v6AssignMode(m) - { - if ((m)&&(typeof m === 'object')&&(!Array.isArray(m))) { - this._v6AssignMode.zt = m.zt; - this._v6AssignMode.rfc4193 = m.rfc4193; - this._v6AssignMode['6plane'] = m['6plane']; - } else if (typeof m === 'string') { // legacy - let ms = m.split(','); - this._v6AssignMode.zt = false; - this._v6AssignMode.rfc4193 = false; - this._v6AssignMode['6plane'] = false; - for(let i=0;i= 10000) mtu = 10000; // maximum as per ZT spec - this._mtu = mtu; - } - - get name() { return this._name; } - set name(n) - { - if (typeof n === 'string') - this._name = n; - else if (typeof n === 'number') - this._name = n.toString(); - else this._name = ''; - } - - get private() { return this._private; } - set private(b) - { - // This is really meaningful for security, so make true unless explicitly set to false. - this._private = (b !== false); - } - - get activeMemberCount() { return this.__activeMemberCount; } - get authorizedMemberCount() { return this.__authorizedMemberCount; } - get totalMemberCount() { return this.__totalMemberCount; } - get clock() { return this.__clock; } - get creationTime() { return this.__creationTime; } - get revision() { return this.__revision; } - - toJSONExcludeControllerGenerated() - { - return { - id: this.id, - objtype: 'network', - nwid: this.nwid, - authTokens: this.authTokens, - capabilities: this.capabilities, - ipAssignmentPools: this.ipAssignmentPools, - multicastLimit: this.multicastLimit, - routes: this.routes, - tags: this.tags, - v4AssignMode: this._v4AssignMode.toJSON(), - v6AssignMode: this._v6AssignMode.toJSON(), - rules: this.rules, - enableBroadcast: this.enableBroadcast, - mtu: this.mtu, - name: this.name, - 'private': this['private'] - }; - } - - toJSON() - { - var j = this.toJSONExcludeControllerGenerated(); - j.activeMemberCount = this.activeMemberCount; - j.authorizedMemberCount = this.authorizedMemberCount; - j.totalMemberCount = this.totalMemberCount; - j.clock = this.clock; - j.creationTime = this.creationTime; - j.revision = this.revision; - return j; - } - - clear() - { - this._id = ''; - this._authTokens = {}; - this._capabilities = []; - this._ipAssignmentPools = []; - this._multicastLimit = 32; - this._routes = []; - this._tags = []; - this._v4AssignMode = new _V4AssignMode(); - this._v6AssignMode = new _v6AssignMode(); - this._rules = []; - this._enableBroadcast = true; - this._mtu = 2800; - this._name = ''; - this._private = true; - - this.__activeMemberCount = 0; - this.__authorizedMemberCount = 0; - this.__totalMemberCount = 0; - this.__clock = 0; - this.__creationTime = 0; - this.__revision = 0; - } - - patch(obj) - { - if (obj instanceof Network) - obj = obj.toJSON(); - if ((obj)&&(typeof obj === 'object')&&(!Array.isArray(obj))) { - for(var k in obj) { - try { - switch(k) { - case 'id': - case 'authTokens': - case 'capabilities': - case 'ipAssignmentPools': - case 'multicastLimit': - case 'routes': - case 'tags': - case 'rules': - case 'enableBroadcast': - case 'mtu': - case 'name': - case 'private': - case 'v4AssignMode': - case 'v6AssignMode': - this[k] = obj[k]; - break; - - case 'activeMemberCount': - case 'authorizedMemberCount': - case 'totalMemberCount': - case 'clock': - case 'creationTime': - case 'revision': - this['__'+k] = parseInt(obj[k])||0; - break; - } - } catch (e) {} - } - } - } -}; -exports.Network = Network; - -class Member -{ - constructor(obj) - { - this.clear(); - this.patch(obj); - } - - get objtype() { return 'member'; } - - get id() { return this._id; } - set id(x) { this._id = formatZeroTierIdentifier((typeof x === 'number') ? x.toString(16) : x,10); } - - get address() { return this._id; } // legacy - - get nwid() { return this._nwid; } - set nwid(x) { this._nwid = formatZeroTierIdentifier(x,16); } - - get controllerId() { return this.nwid.substr(0,10); } - - get authorized() { return this._authorized; } - set authorized(b) { this._authorized = (b === true); } // security critical so require explicit set to true - - get activeBridge() { return this._activeBridge; } - set activeBridge(b) { this._activeBridge = !!b; } - - get capabilities() { return this._capabilities; } - set capabilities(c) - { - let caps = {}; - let ca = []; - if ((c)&&(Array.isArray(c))) { - for(let a=0;a= 0)&&(capId <= 0xffffffff)&&(!caps[capId])) { - caps[capId] = true; - ca.push(capId); - } - } - } - ca.sort(); - this._capabilities = ca; - return ca; - } - - get identity() { return this._identity; } - set identity(istr) - { - if ((istr)&&(typeof istr === 'string')) - this._identity = istr; - else this._identity = null; - } - - get ipAssignments() { return this._ipAssignments; } - set ipAssignments(ipa) - { - let ips = {}; - if ((ipa)&&(Array.isArray(ipa))) { - for(let a=0;a 0) - ips[ip] = true; - } - } - this._ipAssignments = Object.keys(ips); - this._ipAssignments.sort(); - return this._ipAssignments; - } - - get noAutoAssignIps() { return this._noAutoAssignIps; } - set noAutoAssignIps(b) { this._noAutoAssignIps = !!b; } - - get tags() { return this._tags; } - set tags(t) - { - let ta = []; - let pairs = {}; - if ((t)&&(Array.isArray(t))) { - for(let a=0;a= 0)&&(tagId <= 0xffffffff)&&(tagValue >= 0)&&(tagValue <= 0xffffffff)&&(!pairs[pk])) { - pairs[pk] = true; - ta.push([ tagId,tagValue ]); - } - } - } - } - ta.sort(function(a,b) { - return ((a[0] < b[0]) ? -1 : ((a[0] > b[0]) ? 1 : 0)); - }); - this._tags = ta; - return ta; - } - - get creationTime() { return this.__creationTime; } - get lastAuthorizedTime() { return this.__lastAuthorizedTime; } - get lastAuthorizedCredentialType() { return this.__lastAuthorizedCredentialType; } - get lastAuthorizedCredential() { return this.__lastAuthorizedCredential; } - get lastDeauthorizedTime() { return this.__lastDeauthorizedTime; } - get physicalAddr() { return this.__physicalAddr; } - get revision() { return this.__revision; } - get vMajor() { return this.__vMajor; } - get vMinor() { return this.__vMinor; } - get vRev() { return this.__vRev; } - get vProto() { return this.__vProto; } - - toJSONExcludeControllerGenerated() - { - return { - id: this.id, - nwid: this.nwid, - objtype: 'member', - address: this.id, - authorized: this.authorized, - activeBridge: this.activeBridge, - capabilities: this.capabilities, - identity: this.identity, - ipAssignments: this.ipAssignments, - noAutoAssignIps: this.noAutoAssignIps, - tags: this.tags - }; - } - - toJSON() - { - let j = this.toJSONExcludeControllerGenerated(); - j.creationTime = this.creationTime; - j.lastAuthorizedTime = this.lastAuthorizedTime; - j.lastAuthorizedCredentialType = this.lastAuthorizedCredentialType; - j.lastAuthorizedCredential = this.lastAuthorizedCredential; - j.lastDeauthorizedTime = this.lastDeauthorizedTime; - j.physicalAddr = this.physicalAddr; - j.revision = this.revision; - j.vMajor = this.vMajor; - j.vMinor = this.vMinor; - j.vRev = this.vRev; - j.vProto = this.vProto; - return j; - } - - clear() - { - this._id = ''; - this._nwid = ''; - this._authorized = false; - this._activeBridge = false; - this._capabilities = []; - this._identity = ''; - this._ipAssignments = []; - this._noAutoAssignIps = false; - this._tags = []; - - this.__creationTime = 0; - this.__lastAuthorizedTime = 0; - this.__lastAuthorizedCredentialType = null; - this.__lastAuthorizedCredential = null; - this.__lastDeauthorizedTime = 0; - this.__physicalAddr = ''; - this.__revision = 0; - this.__vMajor = 0; - this.__vMinor = 0; - this.__vRev = 0; - this.__vProto = 0; - } - - patch(obj) - { - if (obj instanceof Member) - obj = obj.toJSON(); - if ((obj)&&(typeof obj === 'object')&&(!Array.isArray(obj))) { - for(var k in obj) { - try { - switch(k) { - case 'id': - case 'nwid': - case 'authorized': - case 'activeBridge': - case 'capabilities': - case 'identity': - case 'ipAssignments': - case 'noAutoAssignIps': - case 'tags': - this[k] = obj[k]; - break; - - case 'creationTime': - case 'lastAuthorizedTime': - case 'lastAuthorizedCredentialType': - case 'lastAuthorizedCredential': - case 'lastDeauthorizedTime': - case 'physicalAddr': - case 'revision': - case 'vMajor': - case 'vMinor': - case 'vRev': - case 'vProto': - this['__'+k] = parseInt(obj[k])||0; - break; - } - } catch (e) {} - } - } - } -}; -exports.Member = Member; -- cgit v1.2.3 From 59b7cbb591b8f9ed4abfc25773619d6b1bebc4d2 Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Tue, 15 Aug 2017 16:22:28 -0700 Subject: Rename SocketTap to VirtualTap to prevent confusion on role --- service/OneService.cpp | 4 ++-- service/OneService.hpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/service/OneService.cpp b/service/OneService.cpp index ab3b8d73..c3bf9fee 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -99,8 +99,8 @@ namespace ZeroTier { typedef TestEthernetTap EthernetTap; } #include "../controller/EmbeddedNetworkController.hpp" #include "../node/Node.hpp" // Use the virtual netcon endpoint instead of a tun/tap port driver -#include "../src/SocketTap.hpp" -namespace ZeroTier { typedef SocketTap EthernetTap; } +#include "../src/VirtualTap.hpp" +namespace ZeroTier { typedef VirtualTap EthernetTap; } #else diff --git a/service/OneService.hpp b/service/OneService.hpp index 0d37ec63..b0467419 100644 --- a/service/OneService.hpp +++ b/service/OneService.hpp @@ -35,8 +35,8 @@ #ifdef ZT_SDK #include "../node/Node.hpp" // Use the virtual netcon endpoint instead of a tun/tap port driver -#include "../src/SocketTap.hpp" -namespace ZeroTier { typedef SocketTap EthernetTap; } +#include "../src/VirtualTap.hpp" +namespace ZeroTier { typedef VirtualTap EthernetTap; } #endif namespace ZeroTier { -- cgit v1.2.3 From 50e7ea088b16314c8ad9d10757204c966155f157 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 16 Aug 2017 14:14:49 -0700 Subject: More work on controller for new Central harnessed mode, remove old http mode. --- controller/EmbeddedNetworkController.cpp | 42 ++++--- controller/EmbeddedNetworkController.hpp | 4 + controller/JSONDB.cpp | 208 +++++++++++-------------------- controller/JSONDB.hpp | 7 +- 4 files changed, 106 insertions(+), 155 deletions(-) diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 764b5c20..257fef57 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -35,6 +35,7 @@ #include #include "../include/ZeroTierOne.h" +#include "../version.h" #include "../node/Constants.hpp" #include "EmbeddedNetworkController.hpp" @@ -430,7 +431,7 @@ EmbeddedNetworkController::EmbeddedNetworkController(Node *node,const char *dbPa _startTime(OSUtils::now()), _running(true), _lastDumpedStatus(0), - _db(dbPath), + _db(dbPath,this), _node(node) { } @@ -720,14 +721,6 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( json &revj = member["revision"]; member["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); _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 ( ... ) {} } _addMemberNonPersistedFields(nwid,address,member,now); @@ -980,13 +973,6 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( json &revj = network["revision"]; network["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); _db.saveNetwork(nwid,network); - - // 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); - } } JSONDB::NetworkSummaryInfo ns; @@ -1144,6 +1130,28 @@ void EmbeddedNetworkController::handleRemoteTrace(const ZT_RemoteTrace &rt) } } +void EmbeddedNetworkController::onNetworkUpdate(const uint64_t networkId) +{ + // Send an update to all members of the network that are online + const uint64_t now = OSUtils::now(); + Mutex::Lock _l(_memberStatus_m); + for(auto i=_memberStatus.begin();i!=_memberStatus.end();++i) { + if ((i->first.networkId == networkId)&&(i->second.online(now))&&(i->second.lastRequestMetaData)) + request(networkId,InetAddress(),0,i->second.identity,i->second.lastRequestMetaData); + } +} + +void EmbeddedNetworkController::onNetworkMemberUpdate(const uint64_t networkId,const uint64_t memberId) +{ + // Push update to member if online + try { + Mutex::Lock _l(_memberStatus_m); + _MemberStatus &ms = _memberStatus[_MemberStatusKey(networkId,memberId)]; + if ((ms.online(OSUtils::now()))&&(ms.lastRequestMetaData)) + request(networkId,InetAddress(),0,ms.identity,ms.lastRequestMetaData); + } catch ( ... ) {} +} + void EmbeddedNetworkController::threadMain() throw() { @@ -1184,7 +1192,7 @@ void EmbeddedNetworkController::threadMain() first = false; }); } - OSUtils::ztsnprintf(tmp,sizeof(tmp),"],\"clock\":%llu,\"startTime\":%llu,\"uptime\":%llu}",(unsigned long long)now,(unsigned long long)_startTime,(unsigned long long)(now - _startTime)); + OSUtils::ztsnprintf(tmp,sizeof(tmp),"],\"clock\":%llu,\"startTime\":%llu,\"uptime\":%llu,\"vMajor\":%d,\"vMinor\":%d,\"vRev\":%d}",(unsigned long long)now,(unsigned long long)_startTime,(unsigned long long)(now - _startTime),ZEROTIER_ONE_VERSION_MAJOR,ZEROTIER_ONE_VERSION_MINOR,ZEROTIER_ONE_VERSION_REVISION); st.append(tmp); _db.writeRaw("status",st); } diff --git a/controller/EmbeddedNetworkController.hpp b/controller/EmbeddedNetworkController.hpp index 590a8b48..6200e910 100644 --- a/controller/EmbeddedNetworkController.hpp +++ b/controller/EmbeddedNetworkController.hpp @@ -93,6 +93,10 @@ public: void handleRemoteTrace(const ZT_RemoteTrace &rt); + // Called by JSONDB when networks and network members are changed + void onNetworkUpdate(const uint64_t networkId); + void onNetworkMemberUpdate(const uint64_t networkId,const uint64_t memberId); + void threadMain() throw(); diff --git a/controller/JSONDB.cpp b/controller/JSONDB.cpp index 4b6824c2..a0dd50c2 100644 --- a/controller/JSONDB.cpp +++ b/controller/JSONDB.cpp @@ -29,75 +29,44 @@ #endif #include "JSONDB.hpp" - -#define ZT_JSONDB_HTTP_TIMEOUT 60000 +#include "EmbeddedNetworkController.hpp" namespace ZeroTier { static const nlohmann::json _EMPTY_JSON(nlohmann::json::object()); -static const std::map _ZT_JSONDB_GET_HEADERS; -JSONDB::JSONDB(const std::string &basePath) : +JSONDB::JSONDB(const std::string &basePath,EmbeddedNetworkController *parent) : + _parent(parent), _basePath(basePath), _rawInput(-1), _rawOutput(-1), _summaryThreadRun(true), _dataReady(false) { - if ((_basePath.length() > 7)&&(_basePath.substr(0,7) == "http://")) { - // If base path is http:// we run in HTTP mode - // 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.c_str()); - if (hnend != std::string::npos) - _basePath = _basePath.substr(7 + hnend); - if (_basePath.length() == 0) - _basePath = "/"; - if (_basePath[0] != '/') - _basePath = std::string("/") + _basePath; #ifndef __WINDOWS__ - } else if (_basePath == "-") { - // If base path is "-" we run in stdin/stdout mode and expect our database to be populated on startup via stdin - // Not supported on Windows + if (_basePath == "-") { + // If base path is "-" we run in Central harnessed mode. We read pseudo-http-requests from stdin and write + // them to stdout. _rawInput = STDIN_FILENO; _rawOutput = STDOUT_FILENO; fcntl(_rawInput,F_SETFL,O_NONBLOCK); -#endif } else { +#endif // Default mode of operation is to store files in the filesystem OSUtils::mkdir(_basePath.c_str()); OSUtils::lockDownFile(_basePath.c_str(),true); // networks might contain auth tokens, etc., so restrict directory permissions +#ifndef __WINDOWS__ } +#endif _networks_m.lock(); // locked until data is loaded, etc. if (_rawInput < 0) { - 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::iterator n(_networks.begin());n!=_networks.end();++n) - _summaryThreadToDo.push_back(n->first); - - if (_summaryThreadToDo.size() > 0) { - _summaryThread = Thread::start(this); - } else { - _dataReady = true; - _networks_m.unlock(); - } + _load(basePath); + _dataReady = true; + _networks_m.unlock(); } else { - // In IPC mode we wait for the first message to start, and we start - // this thread since this thread is responsible for reading from stdin. + // In harnessed mode we leave the lock locked and wait for our initial DB from Central. _summaryThread = Thread::start(this); } } @@ -128,16 +97,6 @@ bool JSONDB::writeRaw(const std::string &n,const std::string &obj) } else return true; #endif return false; - } else if (_httpAddr) { - std::map headers; - std::string body; - std::map reqHeaders; - char tmp[64]; - OSUtils::ztsnprintf(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(&_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()) @@ -205,10 +164,15 @@ void JSONDB::saveNetwork(const uint64_t networkId,const nlohmann::json &networkC char n[64]; OSUtils::ztsnprintf(n,sizeof(n),"network/%.16llx",(unsigned long long)networkId); writeRaw(n,OSUtils::jsonDump(networkConfig,-1)); + bool update; { Mutex::Lock _l(_networks_m); - _networks[networkId].config = nlohmann::json::to_msgpack(networkConfig); + _NW &nw = _networks[networkId]; + update = !nw.config.empty(); + nw.config = nlohmann::json::to_msgpack(networkConfig); } + if (update) + _parent->onNetworkUpdate(networkId); _recomputeSummaryInfo(networkId); } @@ -217,17 +181,25 @@ void JSONDB::saveNetworkMember(const uint64_t networkId,const uint64_t nodeId,co char n[256]; OSUtils::ztsnprintf(n,sizeof(n),"network/%.16llx/member/%.10llx",(unsigned long long)networkId,(unsigned long long)nodeId); writeRaw(n,OSUtils::jsonDump(memberConfig,-1)); + bool update; { Mutex::Lock _l(_networks_m); - _networks[networkId].members[nodeId] = nlohmann::json::to_msgpack(memberConfig); + std::vector &m = _networks[networkId].members[nodeId]; + update = !m.empty(); + m = nlohmann::json::to_msgpack(memberConfig); _members[nodeId].insert(networkId); } + if (update) + _parent->onNetworkMemberUpdate(networkId,nodeId); _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 + if (_rawOutput >= 0) { + // In harnessed mode, DB deletes occur in the Central database and we do + // not need to erase files. + } else { std::vector memberIds; { Mutex::Lock _l(_networks_m); @@ -239,24 +211,15 @@ nlohmann::json JSONDB::eraseNetwork(const uint64_t networkId) } for(std::vector::iterator m(memberIds.begin());m!=memberIds.end();++m) eraseNetworkMember(networkId,*m,false); - } - char n[256]; - OSUtils::ztsnprintf(n,sizeof(n),"network/%.16llx",(unsigned long long)networkId); - - if (_rawOutput >= 0) { - // In harnessed mode, deletes occur in Central or other management - // software and do not need to be executed this way. - } else if (_httpAddr) { - std::map headers; - std::string body; - Http::DEL(0,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast(&_httpAddr),(_basePath+"/"+n).c_str(),_ZT_JSONDB_GET_HEADERS,headers,body); - } else { + char n[256]; + OSUtils::ztsnprintf(n,sizeof(n),"network/%.16llx",(unsigned long long)networkId); const std::string path(_genPath(n,false)); if (path.length()) OSUtils::rm(path.c_str()); } + // This also erases all members from the memory cache { Mutex::Lock _l(_networks_m); std::unordered_map::iterator i(_networks.find(networkId)); @@ -270,17 +233,11 @@ nlohmann::json JSONDB::eraseNetwork(const uint64_t networkId) nlohmann::json JSONDB::eraseNetworkMember(const uint64_t networkId,const uint64_t nodeId,bool recomputeSummaryInfo) { - char n[256]; - OSUtils::ztsnprintf(n,sizeof(n),"network/%.16llx/member/%.10llx",(unsigned long long)networkId,(unsigned long long)nodeId); - if (_rawOutput >= 0) { - // In harnessed mode, deletes occur in Central or other management - // software and do not need to be executed this way. - } else if (_httpAddr) { - std::map headers; - std::string body; - Http::DEL(0,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast(&_httpAddr),(_basePath+"/"+n).c_str(),_ZT_JSONDB_GET_HEADERS,headers,body); + // In harnessed mode, DB deletes occur in Central and we do not remove files. } else { + char n[256]; + OSUtils::ztsnprintf(n,sizeof(n),"network/%.16llx/member/%.10llx",(unsigned long long)networkId,(unsigned long long)nodeId); const std::string path(_genPath(n,false)); if (path.length()) OSUtils::rm(path.c_str()); @@ -320,7 +277,6 @@ void JSONDB::threadMain() while (_summaryThreadRun) { #ifndef __WINDOWS__ if (_rawInput < 0) { - // In HTTP and filesystem mode we just wait for summary to-do items Thread::sleep(25); } else { // In IPC mode we wait but also select() on STDIN to read database updates @@ -337,8 +293,8 @@ void JSONDB::threadMain() } else if (rawInputBuf.length() > 0) { try { const nlohmann::json obj(OSUtils::jsonParse(rawInputBuf)); - gotMessage = true; + if (!_dataReady) { _dataReady = true; _networks_m.unlock(); @@ -351,6 +307,7 @@ void JSONDB::threadMain() _add(obj); } } catch ( ... ) {} // ignore malformed JSON + rawInputBuf.clear(); } } @@ -369,7 +326,7 @@ void JSONDB::threadMain() else _summaryThreadToDo.swap(todo); } - if (!_dataReady) { + if (!_dataReady) { // sanity check _dataReady = true; _networks_m.unlock(); } @@ -460,17 +417,33 @@ bool JSONDB::_add(const nlohmann::json &j) if ((id.length() == 16)&&(objtype == "network")) { const uint64_t nwid = Utils::hexStrToU64(id.c_str()); if (nwid) { - Mutex::Lock _l(_networks_m); - _networks[nwid].config = nlohmann::json::to_msgpack(j); + bool update; + { + Mutex::Lock _l(_networks_m); + _NW &nw = _networks[nwid]; + update = !nw.config.empty(); + nw.config = nlohmann::json::to_msgpack(j); + } + if (update) + _parent->onNetworkUpdate(nwid); + _recomputeSummaryInfo(nwid); return true; } } else if ((id.length() == 10)&&(objtype == "member")) { const uint64_t mid = Utils::hexStrToU64(id.c_str()); const uint64_t nwid = Utils::hexStrToU64(OSUtils::jsonString(j["nwid"],"0").c_str()); if ((mid)&&(nwid)) { - Mutex::Lock _l(_networks_m); - _networks[nwid].members[mid] = nlohmann::json::to_msgpack(j); - _members[mid].insert(nwid); + bool update; + { + Mutex::Lock _l(_networks_m); + std::vector &m = _networks[nwid].members[mid]; + update = !m.empty(); + m = nlohmann::json::to_msgpack(j); + _members[mid].insert(nwid); + } + if (update) + _parent->onNetworkMemberUpdate(nwid,mid); + _recomputeSummaryInfo(nwid); return true; } } @@ -484,48 +457,21 @@ bool JSONDB::_load(const std::string &p) // This is not used in stdin/stdout mode. Instead data is populated by // sending it all to stdin. - if (_httpAddr) { - // In HTTP harnessed mode we download our entire working data set on startup. - - std::string body; - std::map headers; - const unsigned int sc = Http::GET(0,ZT_JSONDB_HTTP_TIMEOUT,reinterpret_cast(&_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) { - try { - _add(i.value()); - } catch ( ... ) {} - } - 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 dl(OSUtils::listDirectory(p.c_str(),true)); - for(std::vector::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 { - _add(OSUtils::jsonParse(buf)); - } catch ( ... ) {} - } - } else { - this->_load((p + ZT_PATH_SEPARATOR_S + *di)); + std::vector dl(OSUtils::listDirectory(p.c_str(),true)); + for(std::vector::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 { + _add(OSUtils::jsonParse(buf)); + } catch ( ... ) {} } + } else { + this->_load((p + ZT_PATH_SEPARATOR_S + *di)); } - return true; - } + + return true; } void JSONDB::_recomputeSummaryInfo(const uint64_t networkId) @@ -543,23 +489,15 @@ std::string JSONDB::_genPath(const std::string &n,bool create) 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 Date: Wed, 16 Aug 2017 14:41:42 -0700 Subject: Another Central harnessed mode fix. --- controller/EmbeddedNetworkController.cpp | 2 ++ controller/EmbeddedNetworkController.hpp | 2 +- controller/JSONDB.cpp | 8 -------- 3 files changed, 3 insertions(+), 9 deletions(-) diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 257fef57..3ca0f536 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -721,6 +721,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( json &revj = member["revision"]; member["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); _db.saveNetworkMember(nwid,address,member); + onNetworkMemberUpdate(nwid,address); } _addMemberNonPersistedFields(nwid,address,member,now); @@ -973,6 +974,7 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( json &revj = network["revision"]; network["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); _db.saveNetwork(nwid,network); + onNetworkUpdate(nwid); } JSONDB::NetworkSummaryInfo ns; diff --git a/controller/EmbeddedNetworkController.hpp b/controller/EmbeddedNetworkController.hpp index 6200e910..cbbe07ac 100644 --- a/controller/EmbeddedNetworkController.hpp +++ b/controller/EmbeddedNetworkController.hpp @@ -93,7 +93,7 @@ public: void handleRemoteTrace(const ZT_RemoteTrace &rt); - // Called by JSONDB when networks and network members are changed + // Called on update via POST or by JSONDB on external update of network or network member records void onNetworkUpdate(const uint64_t networkId); void onNetworkMemberUpdate(const uint64_t networkId,const uint64_t memberId); diff --git a/controller/JSONDB.cpp b/controller/JSONDB.cpp index a0dd50c2..9813239e 100644 --- a/controller/JSONDB.cpp +++ b/controller/JSONDB.cpp @@ -164,15 +164,11 @@ void JSONDB::saveNetwork(const uint64_t networkId,const nlohmann::json &networkC char n[64]; OSUtils::ztsnprintf(n,sizeof(n),"network/%.16llx",(unsigned long long)networkId); writeRaw(n,OSUtils::jsonDump(networkConfig,-1)); - bool update; { Mutex::Lock _l(_networks_m); _NW &nw = _networks[networkId]; - update = !nw.config.empty(); nw.config = nlohmann::json::to_msgpack(networkConfig); } - if (update) - _parent->onNetworkUpdate(networkId); _recomputeSummaryInfo(networkId); } @@ -181,16 +177,12 @@ void JSONDB::saveNetworkMember(const uint64_t networkId,const uint64_t nodeId,co char n[256]; OSUtils::ztsnprintf(n,sizeof(n),"network/%.16llx/member/%.10llx",(unsigned long long)networkId,(unsigned long long)nodeId); writeRaw(n,OSUtils::jsonDump(memberConfig,-1)); - bool update; { Mutex::Lock _l(_networks_m); std::vector &m = _networks[networkId].members[nodeId]; - update = !m.empty(); m = nlohmann::json::to_msgpack(memberConfig); _members[nodeId].insert(networkId); } - if (update) - _parent->onNetworkMemberUpdate(networkId,nodeId); _recomputeSummaryInfo(networkId); } -- cgit v1.2.3 From 174ba8884ee68c3a54776ce7fe3f8249aa934ac6 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 17 Aug 2017 13:10:10 -0700 Subject: Delete support in harnessed mode. --- controller/EmbeddedNetworkController.cpp | 26 +++++++++++-------- controller/EmbeddedNetworkController.hpp | 1 + controller/JSONDB.cpp | 44 +++++++++++++++++++++++++------- controller/JSONDB.hpp | 2 +- 4 files changed, 53 insertions(+), 20 deletions(-) diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 3ca0f536..f5bfce4e 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -645,16 +645,8 @@ unsigned int EmbeddedNetworkController::handleControlPlaneHttpPOST( } // Member is being de-authorized, so spray Revocation objects to all online members - if (!newAuth) { - 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(_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); - } - } + if (!newAuth) + onNetworkMemberDeauthorize(nwid,address); } } @@ -1154,6 +1146,20 @@ void EmbeddedNetworkController::onNetworkMemberUpdate(const uint64_t networkId,c } catch ( ... ) {} } +void EmbeddedNetworkController::onNetworkMemberDeauthorize(const uint64_t networkId,const uint64_t memberId) +{ + const uint64_t now = OSUtils::now(); + Revocation rev((uint32_t)_node->prng(),networkId,0,now,ZT_REVOCATION_FLAG_FAST_PROPAGATE,Address(memberId),Revocation::CREDENTIAL_TYPE_COM); + rev.sign(_signingId); + { + Mutex::Lock _l(_memberStatus_m); + for(auto i=_memberStatus.begin();i!=_memberStatus.end();++i) { + if ((i->first.networkId == networkId)&&(i->second.online(now))) + _node->ncSendRevocation(Address(i->first.nodeId),rev); + } + } +} + void EmbeddedNetworkController::threadMain() throw() { diff --git a/controller/EmbeddedNetworkController.hpp b/controller/EmbeddedNetworkController.hpp index cbbe07ac..d1217d60 100644 --- a/controller/EmbeddedNetworkController.hpp +++ b/controller/EmbeddedNetworkController.hpp @@ -96,6 +96,7 @@ public: // Called on update via POST or by JSONDB on external update of network or network member records void onNetworkUpdate(const uint64_t networkId); void onNetworkMemberUpdate(const uint64_t networkId,const uint64_t memberId); + void onNetworkMemberDeauthorize(const uint64_t networkId,const uint64_t memberId); void threadMain() throw(); diff --git a/controller/JSONDB.cpp b/controller/JSONDB.cpp index 9813239e..f362acf3 100644 --- a/controller/JSONDB.cpp +++ b/controller/JSONDB.cpp @@ -294,9 +294,9 @@ void JSONDB::threadMain() if (obj.is_array()) { for(unsigned long i=0;i &m = _networks[nwid].members[mid]; - update = !m.empty(); + if (!m.empty()) { + update = true; + nlohmann::json oldm(nlohmann::json::from_msgpack(m)); + deauth = ((OSUtils::jsonBool(oldm["authorized"],false))&&(!OSUtils::jsonBool(j["authorized"],false))); + } m = nlohmann::json::to_msgpack(j); _members[mid].insert(nwid); } - if (update) + if (update) { _parent->onNetworkMemberUpdate(nwid,mid); + if (deauth) + _parent->onNetworkMemberDeauthorize(nwid,mid); + } _recomputeSummaryInfo(nwid); return true; } + + } else if (objtype == "_delete") { // pseudo-object-type, only used in Central harnessed mode + + const std::string deleteType(OSUtils::jsonString(j["deleteType"],"")); + id = OSUtils::jsonString(j["deleteId"],""); + if ((deleteType == "network")&&(id.length() == 16)) { + eraseNetwork(Utils::hexStrToU64(id.c_str())); + } else if ((deleteType == "member")&&(id.length() == 10)) { + const std::string networkId(OSUtils::jsonString(j["deleteNetworkId"],"")); + const uint64_t nwid = Utils::hexStrToU64(networkId.c_str()); + const uint64_t mid = Utils::hexStrToU64(id.c_str()); + if (networkId.length() == 16) + eraseNetworkMember(nwid,mid,true); + _parent->onNetworkMemberDeauthorize(nwid,mid); + } + } } } catch ( ... ) {} @@ -455,7 +481,7 @@ bool JSONDB::_load(const std::string &p) std::string buf; if (OSUtils::readFile((p + ZT_PATH_SEPARATOR_S + *di).c_str(),buf)) { try { - _add(OSUtils::jsonParse(buf)); + _addOrUpdate(OSUtils::jsonParse(buf)); } catch ( ... ) {} } } else { diff --git a/controller/JSONDB.hpp b/controller/JSONDB.hpp index 66d0138a..44f4d7f5 100644 --- a/controller/JSONDB.hpp +++ b/controller/JSONDB.hpp @@ -157,7 +157,7 @@ public: throw(); private: - bool _add(const nlohmann::json &j); + bool _addOrUpdate(const nlohmann::json &j); bool _load(const std::string &p); void _recomputeSummaryInfo(const uint64_t networkId); std::string _genPath(const std::string &n,bool create); -- cgit v1.2.3 From 106dff0d5312ec7908dade36d537fdf85538413c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 18 Aug 2017 13:52:10 -0700 Subject: Make remote trace target null by default, which is probably what we want. --- controller/EmbeddedNetworkController.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index f5bfce4e..0f342fa5 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -1391,7 +1391,7 @@ void EmbeddedNetworkController::_request( if (rtt.length() == 10) { nc->remoteTraceTarget = Address(Utils::hexStrToU64(rtt.c_str())); } else { - nc->remoteTraceTarget = _signingId.address(); + nc->remoteTraceTarget.zero(); } } -- cgit v1.2.3 From fcaf1d89c260943d3c9c4021b9ab6fe89c1c4de8 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 18 Aug 2017 13:59:22 -0700 Subject: Get rid of some noisy remote traces that should not be needed. --- node/IncomingPacket.cpp | 13 ++++---- node/Membership.cpp | 3 -- node/Trace.cpp | 79 ++----------------------------------------------- node/Trace.hpp | 9 +----- 4 files changed, 10 insertions(+), 94 deletions(-) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index e5e10476..3788708d 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -66,10 +66,9 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) // packets are dropped on the floor. const uint64_t tpid = trustedPathId(); if (RR->topology->shouldInboundPathBeTrusted(_path->address(),tpid)) { - RR->t->incomingPacketTrustedPath(tPtr,_path,packetId(),sourceAddress,tpid,true); trusted = true; } else { - RR->t->incomingPacketTrustedPath(tPtr,_path,packetId(),sourceAddress,tpid,false); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops(),"path not trusted"); return true; } } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { @@ -81,7 +80,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) if (peer) { if (!trusted) { if (!dearmor(peer->key())) { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops()); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops(),"invalid MAC"); return true; } } @@ -246,10 +245,10 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool outp.armor(key,true,_path->nextOutgoingCounter()); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } else { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC"); } } else { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid identity"); } return true; @@ -257,7 +256,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool // Identity is the same as the one we already have -- check packet integrity if (!dearmor(peer->key())) { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC"); return true; } @@ -282,7 +281,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool // Check packet integrity and MAC (this is faster than locallyValidate() so do it first to filter out total crap) SharedPtr newPeer(new Peer(RR,RR->identity,id)); if (!dearmor(newPeer->key())) { - RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops()); + RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC"); return true; } diff --git a/node/Membership.cpp b/node/Membership.cpp index a1453307..17de6554 100644 --- a/node/Membership.cpp +++ b/node/Membership.cpp @@ -147,7 +147,6 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme return ADD_REJECTED; case 0: _com = com; - RR->t->credentialAccepted(tPtr,com); return ADD_ACCEPTED_NEW; case 1: return ADD_DEFERRED_FOR_WHOIS; @@ -179,7 +178,6 @@ static Membership::AddCredentialResult _addCredImpl(Hashtable &remot RR->t->credentialRejected(tPtr,cred,"invalid"); return Membership::ADD_REJECTED; case 0: - RR->t->credentialAccepted(tPtr,cred); if (!rc) rc = &(remoteCreds[cred.id()]); *rc = cred; @@ -205,7 +203,6 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme switch(ct) { case Credential::CREDENTIAL_TYPE_COM: if (rev.threshold() > _comRevocationThreshold) { - RR->t->credentialAccepted(tPtr,rev); _comRevocationThreshold = rev.threshold(); return ADD_ACCEPTED_NEW; } diff --git a/node/Trace.cpp b/node/Trace.cpp index 98a4adcb..8e78b676 100644 --- a/node/Trace.cpp +++ b/node/Trace.cpp @@ -164,12 +164,7 @@ void Trace::incomingNetworkFrameDropped(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved) -{ - // TODO -} - -void Trace::incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops) +void Trace::incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason) { char tmp[128]; Dictionary d; @@ -179,6 +174,8 @@ void Trace::incomingPacketMessageAuthenticationFailure(void *const tPtr,const Sh d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_ZTADDR,source); d.add(ZT_REMOTE_TRACE_FIELD__REMOTE_PHYADDR,path->address().toString(tmp)); d.add(ZT_REMOTE_TRACE_FIELD__LOCAL_SOCKET,path->localSocket()); + if (reason) + d.add(ZT_REMOTE_TRACE_FIELD__REASON,reason); _send(tPtr,d,0); } @@ -344,76 +341,6 @@ void Trace::credentialRejected(void *const tPtr,const Revocation &c,const char * _send(tPtr,d,c.networkId()); } -void Trace::credentialAccepted(void *const tPtr,const CertificateOfMembership &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - _send(tPtr,d,c.networkId()); -} - -void Trace::credentialAccepted(void *const tPtr,const CertificateOfOwnership &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - _send(tPtr,d,c.networkId()); -} - -void Trace::credentialAccepted(void *const tPtr,const CertificateOfRepresentation &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - _send(tPtr,d,0); -} - -void Trace::credentialAccepted(void *const tPtr,const Capability &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - _send(tPtr,d,c.networkId()); -} - -void Trace::credentialAccepted(void *const tPtr,const Tag &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TIMESTAMP,c.timestamp()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ISSUED_TO,c.issuedTo()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_INFO,(uint64_t)c.value()); - _send(tPtr,d,c.networkId()); -} - -void Trace::credentialAccepted(void *const tPtr,const Revocation &c) -{ - Dictionary d; - d.add(ZT_REMOTE_TRACE_FIELD__EVENT,ZT_REMOTE_TRACE_EVENT__CREDENTIAL_ACCEPTED_S); - d.add(ZT_REMOTE_TRACE_FIELD__NETWORK_ID,c.networkId()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_TYPE,(uint64_t)c.credentialType()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_ID,(uint64_t)c.id()); - d.add(ZT_REMOTE_TRACE_FIELD__CREDENTIAL_REVOCATION_TARGET,c.target()); - _send(tPtr,d,c.networkId()); -} - void Trace::_send(void *const tPtr,const Dictionary &d) { #ifdef ZT_TRACE diff --git a/node/Trace.hpp b/node/Trace.hpp index d66d0871..a7b2b194 100644 --- a/node/Trace.hpp +++ b/node/Trace.hpp @@ -108,8 +108,7 @@ public: void peerLearnedNewPath(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath,const uint64_t packetId); void peerRedirected(void *const tPtr,const uint64_t networkId,Peer &peer,const SharedPtr &oldPath,const SharedPtr &newPath); - void incomingPacketTrustedPath(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const uint64_t trustedPathId,bool approved); - void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops); + void incomingPacketMessageAuthenticationFailure(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const char *reason); void incomingPacketInvalid(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const unsigned int hops,const Packet::Verb verb,const char *reason); void incomingPacketDroppedHELLO(void *const tPtr,const SharedPtr &path,const uint64_t packetId,const Address &source,const char *reason); @@ -142,12 +141,6 @@ public: void credentialRejected(void *const tPtr,const Capability &c,const char *reason); void credentialRejected(void *const tPtr,const Tag &c,const char *reason); void credentialRejected(void *const tPtr,const Revocation &c,const char *reason); - void credentialAccepted(void *const tPtr,const CertificateOfMembership &c); - void credentialAccepted(void *const tPtr,const CertificateOfOwnership &c); - void credentialAccepted(void *const tPtr,const CertificateOfRepresentation &c); - void credentialAccepted(void *const tPtr,const Capability &c); - void credentialAccepted(void *const tPtr,const Tag &c); - void credentialAccepted(void *const tPtr,const Revocation &c); private: const RuntimeEnvironment *const RR; -- cgit v1.2.3 From bab5647522ef42dc60bc17165c70ab78405b1434 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 18 Aug 2017 14:00:35 -0700 Subject: Add make rule for official-static. --- make-linux.mk | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/make-linux.mk b/make-linux.mk index 7017d31e..3ae2d4fd 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -210,12 +210,6 @@ endif all: one -#ext/x64-salsa2012-asm/salsa2012.o: -# $(CC) -c ext/x64-salsa2012-asm/salsa2012.s -o ext/x64-salsa2012-asm/salsa2012.o - -#ext/arm32-neon-salsa2012-asm/salsa2012.o: -# $(CC) -c ext/arm32-neon-salsa2012-asm/salsa2012.s -o ext/arm32-neon-salsa2012-asm/salsa2012.o - one: $(CORE_OBJS) $(ONE_OBJS) one.o $(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LDLIBS) $(STRIP) zerotier-one @@ -252,6 +246,9 @@ distclean: clean realclean: distclean +official-static: FORCE + make -j4 ZT_STATIC=1 LDLIBS=/usr/lib/libjemalloc.a all selftest + debug: FORCE make ZT_DEBUG=1 one make ZT_DEBUG=1 selftest -- cgit v1.2.3 From ba07a60c4407a6db0037242579994a19a4534e81 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 18 Aug 2017 14:40:10 -0700 Subject: Fix PPC PR. --- make-linux.mk | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/make-linux.mk b/make-linux.mk index 4ef590a4..d96bf263 100644 --- a/make-linux.mk +++ b/make-linux.mk @@ -100,7 +100,13 @@ ifeq ($(CC_MACH),amd64) ZT_USE_X64_ASM_SALSA2012=1 endif ifeq ($(CC_MACH),powerpc64le) - ZT_ARCHITECTURE=2 + ZT_ARCHITECTURE=8 +endif +ifeq ($(CC_MACH),ppc64le) + ZT_ARCHITECTURE=8 +endif +ifeq ($(CC_MACH),ppc64el) + ZT_ARCHITECTURE=8 endif ifeq ($(CC_MACH),i386) ZT_ARCHITECTURE=1 -- cgit v1.2.3 From 4352202349a9059d4cd1fbad7e148ed047d8e47d Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 18 Aug 2017 14:54:10 -0700 Subject: Reduce TCP relay latency -- see GitHub issue #564 --- service/OneService.cpp | 37 ++++++++++++++++++++++++------------- 1 file changed, 24 insertions(+), 13 deletions(-) diff --git a/service/OneService.cpp b/service/OneService.cpp index c3bf9fee..f5f8700a 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -2142,19 +2142,30 @@ public: const uint64_t now = OSUtils::now(); if (((now - _lastDirectReceiveFromGlobal) > ZT_TCP_FALLBACK_AFTER)&&((now - _lastRestart) > ZT_TCP_FALLBACK_AFTER)) { if (_tcpFallbackTunnel) { - Mutex::Lock _l(_tcpFallbackTunnel->writeq_m); - if (_tcpFallbackTunnel->writeq.length() == 0) - _phy.setNotifyWritable(_tcpFallbackTunnel->sock,true); - const unsigned long mlen = len + 7; - _tcpFallbackTunnel->writeq.push_back((char)0x17); - _tcpFallbackTunnel->writeq.push_back((char)0x03); - _tcpFallbackTunnel->writeq.push_back((char)0x03); // fake TLS 1.2 header - _tcpFallbackTunnel->writeq.push_back((char)((mlen >> 8) & 0xff)); - _tcpFallbackTunnel->writeq.push_back((char)(mlen & 0xff)); - _tcpFallbackTunnel->writeq.push_back((char)4); // IPv4 - _tcpFallbackTunnel->writeq.append(reinterpret_cast(reinterpret_cast(&(reinterpret_cast(addr)->sin_addr.s_addr))),4); - _tcpFallbackTunnel->writeq.append(reinterpret_cast(reinterpret_cast(&(reinterpret_cast(addr)->sin_port))),2); - _tcpFallbackTunnel->writeq.append((const char *)data,len); + bool flushNow = false; + { + Mutex::Lock _l(_tcpFallbackTunnel->writeq_m); + if (_tcpFallbackTunnel->writeq.size() < (1024 * 64)) { + if (_tcpFallbackTunnel->writeq.length() == 0) { + _phy.setNotifyWritable(_tcpFallbackTunnel->sock,true); + flushNow = true; + } + const unsigned long mlen = len + 7; + _tcpFallbackTunnel->writeq.push_back((char)0x17); + _tcpFallbackTunnel->writeq.push_back((char)0x03); + _tcpFallbackTunnel->writeq.push_back((char)0x03); // fake TLS 1.2 header + _tcpFallbackTunnel->writeq.push_back((char)((mlen >> 8) & 0xff)); + _tcpFallbackTunnel->writeq.push_back((char)(mlen & 0xff)); + _tcpFallbackTunnel->writeq.push_back((char)4); // IPv4 + _tcpFallbackTunnel->writeq.append(reinterpret_cast(reinterpret_cast(&(reinterpret_cast(addr)->sin_addr.s_addr))),4); + _tcpFallbackTunnel->writeq.append(reinterpret_cast(reinterpret_cast(&(reinterpret_cast(addr)->sin_port))),2); + _tcpFallbackTunnel->writeq.append((const char *)data,len); + } + } + if (flushNow) { + void *tmpptr = (void *)_tcpFallbackTunnel; + phyOnTcpWritable(_tcpFallbackTunnel->sock,&tmpptr); + } } else if (((now - _lastSendToGlobalV4) < ZT_TCP_FALLBACK_AFTER)&&((now - _lastSendToGlobalV4) > (ZT_PING_CHECK_INVERVAL / 2))) { const InetAddress addr(ZT_TCP_FALLBACK_RELAY); TcpConnection *tc = new TcpConnection(); -- cgit v1.2.3 From 64758c46b672f8b3182c370aed6b81a07780c093 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 13:40:51 -0700 Subject: Implement peer serialization and deserialization. --- node/Peer.cpp | 2 +- node/Peer.hpp | 84 ++++++++++++++++++++++++++++++++++++++++++++++++++ node/Topology.cpp | 31 +++++++++++++++---- node/Topology.hpp | 2 ++ service/OneService.cpp | 25 ++++++++++++--- 5 files changed, 132 insertions(+), 12 deletions(-) diff --git a/node/Peer.cpp b/node/Peer.cpp index 986e52ef..127f222c 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -369,7 +369,7 @@ void Peer::tryMemorizedPath(void *tPtr,uint64_t now) _lastTriedMemorizedPath = now; InetAddress mp; if (RR->node->externalPathLookup(tPtr,_id.address(),-1,mp)) - attemptToContactAt(tPtr,InetAddress(),mp,now,true,0); + attemptToContactAt(tPtr,-1,mp,now,true,0); } } diff --git a/node/Peer.hpp b/node/Peer.hpp index c6423a59..af9163a5 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -439,6 +439,90 @@ public: return false; } + /** + * Serialize a peer for storage in local cache + * + * This does not serialize everything, just identity and addresses where the peer + * may be reached. + */ + template + inline void serialize(Buffer &b) const + { + b.append((uint8_t)0); + + _id.serialize(b); + + b.append(_lastReceive); + b.append(_lastNontrivialReceive); + b.append(_lastTriedMemorizedPath); + b.append(_lastDirectPathPushSent); + b.append(_lastDirectPathPushReceive); + b.append(_lastCredentialRequestSent); + b.append(_lastWhoisRequestReceived); + b.append(_lastEchoRequestReceived); + b.append(_lastComRequestReceived); + b.append(_lastComRequestSent); + b.append(_lastCredentialsReceived); + b.append(_lastTrustEstablishedPacketReceived); + + b.append((uint16_t)_vProto); + b.append((uint16_t)_vMajor); + b.append((uint16_t)_vMinor); + b.append((uint16_t)_vRevision); + + { + Mutex::Lock _l(_paths_m); + unsigned int pcount = 0; + if (_v4Path.p) ++pcount; + if (_v6Path.p) ++pcount; + b.append((uint8_t)pcount); + if (_v4Path.p) _v4Path.p->address().serialize(b); + if (_v6Path.p) _v6Path.p->address().serialize(b); + } + + b.append((uint16_t)0); + } + + template + inline static SharedPtr deserializeFromCache(uint64_t now,void *tPtr,Buffer &b,const RuntimeEnvironment *renv) + { + try { + unsigned int ptr = 0; + if (b[ptr++] != 0) + return SharedPtr(); + + Identity id; + ptr += id.deserialize(b,ptr); + if (!id) + return SharedPtr(); + + SharedPtr p(new Peer(renv,renv->identity,id)); + + ptr += 12 * 8; // skip deserializing ephemeral state in this case + + p->_vProto = b.template at(ptr); ptr += 2; + p->_vMajor = b.template at(ptr); ptr += 2; + p->_vMinor = b.template at(ptr); ptr += 2; + p->_vRevision = b.template at(ptr); ptr += 2; + + const unsigned int pcount = (unsigned int)b[ptr++]; + for(unsigned int i=0;iattemptToContactAt(tPtr,-1,inaddr,now,true,0); + } catch ( ... ) { + break; + } + } + + return p; + } catch ( ... ) { + return SharedPtr(); + } + } + private: struct _PeerPath { diff --git a/node/Topology.cpp b/node/Topology.cpp index edca0180..aeca59a7 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -88,6 +88,15 @@ Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) : addWorld(tPtr,defaultPlanet,false); } +Topology::~Topology() +{ + Hashtable< Address,SharedPtr >::Iterator i(_peers); + Address *a = (Address *)0; + SharedPtr *p = (SharedPtr *)0; + while (i.next(a,p)) + _savePeer((void *)0,*p); +} + SharedPtr Topology::addPeer(void *tPtr,const SharedPtr &peer) { SharedPtr np; @@ -113,23 +122,21 @@ SharedPtr Topology::getPeer(void *tPtr,const Address &zta) return *ap; } - /* try { - char buf[ZT_PEER_MAX_SERIALIZED_STATE_SIZE]; + Buffer buf; uint64_t idbuf[2]; idbuf[0] = zta.toInt(); idbuf[1] = 0; - int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,idbuf,buf,(unsigned int)sizeof(buf)); + int len = RR->node->stateObjectGet(tPtr,ZT_STATE_OBJECT_PEER,idbuf,buf.unsafeData(),ZT_PEER_MAX_SERIALIZED_STATE_SIZE); if (len > 0) { Mutex::Lock _l(_peers_m); SharedPtr &ap = _peers[zta]; if (ap) return ap; - ap = Peer::createFromStateUpdate(RR,tPtr,buf,len); + ap = Peer::deserializeFromCache(RR->node->now(),tPtr,buf,RR); if (!ap) _peers.erase(zta); return ap; } } catch ( ... ) {} // ignore invalid identities or other strage failures - */ return SharedPtr(); } @@ -383,8 +390,10 @@ void Topology::doPeriodicTasks(void *tPtr,uint64_t now) Address *a = (Address *)0; SharedPtr *p = (SharedPtr *)0; while (i.next(a,p)) { - if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) + if ( (!(*p)->isAlive(now)) && (std::find(_upstreamAddresses.begin(),_upstreamAddresses.end(),*a) == _upstreamAddresses.end()) ) { + _savePeer(tPtr,*p); _peers.erase(*a); + } } } @@ -440,4 +449,14 @@ void Topology::_memoizeUpstreams(void *tPtr) _cor.sign(RR->identity,RR->node->now()); } +void Topology::_savePeer(void *tPtr,const SharedPtr &peer) +{ + try { + Buffer buf; + peer->serialize(buf); + uint64_t tmpid[2]; tmpid[0] = peer->address().toInt(); tmpid[1] = 0; + RR->node->stateObjectPut(tPtr,ZT_STATE_OBJECT_PEER,tmpid,buf.data(),buf.size()); + } catch ( ... ) {} // sanity check, discard invalid entries +} + } // namespace ZeroTier diff --git a/node/Topology.hpp b/node/Topology.hpp index 30e58abc..04dfb1cc 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -59,6 +59,7 @@ class Topology { public: Topology(const RuntimeEnvironment *renv,void *tPtr); + ~Topology(); /** * Add a peer to database @@ -419,6 +420,7 @@ public: private: Identity _getIdentity(void *tPtr,const Address &zta); void _memoizeUpstreams(void *tPtr); + void _savePeer(void *tPtr,const SharedPtr &peer); const RuntimeEnvironment *const RR; diff --git a/service/OneService.cpp b/service/OneService.cpp index f5f8700a..cd33e399 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -2047,6 +2047,8 @@ public: char p[1024]; FILE *f; bool secure = false; + char dirname[1024]; + dirname[0] = 0; switch(type) { case ZT_STATE_OBJECT_IDENTITY_PUBLIC: @@ -2060,12 +2062,18 @@ public: OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); break; case ZT_STATE_OBJECT_MOON: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id[0]); + OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "moons.d",_homePath.c_str()); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.moon",dirname,(unsigned long long)id[0]); break; case ZT_STATE_OBJECT_NETWORK_CONFIG: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id[0]); + OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "networks.d",_homePath.c_str()); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.16llx.conf",dirname,(unsigned long long)id[0]); secure = true; break; + case ZT_STATE_OBJECT_PEER: + OSUtils::ztsnprintf(dirname,sizeof(dirname),"%s" ZT_PATH_SEPARATOR_S "peers.d",_homePath.c_str()); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "%.10llx.peer",dirname,(unsigned long long)id[0]); + break; default: return; } @@ -2084,6 +2092,10 @@ public: } f = fopen(p,"w"); + if ((!f)&&(dirname[0])) { // create subdirectory if it does not exist + OSUtils::mkdir(dirname); + f = fopen(p,"w"); + } if (f) { if (fwrite(data,len,1,f) != 1) fprintf(stderr,"WARNING: unable to write to file: %s (I/O error)" ZT_EOL_S,p); @@ -2108,15 +2120,18 @@ public: case ZT_STATE_OBJECT_IDENTITY_SECRET: OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "identity.secret",_homePath.c_str()); break; - case ZT_STATE_OBJECT_NETWORK_CONFIG: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id); - break; case ZT_STATE_OBJECT_PLANET: OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); break; case ZT_STATE_OBJECT_MOON: OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id); break; + case ZT_STATE_OBJECT_NETWORK_CONFIG: + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id); + break; + case ZT_STATE_OBJECT_PEER: + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "peers.d/%.10llx.conf",_homePath.c_str(),(unsigned long long)id[0]); + break; default: return -1; } -- cgit v1.2.3 From 9cfc10952748487bed318ec11221eeccbb285c89 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 14:00:08 -0700 Subject: Tighten a few timings. --- node/Constants.hpp | 4 ++-- node/Switch.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/node/Constants.hpp b/node/Constants.hpp index 3f050ead..27dce075 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -226,12 +226,12 @@ /** * Delay between WHOIS retries in ms */ -#define ZT_WHOIS_RETRY_DELAY 1000 +#define ZT_WHOIS_RETRY_DELAY 500 /** * Maximum identity WHOIS retries (each attempt tries consulting a different peer) */ -#define ZT_MAX_WHOIS_RETRIES 4 +#define ZT_MAX_WHOIS_RETRIES 5 /** * Transmit queue entry timeout diff --git a/node/Switch.cpp b/node/Switch.cpp index 053f793e..0d39bee9 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -630,9 +630,9 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) { // Time out TX queue packets that never got WHOIS lookups or other info. Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { - if (_trySend(tPtr,txi->packet,txi->encrypt)) + if (_trySend(tPtr,txi->packet,txi->encrypt)) { _txQueue.erase(txi++); - else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { + } else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { RR->t->txTimedOut(tPtr,txi->dest); _txQueue.erase(txi++); } else ++txi; -- cgit v1.2.3 From 2cebe7a5e0069880e197590a03c4afa8a9492595 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 14:09:29 -0700 Subject: Fix name difference. --- service/OneService.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/service/OneService.cpp b/service/OneService.cpp index cd33e399..2da72461 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -2124,13 +2124,13 @@ public: OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "planet",_homePath.c_str()); break; case ZT_STATE_OBJECT_MOON: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d/%.16llx.moon",_homePath.c_str(),(unsigned long long)id); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "moons.d" ZT_PATH_SEPARATOR_S "%.16llx.moon",_homePath.c_str(),(unsigned long long)id); break; case ZT_STATE_OBJECT_NETWORK_CONFIG: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d/%.16llx.conf",_homePath.c_str(),(unsigned long long)id); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "networks.d" ZT_PATH_SEPARATOR_S "%.16llx.conf",_homePath.c_str(),(unsigned long long)id); break; case ZT_STATE_OBJECT_PEER: - OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "peers.d/%.10llx.conf",_homePath.c_str(),(unsigned long long)id[0]); + OSUtils::ztsnprintf(p,sizeof(p),"%s" ZT_PATH_SEPARATOR_S "peers.d" ZT_PATH_SEPARATOR_S "%.10llx.peer",_homePath.c_str(),(unsigned long long)id[0]); break; default: return -1; -- cgit v1.2.3 From a156a4dbe2ffe5fc5f870144fe80efc172901d8e Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 15:12:00 -0700 Subject: Symmetric NAT cleanup. --- node/SelfAwareness.cpp | 52 ++++++++++++++++++++++++++++---------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/node/SelfAwareness.cpp b/node/SelfAwareness.cpp index cdbb6303..0af0d691 100644 --- a/node/SelfAwareness.cpp +++ b/node/SelfAwareness.cpp @@ -147,13 +147,14 @@ std::vector SelfAwareness::getSymmetricNatPredictions() * read or modify traffic, but they could gather meta-data for forensics * purpsoes or use this as a DOS attack vector. */ - std::map< uint32_t,std::pair > maxPortByIp; + std::map< uint32_t,unsigned int > maxPortByIp; InetAddress theOneTrueSurface; - bool symmetric = false; { Mutex::Lock _l(_phy_m); - { // First get IPs from only trusted peers, and perform basic NAT type characterization + // First check to see if this is a symmetric NAT and enumerate external IPs learned from trusted peers + bool symmetric = false; + { Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); PhySurfaceKey *k = (PhySurfaceKey *)0; PhySurfaceEntry *e = (PhySurfaceEntry *)0; @@ -163,42 +164,47 @@ std::vector SelfAwareness::getSymmetricNatPredictions() theOneTrueSurface = e->mySurface; else if (theOneTrueSurface != e->mySurface) symmetric = true; - maxPortByIp[reinterpret_cast(&(e->mySurface))->sin_addr.s_addr] = std::pair(e->ts,e->mySurface.port()); + maxPortByIp[reinterpret_cast(&(e->mySurface))->sin_addr.s_addr] = e->mySurface.port(); } } } + if (!symmetric) + return std::vector(); - { // Then find max port per IP from a trusted peer + { // Then find the highest issued port per IP Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy); PhySurfaceKey *k = (PhySurfaceKey *)0; PhySurfaceEntry *e = (PhySurfaceEntry *)0; while (i.next(k,e)) { if ((e->mySurface.ss_family == AF_INET)&&(e->mySurface.ipScope() == InetAddress::IP_SCOPE_GLOBAL)) { - std::map< uint32_t,std::pair >::iterator mp(maxPortByIp.find(reinterpret_cast(&(e->mySurface))->sin_addr.s_addr)); - if ((mp != maxPortByIp.end())&&(mp->second.first < e->ts)) { - mp->second.first = e->ts; - mp->second.second = e->mySurface.port(); - } + const unsigned int port = e->mySurface.port(); + std::map< uint32_t,unsigned int >::iterator mp(maxPortByIp.find(reinterpret_cast(&(e->mySurface))->sin_addr.s_addr)); + if ((mp != maxPortByIp.end())&&(mp->second < port)) + mp->second = port; } } } } - if (symmetric) { - std::vector r; - for(unsigned int k=1;k<=3;++k) { - for(std::map< uint32_t,std::pair >::iterator i(maxPortByIp.begin());i!=maxPortByIp.end();++i) { - unsigned int p = i->second.second + k; - if (p > 65535) p -= 64511; - InetAddress pred(&(i->first),4,p); - if (std::find(r.begin(),r.end(),pred) == r.end()) - r.push_back(pred); - } - } - return r; + std::vector r; + + // Try next port up from max for each + for(std::map< uint32_t,unsigned int >::iterator i(maxPortByIp.begin());i!=maxPortByIp.end();++i) { + unsigned int p = i->second + 1; + if (p > 65535) p -= 64511; + const InetAddress pred(&(i->first),4,p); + if (std::find(r.begin(),r.end(),pred) == r.end()) + r.push_back(pred); + } + + // Try a random port for each -- there are only 65535 so eventually it should work + for(std::map< uint32_t,unsigned int >::iterator i(maxPortByIp.begin());i!=maxPortByIp.end();++i) { + const InetAddress pred(&(i->first),4,1024 + ((unsigned int)RR->node->prng() % 64511)); + if (std::find(r.begin(),r.end(),pred) == r.end()) + r.push_back(pred); } - return std::vector(); + return r; } } // namespace ZeroTier -- cgit v1.2.3 From b1d94c9f9324a31887dc6edc99ed58d4f9b187db Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 15:19:26 -0700 Subject: Performance improvement to RX queue ring buffer. --- node/Switch.hpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/node/Switch.hpp b/node/Switch.hpp index 114bc5e1..88415541 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -174,19 +174,20 @@ private: // Returns matching or next available RX queue entry inline RXQueueEntry *_findRXQueueEntry(uint64_t packetId) { - unsigned int ptr = static_cast(_rxQueuePtr.load()); - for(unsigned int k=0;k(_rxQueuePtr.load()); + for(unsigned int k=1;k<=ZT_RX_QUEUE_SIZE;++k) { + RXQueueEntry *rq = &(_rxQueue[(current - k) % ZT_RX_QUEUE_SIZE]); if ((rq->packetId == packetId)&&(rq->timestamp)) return rq; } - return &(_rxQueue[static_cast(++_rxQueuePtr) % ZT_RX_QUEUE_SIZE]); + ++_rxQueuePtr; + return &(_rxQueue[static_cast(current) % ZT_RX_QUEUE_SIZE]); } - // Returns next RX queue entry in ring buffer and increments ring counter + // Returns current entry in rx queue ring buffer and increments ring pointer inline RXQueueEntry *_nextRXQueueEntry() { - return &(_rxQueue[static_cast(++_rxQueuePtr) % ZT_RX_QUEUE_SIZE]); + return &(_rxQueue[static_cast((++_rxQueuePtr) - 1) % ZT_RX_QUEUE_SIZE]); } // ZeroTier-layer TX queue entry -- cgit v1.2.3 From 6ee201865b12f5b0f16208f6d696b1bf00197eaf Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 16:42:17 -0700 Subject: Clean up WHOIS code. --- node/Capability.cpp | 3 +- node/CertificateOfMembership.cpp | 3 +- node/CertificateOfOwnership.cpp | 3 +- node/Constants.hpp | 9 +-- node/IncomingPacket.cpp | 4 +- node/Node.cpp | 26 ++++---- node/Revocation.cpp | 3 +- node/Switch.cpp | 132 ++++++++++++++++++++------------------- node/Switch.hpp | 24 +++---- node/Tag.cpp | 3 +- node/Topology.cpp | 35 +++-------- node/Topology.hpp | 14 +---- 12 files changed, 115 insertions(+), 144 deletions(-) diff --git a/node/Capability.cpp b/node/Capability.cpp index 0e02025a..47dca1fc 100644 --- a/node/Capability.cpp +++ b/node/Capability.cpp @@ -30,6 +30,7 @@ #include "Topology.hpp" #include "Switch.hpp" #include "Network.hpp" +#include "Node.hpp" namespace ZeroTier { @@ -59,7 +60,7 @@ int Capability::verify(const RuntimeEnvironment *RR,void *tPtr) const if (!id.verify(tmp.data(),tmp.size(),_custody[c].signature)) return -1; } else { - RR->sw->requestWhois(tPtr,_custody[c].from); + RR->sw->requestWhois(tPtr,RR->node->now(),_custody[c].from); return 1; } } diff --git a/node/CertificateOfMembership.cpp b/node/CertificateOfMembership.cpp index 100253e1..dedcccff 100644 --- a/node/CertificateOfMembership.cpp +++ b/node/CertificateOfMembership.cpp @@ -29,6 +29,7 @@ #include "Topology.hpp" #include "Switch.hpp" #include "Network.hpp" +#include "Node.hpp" namespace ZeroTier { @@ -223,7 +224,7 @@ int CertificateOfMembership::verify(const RuntimeEnvironment *RR,void *tPtr) con const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(tPtr,_signedBy); + RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); return 1; } diff --git a/node/CertificateOfOwnership.cpp b/node/CertificateOfOwnership.cpp index 31d0ae18..eeb0d99c 100644 --- a/node/CertificateOfOwnership.cpp +++ b/node/CertificateOfOwnership.cpp @@ -30,6 +30,7 @@ #include "Topology.hpp" #include "Switch.hpp" #include "Network.hpp" +#include "Node.hpp" namespace ZeroTier { @@ -39,7 +40,7 @@ int CertificateOfOwnership::verify(const RuntimeEnvironment *RR,void *tPtr) cons return -1; const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(tPtr,_signedBy); + RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); return 1; } try { diff --git a/node/Constants.hpp b/node/Constants.hpp index 27dce075..cda1af3b 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -228,20 +228,15 @@ */ #define ZT_WHOIS_RETRY_DELAY 500 -/** - * Maximum identity WHOIS retries (each attempt tries consulting a different peer) - */ -#define ZT_MAX_WHOIS_RETRIES 5 - /** * Transmit queue entry timeout */ -#define ZT_TRANSMIT_QUEUE_TIMEOUT (ZT_WHOIS_RETRY_DELAY * (ZT_MAX_WHOIS_RETRIES + 1)) +#define ZT_TRANSMIT_QUEUE_TIMEOUT 5000 /** * Receive queue entry timeout */ -#define ZT_RECEIVE_QUEUE_TIMEOUT (ZT_WHOIS_RETRY_DELAY * (ZT_MAX_WHOIS_RETRIES + 1)) +#define ZT_RECEIVE_QUEUE_TIMEOUT 5000 /** * Maximum latency to allow for OK(HELLO) before packet is discarded diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 3788708d..685f2f09 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -115,7 +115,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr) case Packet::VERB_REMOTE_TRACE: return _doREMOTE_TRACE(RR,tPtr,peer); } } else { - RR->sw->requestWhois(tPtr,sourceAddress); + RR->sw->requestWhois(tPtr,RR->node->now(),sourceAddress); return false; } } catch ( ... ) { @@ -556,7 +556,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar ++count; } else { // Request unknown WHOIS from upstream from us (if we have one) - RR->sw->requestWhois(tPtr,addr); + RR->sw->requestWhois(tPtr,RR->node->now(),addr); } } diff --git a/node/Node.cpp b/node/Node.cpp index 366ddbf0..09260172 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -249,6 +249,19 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint try { _lastPingCheck = now; + // Do pings and keepalives + Hashtable< Address,std::vector > upstreamsToContact; + RR->topology->getUpstreamsToContact(upstreamsToContact); + _PingPeersThatNeedPing pfunc(RR,tptr,upstreamsToContact,now); + RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); + + // Run WHOIS to create Peer for any upstreams we could not contact (including pending moon seeds) + Hashtable< Address,std::vector >::Iterator i(upstreamsToContact); + Address *upstreamAddress = (Address *)0; + std::vector *upstreamStableEndpoints = (std::vector *)0; + while (i.next(upstreamAddress,upstreamStableEndpoints)) + RR->sw->requestWhois(tptr,now,*upstreamAddress); + // Get networks that need config without leaving mutex locked { std::vector< std::pair< SharedPtr,bool > > nwl; @@ -268,19 +281,6 @@ ZT_ResultCode Node::processBackgroundTasks(void *tptr,uint64_t now,volatile uint } } - // Do pings and keepalives - Hashtable< Address,std::vector > upstreamsToContact; - RR->topology->getUpstreamsToContact(upstreamsToContact); - _PingPeersThatNeedPing pfunc(RR,tptr,upstreamsToContact,now); - RR->topology->eachPeer<_PingPeersThatNeedPing &>(pfunc); - - // Run WHOIS to create Peer for any upstreams we could not contact (including pending moon seeds) - Hashtable< Address,std::vector >::Iterator i(upstreamsToContact); - Address *upstreamAddress = (Address *)0; - std::vector *upstreamStableEndpoints = (std::vector *)0; - while (i.next(upstreamAddress,upstreamStableEndpoints)) - RR->sw->requestWhois(tptr,*upstreamAddress); - // Update online status, post status change as event const bool oldOnline = _online; _online = (((now - pfunc.lastReceiveFromUpstream) < ZT_PEER_ACTIVITY_TIMEOUT)||(RR->topology->amRoot())); diff --git a/node/Revocation.cpp b/node/Revocation.cpp index 026058da..89a2db95 100644 --- a/node/Revocation.cpp +++ b/node/Revocation.cpp @@ -30,6 +30,7 @@ #include "Topology.hpp" #include "Switch.hpp" #include "Network.hpp" +#include "Node.hpp" namespace ZeroTier { @@ -39,7 +40,7 @@ int Revocation::verify(const RuntimeEnvironment *RR,void *tPtr) const return -1; const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(tPtr,_signedBy); + RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); return 1; } try { diff --git a/node/Switch.cpp b/node/Switch.cpp index 0d39bee9..8446602c 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -50,7 +50,6 @@ namespace ZeroTier { Switch::Switch(const RuntimeEnvironment *renv) : RR(renv), _lastBeaconResponse(0), - _outstandingWhoisRequests(32), _lastUniteAttempt(8) // only really used on root servers and upstreams, and it'll grow there just fine { } @@ -229,8 +228,8 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre } } } else { - relayTo = RR->topology->getUpstreamPeer(&source,1,true); - if (relayTo) + relayTo = RR->topology->getUpstreamPeer(); + if ((relayTo)&&(relayTo->address() != source)) relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true); } } @@ -553,33 +552,35 @@ void Switch::send(void *tPtr,Packet &packet,bool encrypt) } } -void Switch::requestWhois(void *tPtr,const Address &addr) +void Switch::requestWhois(void *tPtr,const uint64_t now,const Address &addr) { if (addr == RR->identity.address()) return; - bool inserted = false; + { - Mutex::Lock _l(_outstandingWhoisRequests_m); - WhoisRequest &r = _outstandingWhoisRequests[addr]; - if (r.lastSent) { - r.retries = 0; // reset retry count if entry already existed, but keep waiting and retry again after normal timeout - } else { - r.lastSent = RR->node->now(); - inserted = true; - } + Mutex::Lock _l(_lastSentWhoisRequest_m); + uint64_t &last = _lastSentWhoisRequest[addr]; + if ((now - last) < ZT_WHOIS_RETRY_DELAY) + return; + else last = now; + } + + const SharedPtr upstream(RR->topology->getUpstreamPeer()); + if (upstream) { + Packet outp(upstream->address(),RR->identity.address(),Packet::VERB_WHOIS); + addr.appendTo(outp); + RR->node->expectReplyTo(outp.packetId()); + send(tPtr,outp,true); } - if (inserted) - _sendWhoisRequest(tPtr,addr,(const Address *)0,0); } void Switch::doAnythingWaitingForPeer(void *tPtr,const SharedPtr &peer) { - { // cancel pending WHOIS since we now know this peer - Mutex::Lock _l(_outstandingWhoisRequests_m); - _outstandingWhoisRequests.erase(peer->address()); + { + Mutex::Lock _l(_lastSentWhoisRequest_m); + _lastSentWhoisRequest.erase(peer->address()); } - // finish processing any packets waiting on peer's public key / identity const uint64_t now = RR->node->now(); for(unsigned int ptr=0;ptr &peer) } } - { // finish sending any packets waiting on peer's public key / identity + { Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { if (txi->dest == peer->address()) { - if (_trySend(tPtr,txi->packet,txi->encrypt)) + if (_trySend(tPtr,txi->packet,txi->encrypt)) { _txQueue.erase(txi++); - else ++txi; - } else ++txi; - } - } -} - -unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) -{ - unsigned long nextDelay = 0xffffffff; // ceiling delay, caller will cap to minimum - - { // Retry outstanding WHOIS requests - Mutex::Lock _l(_outstandingWhoisRequests_m); - Hashtable< Address,WhoisRequest >::Iterator i(_outstandingWhoisRequests); - Address *a = (Address *)0; - WhoisRequest *r = (WhoisRequest *)0; - while (i.next(a,r)) { - const unsigned long since = (unsigned long)(now - r->lastSent); - if (since >= ZT_WHOIS_RETRY_DELAY) { - if (r->retries >= ZT_MAX_WHOIS_RETRIES) { - _outstandingWhoisRequests.erase(*a); } else { - r->lastSent = now; - r->peersConsulted[r->retries] = _sendWhoisRequest(tPtr,*a,r->peersConsulted,(r->retries > 1) ? r->retries : 0); - ++r->retries; - nextDelay = std::min(nextDelay,(unsigned long)ZT_WHOIS_RETRY_DELAY); + ++txi; } } else { - nextDelay = std::min(nextDelay,ZT_WHOIS_RETRY_DELAY - since); + ++txi; } } } +} - { // Time out TX queue packets that never got WHOIS lookups or other info. +unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) +{ + const uint64_t timeSinceLastCheck = now - _lastCheckedQueues; + if (timeSinceLastCheck < ZT_WHOIS_RETRY_DELAY) + return (unsigned long)(ZT_WHOIS_RETRY_DELAY - timeSinceLastCheck); + _lastCheckedQueues = now; + + { Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { if (_trySend(tPtr,txi->packet,txi->encrypt)) { _txQueue.erase(txi++); } else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { RR->t->txTimedOut(tPtr,txi->dest); - _txQueue.erase(txi++); - } else ++txi; + _txQueue.erase(txi); + ++txi; + } else if (!RR->topology->getPeer(tPtr,txi->dest)) { + requestWhois(tPtr,now,txi->dest); + ++txi; + } else { + ++txi; + } + } + } + + for(unsigned int ptr=0;ptrtimestamp)&&(rq->complete)) { + if ((rq->frag0.tryDecode(RR,tPtr))||((now - rq->timestamp) > ZT_RECEIVE_QUEUE_TIMEOUT)) { + rq->timestamp = 0; + } else { + const Address src(rq->frag0.source()); + if (!RR->topology->getPeer(tPtr,src)) + requestWhois(tPtr,now,src); + } } } - { // Remove really old last unite attempt entries to keep table size controlled + { Mutex::Lock _l(_lastUniteAttempt_m); Hashtable< _LastUniteKey,uint64_t >::Iterator i(_lastUniteAttempt); _LastUniteKey *k = (_LastUniteKey *)0; @@ -650,7 +655,18 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) } } - return nextDelay; + { + Mutex::Lock _l(_lastSentWhoisRequest_m); + Hashtable< Address,uint64_t >::Iterator i(_lastSentWhoisRequest); + Address *a = (Address *)0; + uint64_t *ts = (uint64_t *)0; + while (i.next(a,ts)) { + if ((now - *ts) > (ZT_WHOIS_RETRY_DELAY * 2)) + _lastSentWhoisRequest.erase(*a); + } + } + + return ZT_WHOIS_RETRY_DELAY; } bool Switch::_shouldUnite(const uint64_t now,const Address &source,const Address &destination) @@ -664,18 +680,6 @@ bool Switch::_shouldUnite(const uint64_t now,const Address &source,const Address return false; } -Address Switch::_sendWhoisRequest(void *tPtr,const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted) -{ - SharedPtr upstream(RR->topology->getUpstreamPeer(peersAlreadyConsulted,numPeersAlreadyConsulted,false)); - if (upstream) { - Packet outp(upstream->address(),RR->identity.address(),Packet::VERB_WHOIS); - addr.appendTo(outp); - RR->node->expectReplyTo(outp.packetId()); - send(tPtr,outp,true); - } - return Address(); -} - bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) { SharedPtr viaPath; @@ -709,7 +713,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) } } } else { - requestWhois(tPtr,destination); + requestWhois(tPtr,now,destination); return false; // if we are not in cluster mode, there is no way we can send without knowing the peer directly } diff --git a/node/Switch.hpp b/node/Switch.hpp index 88415541..2420607d 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -111,9 +111,10 @@ public: * Request WHOIS on a given address * * @param tPtr Thread pointer to be handed through to any callbacks called as a result of this call + * @param now Current time * @param addr Address to look up */ - void requestWhois(void *tPtr,const Address &addr); + void requestWhois(void *tPtr,const uint64_t now,const Address &addr); /** * Run any processes that are waiting for this peer's identity @@ -139,34 +140,27 @@ public: private: bool _shouldUnite(const uint64_t now,const Address &source,const Address &destination); - Address _sendWhoisRequest(void *tPtr,const Address &addr,const Address *peersAlreadyConsulted,unsigned int numPeersAlreadyConsulted); bool _trySend(void *tPtr,Packet &packet,bool encrypt); // packet is modified if return is true const RuntimeEnvironment *const RR; uint64_t _lastBeaconResponse; + uint64_t _lastCheckedQueues; - // Outstanding WHOIS requests and how many retries they've undergone - struct WhoisRequest - { - WhoisRequest() : lastSent(0),retries(0) {} - uint64_t lastSent; - Address peersConsulted[ZT_MAX_WHOIS_RETRIES]; // by retry - unsigned int retries; // 0..ZT_MAX_WHOIS_RETRIES - }; - Hashtable< Address,WhoisRequest > _outstandingWhoisRequests; - Mutex _outstandingWhoisRequests_m; + // Time we last sent a WHOIS request for each address + Hashtable< Address,uint64_t > _lastSentWhoisRequest; + Mutex _lastSentWhoisRequest_m; // Packets waiting for WHOIS replies or other decode info or missing fragments struct RXQueueEntry { RXQueueEntry() : timestamp(0) {} - uint64_t timestamp; // 0 if entry is not in use - uint64_t packetId; + volatile uint64_t timestamp; // 0 if entry is not in use + volatile uint64_t packetId; IncomingPacket frag0; // head of packet Packet::Fragment frags[ZT_MAX_PACKET_FRAGMENTS - 1]; // later fragments (if any) unsigned int totalFragments; // 0 if only frag0 received, waiting for frags uint32_t haveFragments; // bit mask, LSB to MSB - bool complete; // if true, packet is complete + volatile bool complete; // if true, packet is complete }; RXQueueEntry _rxQueue[ZT_RX_QUEUE_SIZE]; AtomicCounter _rxQueuePtr; diff --git a/node/Tag.cpp b/node/Tag.cpp index 39b17f2a..bde41a70 100644 --- a/node/Tag.cpp +++ b/node/Tag.cpp @@ -30,6 +30,7 @@ #include "Topology.hpp" #include "Switch.hpp" #include "Network.hpp" +#include "Node.hpp" namespace ZeroTier { @@ -39,7 +40,7 @@ int Tag::verify(const RuntimeEnvironment *RR,void *tPtr) const return -1; const Identity id(RR->topology->getIdentity(tPtr,_signedBy)); if (!id) { - RR->sw->requestWhois(tPtr,_signedBy); + RR->sw->requestWhois(tPtr,RR->node->now(),_signedBy); return 1; } try { diff --git a/node/Topology.cpp b/node/Topology.cpp index aeca59a7..ee5d969d 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -154,13 +154,11 @@ Identity Topology::getIdentity(void *tPtr,const Address &zta) return Identity(); } -SharedPtr Topology::getUpstreamPeer(const Address *avoid,unsigned int avoidCount,bool strictAvoid) +SharedPtr Topology::getUpstreamPeer() { const uint64_t now = RR->node->now(); - unsigned int bestQualityOverall = ~((unsigned int)0); - unsigned int bestQualityNotAvoid = ~((unsigned int)0); - const SharedPtr *bestOverall = (const SharedPtr *)0; - const SharedPtr *bestNotAvoid = (const SharedPtr *)0; + unsigned int bestq = ~((unsigned int)0); + const SharedPtr *best = (const SharedPtr *)0; Mutex::Lock _l1(_peers_m); Mutex::Lock _l2(_upstreams_m); @@ -168,32 +166,17 @@ SharedPtr Topology::getUpstreamPeer(const Address *avoid,unsigned int avoi for(std::vector
::const_iterator a(_upstreamAddresses.begin());a!=_upstreamAddresses.end();++a) { const SharedPtr *p = _peers.get(*a); if (p) { - bool avoiding = false; - for(unsigned int i=0;iaddress()) { - avoiding = true; - break; - } - } const unsigned int q = (*p)->relayQuality(now); - if (q <= bestQualityOverall) { - bestQualityOverall = q; - bestOverall = &(*p); - } - if ((!avoiding)&&(q <= bestQualityNotAvoid)) { - bestQualityNotAvoid = q; - bestNotAvoid = &(*p); + if (q <= bestq) { + bestq = q; + best = p; } } } - if (bestNotAvoid) { - return *bestNotAvoid; - } else if ((!strictAvoid)&&(bestOverall)) { - return *bestOverall; - } - - return SharedPtr(); + if (!best) + return SharedPtr(); + return *best; } bool Topology::isUpstream(const Identity &id) const diff --git a/node/Topology.hpp b/node/Topology.hpp index 04dfb1cc..43921896 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -127,19 +127,9 @@ public: /** * Get the current best upstream peer * - * @return Root server with lowest latency or NULL if none + * @return Upstream or NULL if none available */ - inline SharedPtr getUpstreamPeer() { return getUpstreamPeer((const Address *)0,0,false); } - - /** - * Get the current best upstream peer, avoiding those in the supplied avoid list - * - * @param avoid Nodes to avoid - * @param avoidCount Number of nodes to avoid - * @param strictAvoid If false, consider avoided root servers anyway if no non-avoid root servers are available - * @return Root server or NULL if none available - */ - SharedPtr getUpstreamPeer(const Address *avoid,unsigned int avoidCount,bool strictAvoid); + SharedPtr getUpstreamPeer(); /** * @param id Identity to check -- cgit v1.2.3 From 180049a27725523e18004769d145ba88a68c799b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 16:55:22 -0700 Subject: Fix pointer bug. --- node/Switch.cpp | 3 +-- node/Switch.hpp | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/node/Switch.cpp b/node/Switch.cpp index 8446602c..388ed672 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -620,8 +620,7 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) _txQueue.erase(txi++); } else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { RR->t->txTimedOut(tPtr,txi->dest); - _txQueue.erase(txi); - ++txi; + _txQueue.erase(txi++); } else if (!RR->topology->getPeer(tPtr,txi->dest)) { requestWhois(tPtr,now,txi->dest); ++txi; diff --git a/node/Switch.hpp b/node/Switch.hpp index 2420607d..c258a255 100644 --- a/node/Switch.hpp +++ b/node/Switch.hpp @@ -144,7 +144,7 @@ private: const RuntimeEnvironment *const RR; uint64_t _lastBeaconResponse; - uint64_t _lastCheckedQueues; + volatile uint64_t _lastCheckedQueues; // Time we last sent a WHOIS request for each address Hashtable< Address,uint64_t > _lastSentWhoisRequest; -- cgit v1.2.3 From 0a9c3b557181a77f059d4b2957f6a02f7cc5bde5 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 16:59:31 -0700 Subject: Fix possible deadlock. --- node/Switch.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/node/Switch.cpp b/node/Switch.cpp index 388ed672..62c3f450 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -613,6 +613,7 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) return (unsigned long)(ZT_WHOIS_RETRY_DELAY - timeSinceLastCheck); _lastCheckedQueues = now; + std::vector
needWhois; { Mutex::Lock _l(_txQueue_m); for(std::list< TXQueueEntry >::iterator txi(_txQueue.begin());txi!=_txQueue.end();) { @@ -621,14 +622,15 @@ unsigned long Switch::doTimerTasks(void *tPtr,uint64_t now) } else if ((now - txi->creationTime) > ZT_TRANSMIT_QUEUE_TIMEOUT) { RR->t->txTimedOut(tPtr,txi->dest); _txQueue.erase(txi++); - } else if (!RR->topology->getPeer(tPtr,txi->dest)) { - requestWhois(tPtr,now,txi->dest); - ++txi; } else { + if (!RR->topology->getPeer(tPtr,txi->dest)) + needWhois.push_back(txi->dest); ++txi; } } } + for(std::vector
::const_iterator i(needWhois.begin());i!=needWhois.end();++i) + requestWhois(tPtr,now,*i); for(unsigned int ptr=0;ptr Date: Wed, 23 Aug 2017 17:14:06 -0700 Subject: Fix another deadlock. --- node/Switch.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/node/Switch.cpp b/node/Switch.cpp index 62c3f450..fce12622 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -544,11 +544,16 @@ void Switch::onLocalEthernet(void *tPtr,const SharedPtr &network,const void Switch::send(void *tPtr,Packet &packet,bool encrypt) { - if (packet.destination() == RR->identity.address()) + const Address dest(packet.destination()); + if (dest == RR->identity.address()) return; if (!_trySend(tPtr,packet,encrypt)) { - Mutex::Lock _l(_txQueue_m); - _txQueue.push_back(TXQueueEntry(packet.destination(),RR->node->now(),packet,encrypt)); + { + Mutex::Lock _l(_txQueue_m); + _txQueue.push_back(TXQueueEntry(dest,RR->node->now(),packet,encrypt)); + } + if (!RR->topology->getPeer(tPtr,dest)) + requestWhois(tPtr,RR->node->now(),dest); } } @@ -714,7 +719,6 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) } } } else { - requestWhois(tPtr,now,destination); return false; // if we are not in cluster mode, there is no way we can send without knowing the peer directly } -- cgit v1.2.3 From dd8b03a5c55baf7349ce075c8f4cad1d59cbe988 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 18:28:40 -0700 Subject: Threading issue fix? --- node/Peer.cpp | 7 +++++-- node/Switch.cpp | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/node/Peer.cpp b/node/Peer.cpp index 127f222c..b3020854 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -424,18 +424,21 @@ void Peer::redirect(void *tPtr,const int64_t localSocket,const InetAddress &remo SharedPtr op; SharedPtr np(RR->topology->getPath(localSocket,remoteAddress)); + np->received(now); attemptToContactAt(tPtr,localSocket,remoteAddress,now,true,np->nextOutgoingCounter()); { Mutex::Lock _l(_paths_m); if (remoteAddress.ss_family == AF_INET) { op = _v4Path.p; - _v4Path.p = np; + _v4Path.lr = now; _v4Path.sticky = now; + _v4Path.p = np; } else if (remoteAddress.ss_family == AF_INET6) { op = _v6Path.p; - _v6Path.p = np; + _v6Path.lr = now; _v6Path.sticky = now; + _v6Path.p = np; } } diff --git a/node/Switch.cpp b/node/Switch.cpp index fce12622..952bdef8 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -719,7 +719,7 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) } } } else { - return false; // if we are not in cluster mode, there is no way we can send without knowing the peer directly + return false; } unsigned int chunkSize = std::min(packet.size(),(unsigned int)ZT_UDP_DEFAULT_PAYLOAD_MTU); -- cgit v1.2.3 From 49fa30d495c0524a15ba86668f4fee12b9715089 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Aug 2017 18:52:32 -0700 Subject: Ticket lock for x64/gcc/clang platforms. --- node/Mutex.hpp | 84 +++++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 63 insertions(+), 21 deletions(-) diff --git a/node/Mutex.hpp b/node/Mutex.hpp index 854f321a..b16f53f7 100644 --- a/node/Mutex.hpp +++ b/node/Mutex.hpp @@ -32,32 +32,84 @@ #ifdef __UNIX_LIKE__ +#include #include #include namespace ZeroTier { +#if defined(__GNUC__) && (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64)) + +// Inline ticket lock on x64 systems with GCC and CLANG (Mac, Linux) -- this is really fast as long as locking durations are very short class Mutex : NonCopyable { public: - Mutex() + Mutex() : + nextTicket(0), + nowServing(0) { - pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0); } - ~Mutex() + inline void lock() const { - pthread_mutex_destroy(&_mh); + const uint16_t myTicket = __sync_fetch_and_add(&(const_cast(this)->nextTicket),1); + while (nowServing != myTicket) { + __asm__ __volatile__("rep;nop"::); + __asm__ __volatile__("":::"memory"); + } } - inline void lock() + inline void unlock() const { - pthread_mutex_lock(&_mh); + ++(const_cast(this)->nowServing); } - inline void unlock() + /** + * Uses C++ contexts and constructor/destructor to lock/unlock automatically + */ + class Lock : NonCopyable { - pthread_mutex_unlock(&_mh); + public: + Lock(Mutex &m) : + _m(&m) + { + m.lock(); + } + + Lock(const Mutex &m) : + _m(const_cast(&m)) + { + _m->lock(); + } + + ~Lock() + { + _m->unlock(); + } + + private: + Mutex *const _m; + }; + +private: + uint16_t nextTicket; + uint16_t nowServing; +}; + +#else + +// libpthread based mutex lock +class Mutex : NonCopyable +{ +public: + Mutex() + { + pthread_mutex_init(&_mh,(const pthread_mutexattr_t *)0); + } + + ~Mutex() + { + pthread_mutex_destroy(&_mh); } inline void lock() const @@ -70,9 +122,6 @@ public: (const_cast (this))->unlock(); } - /** - * Uses C++ contexts and constructor/destructor to lock/unlock automatically - */ class Lock : NonCopyable { public: @@ -101,6 +150,8 @@ private: pthread_mutex_t _mh; }; +#endif + } // namespace ZeroTier #endif // Apple / Linux @@ -112,6 +163,7 @@ private: namespace ZeroTier { +// Windows critical section based lock class Mutex : NonCopyable { public: @@ -125,16 +177,6 @@ public: DeleteCriticalSection(&_cs); } - inline void lock() - { - EnterCriticalSection(&_cs); - } - - inline void unlock() - { - LeaveCriticalSection(&_cs); - } - inline void lock() const { (const_cast (this))->lock(); -- cgit v1.2.3 From 6418d02572d91b0e53b030642d997573181d8c6b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 24 Aug 2017 15:33:24 -0700 Subject: Fix HTTP DELETE stupid bug. --- service/OneService.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/service/OneService.cpp b/service/OneService.cpp index 2da72461..093d9ee8 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -1728,9 +1728,10 @@ public: case TcpConnection::TCP_UNCATEGORIZED_INCOMING: switch(reinterpret_cast(data)[0]) { - // HTTP: GET, PUT, POST, HEAD + // HTTP: GET, PUT, POST, HEAD, DELETE case 'G': case 'P': + case 'D': case 'H': { // This is only allowed from IPs permitted to access the management // backplane, which is just 127.0.0.1/::1 unless otherwise configured. @@ -2313,7 +2314,7 @@ public: fprintf(stderr,"WARNING: unexpected exception processing control HTTP request: %s" ZT_EOL_S,exc.what()); scode = 500; } catch ( ... ) { - fprintf(stderr,"WARNING: unexpected exception processing control HTTP request: unknown exceptino" ZT_EOL_S); + fprintf(stderr,"WARNING: unexpected exception processing control HTTP request: unknown exception" ZT_EOL_S); scode = 500; } -- cgit v1.2.3 From e51e212b9543b82a3994b730a39aed7796c29ea1 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 25 Aug 2017 16:04:04 -0700 Subject: Add some defines of use to low level developers. --- include/ZeroTierOne.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index e6ec8090..2a970d5b 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -92,6 +92,21 @@ extern "C" { */ #define ZT_MAX_MTU 10000 +/** + * Maximum physical UDP payload + */ +#define ZT_MAX_PHYSPAYLOAD 10100 + +/** + * Headroom for max physical MTU + */ +#define ZT_MAX_HEADROOM 224 + +/** + * Maximum physical MTU + */ +#define ZT_MAX_PHYSMTU (ZT_MAX_PHYSPAYLOAD + ZT_MAX_HEADROOM) + /** * Maximum size of a remote trace message's serialized Dictionary */ -- cgit v1.2.3 From 5bf5d5e9cbf799987897fd3ea07e212c1ff1ab6c Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 30 Aug 2017 17:22:25 -0700 Subject: Minor controller stuff. --- controller/EmbeddedNetworkController.cpp | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 0f342fa5..8d5febd9 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -1242,7 +1242,7 @@ void EmbeddedNetworkController::_request( _initMember(member); { - std::string haveIdStr(OSUtils::jsonString(member["identity"],"")); + const std::string haveIdStr(OSUtils::jsonString(member["identity"],"")); if (haveIdStr.length() > 0) { // If we already know this member's identity perform a full compare. This prevents // a "collision" from being able to auth onto our network in place of an already @@ -1308,8 +1308,6 @@ void EmbeddedNetworkController::_request( member["lastAuthorizedTime"] = now; member["lastAuthorizedCredentialType"] = autoAuthCredentialType; member["lastAuthorizedCredential"] = autoAuthCredential; - json &revj = member["revision"]; - member["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); } if (authorized) { @@ -1338,6 +1336,7 @@ void EmbeddedNetworkController::_request( if (fromAddr) ms.physicalAddr = fromAddr; + char tmpip[64]; if (ms.physicalAddr) member["physicalAddr"] = ms.physicalAddr.toString(tmpip); @@ -1346,8 +1345,11 @@ void EmbeddedNetworkController::_request( } else { // If they are not authorized, STOP! _removeMemberNonPersistedFields(member); - if (origMember != member) + if (origMember != member) { + json &revj = member["revision"]; + member["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); _db.saveNetworkMember(nwid,identity.address().toInt(),member); + } _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_ACCESS_DENIED); return; } @@ -1710,8 +1712,11 @@ void EmbeddedNetworkController::_request( } _removeMemberNonPersistedFields(member); - if (member != origMember) + if (member != origMember) { + json &revj = member["revision"]; + member["revision"] = (revj.is_number() ? ((uint64_t)revj + 1ULL) : 1ULL); _db.saveNetworkMember(nwid,identity.address().toInt(),member); + } _sender->ncSendConfig(nwid,requestPacketId,identity.address(),*(nc.get()),metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6); } -- cgit v1.2.3 From f39e2e2a53f3f521b79d06681b859c7d9f4f80ca Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Thu, 31 Aug 2017 11:37:29 -0700 Subject: Fixed typo of mysterious origin --- osdep/LinuxEthernetTap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osdep/LinuxEthernetTap.cpp b/osdep/LinuxEthernetTap.cpp index c8f9ef9d..848f3638 100644 --- a/osdep/LinuxEthernetTap.cpp +++ b/osdep/LinuxEthernetTap.cpp @@ -314,7 +314,7 @@ bool LinuxEthernetTap::addIpSyn(std::vector ips) OSUtils::writeFile(filepath.c_str(), cfg_contents.c_str(), cfg_contents.length()); // Finaly, add IPs for(int i=0; i<(int)ips.size(); i++){ - char iptmp[128],iptmp2[128[; + char iptmp[128],iptmp2[128]; if (ips[i].isV4()) ::execlp("ip","ip","addr","add",ips[i].toString(iptmp),"broadcast",ips[i].broadcast().toIpString(iptmp2),"dev",_dev.c_str(),(const char *)0); else -- cgit v1.2.3 From 283e8d5bc00c13f821c67ed7a431af4bd7694113 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 31 Aug 2017 18:01:21 -0400 Subject: Start threads in Central harnessed mode. --- controller/EmbeddedNetworkController.cpp | 16 ++++++++++++++++ controller/EmbeddedNetworkController.hpp | 15 +-------------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/controller/EmbeddedNetworkController.cpp b/controller/EmbeddedNetworkController.cpp index 8d5febd9..1d46d5e6 100644 --- a/controller/EmbeddedNetworkController.cpp +++ b/controller/EmbeddedNetworkController.cpp @@ -434,6 +434,8 @@ EmbeddedNetworkController::EmbeddedNetworkController(Node *node,const char *dbPa _db(dbPath,this), _node(node) { + if ((dbPath[0] == '-')&&(dbPath[1] == 0)) + _startThreads(); // start threads now in Central harnessed mode } EmbeddedNetworkController::~EmbeddedNetworkController() @@ -1721,4 +1723,18 @@ void EmbeddedNetworkController::_request( _sender->ncSendConfig(nwid,requestPacketId,identity.address(),*(nc.get()),metaData.getUI(ZT_NETWORKCONFIG_REQUEST_METADATA_KEY_VERSION,0) < 6); } +void EmbeddedNetworkController::_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 &metaData); - - 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 Date: Thu, 31 Aug 2017 20:47:44 -0400 Subject: Non-x86 build fix. --- node/Mutex.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node/Mutex.hpp b/node/Mutex.hpp index b16f53f7..b68e5d93 100644 --- a/node/Mutex.hpp +++ b/node/Mutex.hpp @@ -114,12 +114,12 @@ public: inline void lock() const { - (const_cast (this))->lock(); + pthread_mutex_lock(&((const_cast (this))->_mh)); } inline void unlock() const { - (const_cast (this))->unlock(); + pthread_mutex_unlock(&((const_cast (this))->_mh)); } class Lock : NonCopyable -- cgit v1.2.3 From b1fb020aea80ea70ed801b876ad01beb09e218e1 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 1 Sep 2017 10:43:44 -0700 Subject: Raise chunk size to max packet size for network configs. Chunking breaks really ancient clients, so this helps them live a little longer. No real downside for new clients. --- node/Node.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/Node.cpp b/node/Node.cpp index 09260172..34609fd4 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -592,7 +592,7 @@ void Node::ncSendConfig(uint64_t nwid,uint64_t requestPacketId,const Address &de const unsigned int totalSize = dconf->sizeBytes(); unsigned int chunkIndex = 0; while (chunkIndex < totalSize) { - const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_UDP_DEFAULT_PAYLOAD_MTU - (ZT_PACKET_IDX_PAYLOAD + 256))); + const unsigned int chunkLen = std::min(totalSize - chunkIndex,(unsigned int)(ZT_PROTO_MAX_PACKET_LENGTH - (ZT_PACKET_IDX_PAYLOAD + 256))); Packet outp(destination,RR->identity.address(),(requestPacketId) ? Packet::VERB_OK : Packet::VERB_NETWORK_CONFIG); if (requestPacketId) { outp.append((unsigned char)Packet::VERB_NETWORK_CONFIG_REQUEST); -- cgit v1.2.3 From 2d858b05ac8554ba11374fefaeb583a0bbc0546b Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 1 Sep 2017 12:03:31 -0700 Subject: Another fix for ye old tyme clients. --- include/ZeroTierOne.h | 11 ++++++++++- node/Constants.hpp | 9 --------- node/NetworkConfig.cpp | 5 +++-- 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index 2a970d5b..b889ade0 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -92,6 +92,15 @@ extern "C" { */ #define ZT_MAX_MTU 10000 +/** + * Default payload MTU for UDP packets + * + * This is 1500 - IPv6 UDP overhead - PPPoE overhead and is safe for 99.9% of + * all Internet links. + */ +#define ZT_DEFAULT_PHYSMTU 1444 +#define ZT_UDP_DEFAULT_PAYLOAD_MTU 1444 + /** * Maximum physical UDP payload */ @@ -103,7 +112,7 @@ extern "C" { #define ZT_MAX_HEADROOM 224 /** - * Maximum physical MTU + * Maximum payload MTU for UDP packets */ #define ZT_MAX_PHYSMTU (ZT_MAX_PHYSPAYLOAD + ZT_MAX_HEADROOM) diff --git a/node/Constants.hpp b/node/Constants.hpp index cda1af3b..651fe50d 100644 --- a/node/Constants.hpp +++ b/node/Constants.hpp @@ -171,15 +171,6 @@ */ #define ZT_ADDRESS_RESERVED_PREFIX 0xff -/** - * Default payload MTU for UDP packets - * - * In the future we might support UDP path MTU discovery, but for now we - * set a maximum that is equal to 1500 minus 8 (for PPPoE overhead, common - * in some markets) minus 48 (IPv6 UDP overhead). - */ -#define ZT_UDP_DEFAULT_PAYLOAD_MTU 1444 - /** * Default MTU used for Ethernet tap device */ diff --git a/node/NetworkConfig.cpp b/node/NetworkConfig.cpp index 0bf4bc19..110a20b0 100644 --- a/node/NetworkConfig.cpp +++ b/node/NetworkConfig.cpp @@ -35,6 +35,7 @@ namespace ZeroTier { bool NetworkConfig::toDictionary(Dictionary &d,bool includeLegacy) const { Buffer *tmp = new Buffer(); + char tmp2[128]; try { d.clear(); @@ -46,8 +47,8 @@ bool NetworkConfig::toDictionary(Dictionary &d,b if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TIMESTAMP,this->timestamp)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_CREDENTIAL_TIME_MAX_DELTA,this->credentialTimeMaxDelta)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REVISION,this->revision)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo)) return false; - if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET,this->remoteTraceTarget)) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_ISSUED_TO,this->issuedTo.toString(tmp2))) return false; + if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_REMOTE_TRACE_TARGET,this->remoteTraceTarget.toString(tmp2))) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_FLAGS,this->flags)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_MULTICAST_LIMIT,(uint64_t)this->multicastLimit)) return false; if (!d.add(ZT_NETWORKCONFIG_DICT_KEY_TYPE,(uint64_t)this->type)) return false; -- cgit v1.2.3 From f8014413a376551b7853baae81072f969a755e46 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 1 Sep 2017 16:25:34 -0700 Subject: Add UDP MTU configurability. --- include/ZeroTierOne.h | 55 +++++++++++++++-------------- node/Multicaster.cpp | 2 +- node/Network.cpp | 1 - node/Node.cpp | 14 ++++---- node/Node.hpp | 2 +- node/Packet.hpp | 6 +--- node/Switch.cpp | 13 ++++--- node/Topology.cpp | 2 +- node/Topology.hpp | 95 ++++++++++++++++++++++++++++++++++++++------------ service/OneService.cpp | 25 ++++++------- service/README.md | 3 +- 11 files changed, 134 insertions(+), 84 deletions(-) diff --git a/include/ZeroTierOne.h b/include/ZeroTierOne.h index b889ade0..7cbebb32 100644 --- a/include/ZeroTierOne.h +++ b/include/ZeroTierOne.h @@ -93,13 +93,17 @@ extern "C" { #define ZT_MAX_MTU 10000 /** - * Default payload MTU for UDP packets + * Minimum UDP payload size allowed + */ +#define ZT_MIN_PHYSMTU 1400 + +/** + * Default UDP payload size (physical path MTU) not including UDP and IP overhead * * This is 1500 - IPv6 UDP overhead - PPPoE overhead and is safe for 99.9% of * all Internet links. */ #define ZT_DEFAULT_PHYSMTU 1444 -#define ZT_UDP_DEFAULT_PAYLOAD_MTU 1444 /** * Maximum physical UDP payload @@ -172,9 +176,9 @@ extern "C" { #define ZT_MAX_PEER_NETWORK_PATHS 4 /** - * Maximum number of trusted physical network paths + * Maximum number of path configurations that can be set */ -#define ZT_MAX_TRUSTED_PATHS 16 +#define ZT_MAX_CONFIGURABLE_PATHS 32 /** * Maximum number of rules per capability @@ -1058,11 +1062,6 @@ typedef struct */ unsigned int mtu; - /** - * Recommended MTU to avoid fragmentation at the physical layer (hint) - */ - unsigned int physicalMtu; - /** * If nonzero, the network this port belongs to indicates DHCP availability * @@ -1132,6 +1131,21 @@ typedef struct unsigned long networkCount; } ZT_VirtualNetworkList; +/** + * Physical path configuration + */ +typedef struct { + /** + * If non-zero set this physical network path to be trusted to disable encryption and authentication + */ + uint64_t trustedPathId; + + /** + * Physical path MTU from ZT_MIN_PHYSMTU and ZT_MAX_PHYSMTU or <= 0 to use default + */ + int mtu; +} ZT_PhysicalPathConfiguration; + /** * Physical network path to a peer */ @@ -1856,27 +1870,14 @@ ZT_SDK_API int ZT_Node_sendUserMessage(ZT_Node *node,void *tptr,uint64_t dest,ui ZT_SDK_API void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkConfigMasterInstance); /** - * Set trusted paths - * - * A trusted path is a physical network (network/bits) over which both - * encryption and authentication can be skipped to improve performance. - * Each trusted path must have a non-zero unique ID that is the same across - * all participating nodes. - * - * We don't recommend using trusted paths at all unless you really *need* - * near-bare-metal performance. Even on a LAN authentication and encryption - * are never a bad thing, and anything that introduces an "escape hatch" - * for encryption should be treated with the utmost care. - * - * Calling with NULL pointers for networks and ids and a count of zero clears - * all trusted paths. + * Set configuration for a given physical path * * @param node Node instance - * @param networks Array of [count] networks - * @param ids Array of [count] corresponding non-zero path IDs (zero path IDs are ignored) - * @param count Number of trusted paths-- values greater than ZT_MAX_TRUSTED_PATHS are clipped + * @param pathNetwork Network/CIDR of path or NULL to clear the cache and reset all paths to default + * @param pathConfig Path configuration or NULL to erase this entry and therefore reset it to NULL + * @return OK or error code */ -ZT_SDK_API void ZT_Node_setTrustedPaths(ZT_Node *node,const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count); +ZT_SDK_API enum ZT_ResultCode ZT_Node_setPhysicalPathConfiguration(ZT_Node *node,const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig); /** * Get ZeroTier One version diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index fb7b068f..e8c8613a 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -111,7 +111,7 @@ unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const // Members are returned in random order so that repeated gather queries // will return different subsets of a large multicast group. k = 0; - while ((added < limit)&&(k < s->members.size())&&((appendTo.size() + ZT_ADDRESS_LENGTH) <= ZT_UDP_DEFAULT_PAYLOAD_MTU)) { + while ((added < limit)&&(k < s->members.size())&&((appendTo.size() + ZT_ADDRESS_LENGTH) <= ZT_PROTO_MAX_PACKET_LENGTH)) { rptr = (unsigned int)RR->node->prng(); restart_member_scan: diff --git a/node/Network.cpp b/node/Network.cpp index f7b144e3..16155c33 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -1346,7 +1346,6 @@ void Network::_externalConfig(ZT_VirtualNetworkConfig *ec) const ec->status = _status(); ec->type = (_config) ? (_config.isPrivate() ? ZT_NETWORK_TYPE_PRIVATE : ZT_NETWORK_TYPE_PUBLIC) : ZT_NETWORK_TYPE_PRIVATE; ec->mtu = (_config) ? _config.mtu : ZT_DEFAULT_MTU; - ec->physicalMtu = ZT_UDP_DEFAULT_PAYLOAD_MTU - (ZT_PACKET_IDX_PAYLOAD + 16); ec->dhcp = 0; std::vector
ab(_config.activeBridges()); ec->bridge = ((_config.allowPassiveBridging())||(std::find(ab.begin(),ab.end(),RR->identity.address()) != ab.end())) ? 1 : 0; diff --git a/node/Node.cpp b/node/Node.cpp index 34609fd4..871fb21b 100644 --- a/node/Node.cpp +++ b/node/Node.cpp @@ -561,9 +561,9 @@ uint64_t Node::prng() return z + y; } -void Node::setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count) +ZT_ResultCode Node::setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork, const ZT_PhysicalPathConfiguration *pathConfig) { - RR->topology->setTrustedPaths(reinterpret_cast(networks),ids,count); + return ZT_RESULT_OK; } World Node::planet() const @@ -815,7 +815,7 @@ enum ZT_ResultCode ZT_Node_orbit(ZT_Node *node,void *tptr,uint64_t moonWorldId,u } } -ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t moonWorldId) +enum ZT_ResultCode ZT_Node_deorbit(ZT_Node *node,void *tptr,uint64_t moonWorldId) { try { return reinterpret_cast(node)->deorbit(tptr,moonWorldId); @@ -902,11 +902,13 @@ void ZT_Node_setNetconfMaster(ZT_Node *node,void *networkControllerInstance) } catch ( ... ) {} } -void ZT_Node_setTrustedPaths(ZT_Node *node,const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count) +enum ZT_ResultCode ZT_Node_setPhysicalPathConfiguration(ZT_Node *node,const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig) { try { - reinterpret_cast(node)->setTrustedPaths(networks,ids,count); - } catch ( ... ) {} + return reinterpret_cast(node)->setPhysicalPathConfiguration(pathNetwork,pathConfig); + } catch ( ... ) { + return ZT_RESULT_FATAL_ERROR_INTERNAL; + } } void ZT_version(int *major,int *minor,int *revision) diff --git a/node/Node.hpp b/node/Node.hpp index 9658174f..1aa01c9a 100644 --- a/node/Node.hpp +++ b/node/Node.hpp @@ -192,7 +192,7 @@ public: inline bool externalPathLookup(void *tPtr,const Address &ztaddr,int family,InetAddress &addr) { return ( (_cb.pathLookupFunction) ? (_cb.pathLookupFunction(reinterpret_cast(this),_uPtr,tPtr,ztaddr.toInt(),family,reinterpret_cast(&addr)) != 0) : false ); } uint64_t prng(); - void setTrustedPaths(const struct sockaddr_storage *networks,const uint64_t *ids,unsigned int count); + ZT_ResultCode setPhysicalPathConfiguration(const struct sockaddr_storage *pathNetwork,const ZT_PhysicalPathConfiguration *pathConfig); World planet() const; std::vector moons() const; diff --git a/node/Packet.hpp b/node/Packet.hpp index 5fc631b1..db70e06f 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -225,12 +225,8 @@ /** * Packet buffer size (can be changed) - * - * The current value is big enough for ZT_MAX_PACKET_FRAGMENTS, the pragmatic - * packet fragment limit, times the default UDP MTU. Most packets won't be - * this big. */ -#define ZT_PROTO_MAX_PACKET_LENGTH (ZT_MAX_PACKET_FRAGMENTS * ZT_UDP_DEFAULT_PAYLOAD_MTU) +#define ZT_PROTO_MAX_PACKET_LENGTH (ZT_MAX_PACKET_FRAGMENTS * ZT_DEFAULT_PHYSMTU) /** * Minimum viable packet length (a.k.a. header length) diff --git a/node/Switch.cpp b/node/Switch.cpp index 952bdef8..f46b3e73 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -722,10 +722,13 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) return false; } - unsigned int chunkSize = std::min(packet.size(),(unsigned int)ZT_UDP_DEFAULT_PAYLOAD_MTU); + unsigned int mtu = ZT_DEFAULT_PHYSMTU; + uint64_t trustedPathId = 0; + RR->topology->getOutboundPathInfo(viaPath->address(),mtu,trustedPathId); + + unsigned int chunkSize = std::min(packet.size(),mtu); packet.setFragmented(chunkSize < packet.size()); - const uint64_t trustedPathId = RR->topology->getOutboundPathTrust(viaPath->address()); if (trustedPathId) { packet.setTrusted(trustedPathId); } else { @@ -737,13 +740,13 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt) // Too big for one packet, fragment the rest unsigned int fragStart = chunkSize; unsigned int remaining = packet.size() - chunkSize; - unsigned int fragsRemaining = (remaining / (ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH)); - if ((fragsRemaining * (ZT_UDP_DEFAULT_PAYLOAD_MTU - ZT_PROTO_MIN_FRAGMENT_LENGTH)) < remaining) + unsigned int fragsRemaining = (remaining / (mtu - ZT_PROTO_MIN_FRAGMENT_LENGTH)); + if ((fragsRemaining * (mtu - ZT_PROTO_MIN_FRAGMENT_LENGTH)) < remaining) ++fragsRemaining; const unsigned int totalFragments = fragsRemaining + 1; for(unsigned int fno=1;fnosend(RR,tPtr,frag.data(),frag.size(),now); fragStart += chunkSize; diff --git a/node/Topology.cpp b/node/Topology.cpp index ee5d969d..905b6a91 100644 --- a/node/Topology.cpp +++ b/node/Topology.cpp @@ -65,7 +65,7 @@ static const unsigned char ZT_DEFAULT_WORLD[ZT_DEFAULT_WORLD_LENGTH] = {0x01,0x0 Topology::Topology(const RuntimeEnvironment *renv,void *tPtr) : RR(renv), - _trustedPathCount(0), + _numConfiguredPhysicalPaths(0), _amRoot(false) { uint8_t tmp[ZT_WORLD_MAX_SERIALIZED_LENGTH]; diff --git a/node/Topology.hpp b/node/Topology.hpp index 43921896..34df28a1 100644 --- a/node/Topology.hpp +++ b/node/Topology.hpp @@ -339,6 +339,41 @@ public: */ inline bool amRoot() const { return _amRoot; } + /** + * Get info about a path + * + * The supplied result variables are not modified if no special config info is found. + * + * @param physicalAddress Physical endpoint address + * @param mtu Variable set to MTU + * @param trustedPathId Variable set to trusted path ID + */ + inline void getOutboundPathInfo(const InetAddress &physicalAddress,unsigned int &mtu,uint64_t &trustedPathId) + { + for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i ZT_MAX_TRUSTED_PATHS) - count = ZT_MAX_TRUSTED_PATHS; - Mutex::Lock _l(_trustedPaths_m); - for(unsigned int i=0;i cpaths; + for(unsigned int i=0,j=_numConfiguredPhysicalPaths;i ZT_MAX_PHYSMTU) + pc.mtu = ZT_MAX_PHYSMTU; + + cpaths[*(reinterpret_cast(pathNetwork))] = pc; + } else { + cpaths.erase(*(reinterpret_cast(pathNetwork))); + } + + unsigned int cnt = 0; + for(std::map::const_iterator i(cpaths.begin());((i!=cpaths.end())&&(cntfirst; + _physicalPathConfig[cnt].second = i->second; + ++cnt; + } + _numConfiguredPhysicalPaths = cnt; } - _trustedPathCount = count; } /** @@ -414,10 +467,8 @@ private: const RuntimeEnvironment *const RR; - uint64_t _trustedPathIds[ZT_MAX_TRUSTED_PATHS]; - InetAddress _trustedPathNetworks[ZT_MAX_TRUSTED_PATHS]; - unsigned int _trustedPathCount; - Mutex _trustedPaths_m; + std::pair _physicalPathConfig[ZT_MAX_CONFIGURABLE_PATHS]; + volatile unsigned int _numConfiguredPhysicalPaths; Hashtable< Address,SharedPtr > _peers; Mutex _peers_m; diff --git a/service/OneService.cpp b/service/OneService.cpp index 093d9ee8..66e9a9c8 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -564,16 +564,14 @@ public: // Read local configuration { - uint64_t trustedPathIds[ZT_MAX_TRUSTED_PATHS]; - InetAddress trustedPathNetworks[ZT_MAX_TRUSTED_PATHS]; - unsigned int trustedPathCount = 0; + std::map ppc; // LEGACY: support old "trustedpaths" flat file FILE *trustpaths = fopen((_homePath + ZT_PATH_SEPARATOR_S "trustedpaths").c_str(),"r"); if (trustpaths) { fprintf(stderr,"WARNING: 'trustedpaths' flat file format is deprecated in favor of path definitions in local.conf" ZT_EOL_S); char buf[1024]; - while ((fgets(buf,sizeof(buf),trustpaths))&&(trustedPathCount < ZT_MAX_TRUSTED_PATHS)) { + while (fgets(buf,sizeof(buf),trustpaths)) { int fno = 0; char *saveptr = (char *)0; uint64_t trustedPathId = 0; @@ -587,9 +585,8 @@ public: ++fno; } if ( (trustedPathId != 0) && ((trustedPathNetwork.ss_family == AF_INET)||(trustedPathNetwork.ss_family == AF_INET6)) && (trustedPathNetwork.ipScope() != InetAddress::IP_SCOPE_GLOBAL) && (trustedPathNetwork.netmaskBits() > 0) ) { - trustedPathIds[trustedPathCount] = trustedPathId; - trustedPathNetworks[trustedPathCount] = trustedPathNetwork; - ++trustedPathCount; + ppc[trustedPathNetwork].trustedPathId = trustedPathId; + ppc[trustedPathNetwork].mtu = 0; // use default } } fclose(trustpaths); @@ -618,12 +615,10 @@ public: if (phy.value().is_object()) { uint64_t tpid; if ((tpid = OSUtils::jsonInt(phy.value()["trustedPathId"],0ULL)) != 0ULL) { - if ( ((net.ss_family == AF_INET)||(net.ss_family == AF_INET6)) && (trustedPathCount < ZT_MAX_TRUSTED_PATHS) && (net.ipScope() != InetAddress::IP_SCOPE_GLOBAL) && (net.netmaskBits() > 0) ) { - trustedPathIds[trustedPathCount] = tpid; - trustedPathNetworks[trustedPathCount] = net; - ++trustedPathCount; - } + if ((net.ss_family == AF_INET)||(net.ss_family == AF_INET6)) + ppc[net].trustedPathId = tpid; } + ppc[net].mtu = (int)OSUtils::jsonInt(phy.value()["mtu"],0ULL); // 0 means use default } } } @@ -638,8 +633,10 @@ public: } // Set trusted paths if there are any - if (trustedPathCount) - _node->setTrustedPaths(reinterpret_cast(trustedPathNetworks),trustedPathIds,trustedPathCount); + if (ppc.size() > 0) { + for(std::map::iterator i(ppc.begin());i!=ppc.end();++i) + _node->setPhysicalPathConfiguration(reinterpret_cast(&(i->first)),&(i->second)); + } } // Apply other runtime configuration from local.conf diff --git a/service/README.md b/service/README.md index f5223f2d..77085a6f 100644 --- a/service/README.md +++ b/service/README.md @@ -14,7 +14,8 @@ Settings available in `local.conf` (this is not valid JSON, and JSON does not al "physical": { /* Settings that apply to physical L2/L3 network paths. */ "NETWORK/bits": { /* Network e.g. 10.0.0.0/24 or fd00::/32 */ "blacklist": true|false, /* If true, blacklist this path for all ZeroTier traffic */ - "trustedPathId": 0|!0 /* If present and nonzero, define this as a trusted path (see below) */ + "trustedPathId": 0|!0, /* If present and nonzero, define this as a trusted path (see below) */ + "mtu": 0|!0 /* if present and non-zero, set UDP maximum payload MTU for this path */ } /* ,... additional networks */ }, "virtual": { /* Settings applied to ZeroTier virtual network devices (VL1) */ -- cgit v1.2.3 From 52916eebcfae2559966d12d4be4b5376289a982d Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Thu, 14 Sep 2017 20:56:50 -0700 Subject: Keep attemting to upgrade direct path if path is not private to facilitate better use of LANs and backplane networks. --- node/Peer.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/node/Peer.cpp b/node/Peer.cpp index b3020854..a954b716 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -194,8 +194,12 @@ void Peer::received( } } } - } else if (this->trustEstablished(now)) { - // Send PUSH_DIRECT_PATHS if hops>0 (relayed) and we have a trust relationship (common network membership) + } + + // If we are being relayed or if we're using a global address, send PUSH_DIRECT_PATHS. + // In the global address case we push only configured direct paths to accomplish + // fall-forward to local backplane networks over e.g. LAN or Amazon VPC. + if ( ((hops > 0)||(path->ipScope() == InetAddress::IP_SCOPE_GLOBAL)) && (this->trustEstablished(now)) ) { if ((now - _lastDirectPathPushSent) >= ZT_DIRECT_PATH_PUSH_INTERVAL) { _lastDirectPathPushSent = now; @@ -205,13 +209,15 @@ void Peer::received( for(std::vector::const_iterator i(dps.begin());i!=dps.end();++i) pathsToPush.push_back(*i); - std::vector sym(RR->sa->getSymmetricNatPredictions()); - for(unsigned long i=0,added=0;inode->prng() % sym.size()]); - if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) { - pathsToPush.push_back(tmp); - if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) - break; + if (hops > 0) { + std::vector sym(RR->sa->getSymmetricNatPredictions()); + for(unsigned long i=0,added=0;inode->prng() % sym.size()]); + if (std::find(pathsToPush.begin(),pathsToPush.end(),tmp) == pathsToPush.end()) { + pathsToPush.push_back(tmp); + if (++added >= ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY) + break; + } } } -- cgit v1.2.3