Merge branch 'dev' into redisrection

This commit is contained in:
Grant Limberg 2022-06-13 13:09:36 -07:00
commit c6fc3560f2
No known key found for this signature in database
GPG key ID: 8F2F97D3BE8D7735
12804 changed files with 2946788 additions and 1833 deletions

68
.drone.jsonnet Normal file
View file

@ -0,0 +1,68 @@
local targets = [
//
// Render these into .drone.yaml by running "make drone"
//
{ "os": "linux", "name": "el9", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag" ] },
{ "os": "linux", "name": "el8", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag" ] },
{ "os": "linux", "name": "el7", "isas": [ "amd64", "ppc64le"], "events": [ "tag" ] },
{ "os": "linux", "name": "el6", "isas": [ "amd64" ], "events": [ "tag" ] },
{ "os": "linux", "name": "amzn2", "isas": [ "amd64", "arm64" ], "events": [ "tag" ] },
{ "os": "linux", "name": "fc37", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag" ] },
{ "os": "linux", "name": "fc36", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag" ] },
{ "os": "linux", "name": "fc35", "isas": [ "amd64", "arm64", "ppc64le", "s390x" ], "events": [ "tag" ] },
{ "os": "linux", "name": "jammy", "isas": [ "amd64", "arm64", "armv7", "riscv64", "ppc64le", "s390x" ], "events": [ "tag" ] },
{ "os": "linux", "name": "focal", "isas": [ "amd64", "arm64", "armv7", "riscv64", "ppc64le" ], "events": [ "tag" ] },
{ "os": "linux", "name": "bionic", "isas": [ "amd64", "arm64", "386", "ppc64le", "s390x" ], "events": ["tag" ] },
{ "os": "linux", "name": "xenial", "isas": [ "amd64", "arm64", "386" ], "events": [ "tag" ] },
{ "os": "linux", "name": "sid", "isas": [ "386", "amd64", "arm64", "armv7", "riscv64", "mips64le", "ppc64le", "s390x" ], "events": [ "push", "tag" ] },
{ "os": "linux", "name": "bookworm", "isas": [ "amd64", "arm64", "armv7", "386", "mips64le", "ppc64le", "s390x" ], "events": [ "tag" ] },
{ "os": "linux", "name": "bullseye", "isas": [ "amd64", "arm64", "armv7", "386", "mips64le", "ppc64le", "s390x" ], "events": [ "tag" ] },
{ "os": "linux", "name": "buster", "isas": [ "amd64", "arm64", "armv7", "386", "mips64le", "ppc64le", "s390x" ], "events": [ "tag" ] },
{ "os": "linux", "name": "stretch", "isas": [ "amd64", "arm64", "386" ], "events": [ "tag" ] },
// { "os": "windows", "name": "win2k19", "isas": [ "amd64" ], "events": ["push", "tag" ] }
];
local Build(platform, os, isa, events) = {
"kind": "pipeline",
"type": "docker",
"pull": "always",
"name": platform + " " + isa + " " + "build",
"clone": { "depth": 1 },
"steps": [
{
"name": "build",
"image": "registry.sean.farm/honda-builder",
"commands": [ "./ci/scripts/build.sh " + platform + " " + isa + " " + "100.0.0+${DRONE_COMMIT_SHA:0:8}" + " " + "${DRONE_BUILD_EVENT}" ]
},
{
"name": "list",
"image": "registry.sean.farm/honda-builder",
"commands": [ "ls -la " + platform ]
},
{
"name": "notify-mattermost",
"image": "registry.sean.farm/mattermost-notify",
"environment": {
"token": { "from_secret": "mattermost-token" },
"host": { "from_secret": "mattermost-host" },
"channel": { "from_secret": "mattermost-channel" },
"maxRetry": 3,
},
"when": { "status": [ "failure" ] }
}
],
"image_pull_secrets": [ "dockerconfigjson" ],
[ if isa == "arm64" || isa == "armv7" then "platform" ]: { os: os, arch: "arm64" },
"trigger": { "event": events }
};
// puttin on the bits
std.flattenArrays([
[
Build(p.name, p.os, isa, p.events)
for isa in p.isas
]
for p in targets
])

2778
.drone.yml

File diff suppressed because it is too large Load diff

10
.gitignore vendored
View file

@ -6,6 +6,11 @@
/zerotier /zerotier
/nltest /nltest
# IDE stuff
/.idea
/.nova
/compile_commands.json
# OS-created garbage files from various platforms # OS-created garbage files from various platforms
.DS_Store .DS_Store
.Apple* .Apple*
@ -30,7 +35,6 @@ Thumbs.db
/windows/WebUIWrapper/obj /windows/WebUIWrapper/obj
/windows/lib /windows/lib
/ext/installfiles/windows/ZeroTier One-SetupFiles /ext/installfiles/windows/ZeroTier One-SetupFiles
/ext/installfiles/windows/Prerequisites
/ext/installfiles/windows/*-cache /ext/installfiles/windows/*-cache
/ZeroTier One.msi /ZeroTier One.msi
*.vcxproj.backup *.vcxproj.backup
@ -58,7 +62,6 @@ zt1-src.tar.gz
*.opensdf *.opensdf
*.user *.user
*.cache *.cache
*.obj
*.tlog *.tlog
*.pid *.pid
*.pkg *.pkg
@ -103,7 +106,6 @@ windows/ZeroTierOne/Debug/
*.swp *.swp
*~.nib *~.nib
DerivedData/ DerivedData/
build/
*.pbxuser *.pbxuser
*.mode1v3 *.mode1v3
*.mode2v3 *.mode2v3
@ -114,7 +116,6 @@ build/
!default.perspectivev3 !default.perspectivev3
*.xccheckout *.xccheckout
xcuserdata/ xcuserdata/
ext/librethinkdbxx/build
.vscode .vscode
__pycache__ __pycache__
*~ *~
@ -123,7 +124,6 @@ attic/world/mkworld
workspace/ workspace/
workspace2/ workspace2/
zeroidc/target/ zeroidc/target/
tmp/
#snapcraft specifics #snapcraft specifics
/parts/ /parts/

View file

@ -26,3 +26,7 @@ endif
ifeq ($(OSTYPE),NetBSD) ifeq ($(OSTYPE),NetBSD)
include make-netbsd.mk include make-netbsd.mk
endif endif
drone:
@echo "rendering .drone.yaml from .drone.jsonnet"
drone jsonnet --format --stream

View file

@ -1,6 +1,7 @@
ZeroTier - Global Area Networking ZeroTier - Global Area Networking
====== ======
This document is written for a software developer audience. For information on using ZeroTier, see the: [Website](https://www.zerotier.com), [Documentation Site](https://docs.zerotier.com), and [Discussion Forum](https://discuss.zerotier.com)
*This document is written for a software developer audience. For information on using ZeroTier, see the: [Website](https://www.zerotier.com), [Documentation Site](https://docs.zerotier.com), and [Discussion Forum](https://discuss.zerotier.com).*
ZeroTier is a smart programmable Ethernet switch for planet Earth. It allows all networked devices, VMs, containers, and applications to communicate as if they all reside in the same physical data center or cloud region. ZeroTier is a smart programmable Ethernet switch for planet Earth. It allows all networked devices, VMs, containers, and applications to communicate as if they all reside in the same physical data center or cloud region.
@ -42,24 +43,29 @@ The base path contains the ZeroTier One service main entry point (`one.cpp`), se
- `rule-compiler/`: JavaScript rules language compiler for defining network-level rules. - `rule-compiler/`: JavaScript rules language compiler for defining network-level rules.
- `service/`: the ZeroTier One service, which wraps the ZeroTier core and provides VPN-like connectivity to virtual networks for desktops, laptops, servers, VMs, and containers. - `service/`: the ZeroTier One service, which wraps the ZeroTier core and provides VPN-like connectivity to virtual networks for desktops, laptops, servers, VMs, and containers.
- `windows/`: Visual Studio solution files, Windows service code, and the Windows task bar app UI. - `windows/`: Visual Studio solution files, Windows service code, and the Windows task bar app UI.
- `zeroidc/`: OIDC implementation used by ZeroTier service to log into SSO-enabled networks. (This part is written in Rust, and more Rust will be appearing in this repository in the future.)
### Build and Platform Notes ### Build and Platform Notes
To build on Mac and Linux just type `make`. On FreeBSD and OpenBSD `gmake` (GNU make) is required and can be installed from packages or ports. For Windows there is a Visual Studio solution in `windows/`. To build on Mac and Linux just type `make`. On FreeBSD and OpenBSD `gmake` (GNU make) is required and can be installed from packages or ports. For Windows there is a Visual Studio solution in `windows/`.
- **Mac** - **Mac**
- Xcode command line tools for OSX 10.8 or newer are required. - Xcode command line tools for macOS 10.13 or newer are required.
- Rust for x86_64 and ARM64 targets *if SSO is enabled in the build*.
- **Linux** - **Linux**
- The minimum compiler versions required are GCC/G++ 4.9.3 or CLANG/CLANG++ 3.4.2. (Install `clang` on CentOS 7 as G++ is too old.) - The minimum compiler versions required are GCC/G++ 4.9.3 or CLANG/CLANG++ 3.4.2. (Install `clang` on CentOS 7 as G++ is too old.)
- Linux makefiles automatically detect and prefer clang/clang++ if present as it produces smaller and slightly faster binaries in most cases. You can override by supplying CC and CXX variables on the make command line. - Linux makefiles automatically detect and prefer clang/clang++ if present as it produces smaller and slightly faster binaries in most cases. You can override by supplying CC and CXX variables on the make command line.
- Rust for x86_64 and ARM64 targets *if SSO is enabled in the build*.
- **Windows** - **Windows**
- Windows 7 or newer is supported. This *may* work on Vista but isn't officially supported there. It will not work on Windows XP. - Visual Studio 2022 on Windows 10 or newer.
- We build with Visual Studio 2017. Older versions may not work. Clang or MinGW will also probably work but may require some makefile hacking. - Rust for x86_64 and ARM64 targets *if SSO is enabled in the build*.
- **FreeBSD** - **FreeBSD**
- GNU make is required. Type `gmake` to build. - GNU make is required. Type `gmake` to build.
- Rust for x86_64 and ARM64 targets *if SSO is enabled in the build*.
- **OpenBSD** - **OpenBSD**
- There is a limit of four network memberships on OpenBSD as there are only four tap devices (`/dev/tap0` through `/dev/tap3`). - There is a limit of four network memberships on OpenBSD as there are only four tap devices (`/dev/tap0` through `/dev/tap3`).
- GNU make is required. Type `gmake` to build. - GNU make is required. Type `gmake` to build.
- Rust for x86_64 and ARM64 targets *if SSO is enabled in the build*.
Typing `make selftest` will build a *zerotier-selftest* binary which unit tests various internals and reports on a few aspects of the build environment. It's a good idea to try this on novel platforms or architectures. Typing `make selftest` will build a *zerotier-selftest* binary which unit tests various internals and reports on a few aspects of the build environment. It's a good idea to try this on novel platforms or architectures.
@ -82,7 +88,7 @@ Here's where home folders live (by default) on each OS:
* **Linux**: `/var/lib/zerotier-one` * **Linux**: `/var/lib/zerotier-one`
* **FreeBSD** / **OpenBSD**: `/var/db/zerotier-one` * **FreeBSD** / **OpenBSD**: `/var/db/zerotier-one`
* **Mac**: `/Library/Application Support/ZeroTier/One` * **Mac**: `/Library/Application Support/ZeroTier/One`
* **Windows**: `\ProgramData\ZeroTier\One` (That's for Windows 7. The base 'shared app data' folder might be different on different Windows versions.) * **Windows**: `\ProgramData\ZeroTier\One` (That's the default. The base 'shared app data' folder might be different if Windows is installed with a non-standard drive letter assignment or layout.)
### Basic Troubleshooting ### Basic Troubleshooting

View file

@ -1,11 +1,40 @@
ZeroTier Release Notes ZeroTier Release Notes
====== ======
# 2022-03-21 -- Version 1.8.7 # 2022-06-07 -- Version 1.10.0
* Fix for dependency installations in Windows MSI package * Fix formatting problem in `zerotier-cli` when using SSO networks.
* Fix for privilege escalation in desktop UI when the user is not a current super-user * Fix a few other minor bugs in SSO signin to prepare for general availability.
* Bug fix in local OIDC / SSO support * Remove requirement for webview in desktop UI and instead just make everything available via the tray pulldown/menu. Use [libui-ng](https://github.com/libui-ng/libui-ng) for minor prompt dialogs. Saves space and eliminates installation headaches on Windows.
* Fix SSO "spam" bug in desktop UI.
* Use system default browser for SSO login so all your plugins, MFA devices, password managers, etc. will work as you have them configured.
* Minor fix for bonding/multipath.
# 2022-05-10 -- Version 1.8.10
* Fixed a bug preventing SSO sign-on on Windows.
# 2022-04-25 -- Version 1.8.9
* Fixed a long-standing and strange bug that was causing sporadic "phantom" packet authentication failures. Not a security problem but could be behind spordaic reports of link failures under some conditions.
* Fized a memory leak in SSO/OIDC support.
* Fixed SSO/OIDC display error on CLI.
* Fixed a bug causing nodes to sometimes fail to push certs to each other (primarily affects SSO/OIDC use cases).
* Fixed a deadlock bug on leaving SSO/OIDC managed networks.
* Added some new Linux distributions to the build subsystem.
# 2022-04-11 -- Version 1.8.8
* Fix a local privilege escalation bug in the Windows installer.
* Dependency fix for some Ubuntu versions.
* No changes for other platforms. Windows upgrade recommended, everyone else optional.
# 2022-03-30 -- Version 1.8.7
* Fix for dependency installations in Windows MSI package.
* Fix for desktop UI setup when run by a non-super-user.
* Bug fix in local OIDC / SSO support for auth0 and other providers.
* Other minor fixes for e.g. old Linux distributions.
# 2022-03-04 -- Version 1.8.6 # 2022-03-04 -- Version 1.8.6

10
ci/Dockerfile.deb Normal file
View file

@ -0,0 +1,10 @@
ARG PLATFORM
FROM registry.sean.farm/${PLATFORM}-builder as stage
WORKDIR /work/build
COPY . .
RUN make debian
RUN ls -ls /work
FROM scratch AS export
ARG PLATFORM
COPY --from=stage /work/*.deb ./${PLATFORM}/

36
ci/Dockerfile.el6 Normal file
View file

@ -0,0 +1,36 @@
ARG DOCKER_ARCH
FROM --platform=linux/${DOCKER_ARCH} alpine:edge AS builder
RUN apk update
RUN apk add curl
RUN apk add bash
RUN apk add file
RUN apk add rust
RUN apk add cargo
RUN apk add make
RUN apk add cmake
RUN apk add clang
RUN apk add openssl-dev
RUN apk add linux-headers
RUN apk add build-base
RUN apk add openssl-libs-static
COPY . .
RUN ZT_STATIC=1 make one
RUN ls -la
ARG DOCKER_ARCH
FROM --platform=linux/${DOCKER_ARCH} centos:6 AS stage
WORKDIR /root/rpmbuild/BUILD
COPY . .
COPY --from=builder zerotier-one ./
RUN curl https://gist.githubusercontent.com/someara/b363002ba6e57b3c474dd027d4daef85/raw/4ac5534139752fc92fbe1a53599a390214f69615/el6%2520vault --output /etc/yum.repos.d/CentOS-Base.repo
RUN uname -a
RUN yum -y install make gcc rpm-build
RUN pwd
RUN ls -la
RUN make redhat
FROM scratch AS export
ARG PLATFORM
COPY --from=stage /root/rpmbuild/RPMS/*/*.rpm ./${PLATFORM}/

9
ci/Dockerfile.rpm Normal file
View file

@ -0,0 +1,9 @@
ARG PLATFORM
FROM registry.sean.farm/${PLATFORM}-builder as stage
WORKDIR /root/rpmbuild/BUILD
COPY . .
RUN make redhat
FROM scratch AS export
ARG PLATFORM
COPY --from=stage /root/rpmbuild/RPMS/*/*.rpm ./${PLATFORM}/

View file

@ -1,7 +0,0 @@
FROM registry.sean.farm/sid-builder as stage
COPY . .
RUN /usr/bin/make -j 8
FROM scratch AS export
COPY --from=stage /zerotier-one .
COPY --from=stage /zerotier-cli .

View file

@ -2,27 +2,115 @@
set -euo pipefail set -euo pipefail
IFS=$'\n\t' IFS=$'\n\t'
export GOOS=$1 export PLATFORM=$1
export GOARCH=$2 export ZT_ISA=$2
export VERSION=$3 export VERSION=$3
export DOCKER_BUILDKIT=1 export EVENT=$4
echo "nproc: $(nproc)" case $PLATFORM in
el*|fc*|amzn*)
case $GOARCH in export PKGFMT=rpm
armv5)
export ARCH=arm/v5
;;
armv7)
export ARCH=arm/v7
;;
arm64)
export ARCH=arm64/v8
;; ;;
*) *)
export ARCH=$GOARCH export PKGFMT=deb
esac
# OSX
# x86_64-apple-darwin
# aarch64-apple-darwin
# Windows
# x86_64-pc-windows-msvc
# i686-pc-windows-msvc
# aarch64-pc-windows-msvc
# Linux
# i686-unknown-linux-gnu
# x86_64-unknown-linux-gnu
# arm-unknown-linux-gnueabi ?
# arm-unknown-linux-gnueabihf ?
# armv7-unknown-linux-gnueabihf
#
case $ZT_ISA in
386)
export DOCKER_ARCH=386
export RUST_TRIPLET=i686-unknown-linux-gnu
;;
amd64)
export DOCKER_ARCH=amd64
export RUST_TRIPLET=x86_64-unknown-linux-gnu
;;
armv6)
export DOCKER_ARCH=arm/v6
export RUST_TRIPLET=arm-unknown-linux-gnueabi
;;
armv7)
export DOCKER_ARCH=arm/v7
export RUST_TRIPLET=arm-unknown-linux-gnueabihf
;;
arm64)
export DOCKER_ARCH=arm64/v8
export RUST_TRIPLET=aarch64-unknown-linux-gnu
;;
riscv64)
export DOCKER_ARCH=riscv64
export RUST_TRIPLET=riscv64gc-unknown-linux-gnu
;;
ppc64le)
export DOCKER_ARCH=ppc64le
export RUST_TRIPLET=powerpc64le-unknown-linux-gnu
;;
mips64le)
export DOCKER_ARCH=mips64le
export RUST_TRIPLET=mips64el-unknown-linux-gnuabi64
;;
s390x)
export DOCKER_ARCH=s390x
export RUST_TRIPLET=s390x-unknown-linux-gnu
;;
*)
echo "ERROR: could not determine architecture settings. PLEASE FIX ME"
exit 1
;; ;;
esac esac
if [ -f "ci/Dockerfile.${PLATFORM}" ]; then
export DOCKERFILE="ci/Dockerfile.${PLATFORM}"
else
export DOCKERFILE="ci/Dockerfile.${PKGFMT}"
fi
echo "#~~~~~~~~~~~~~~~~~~~~"
echo "$0 variables:"
echo "nproc: $(nproc)"
echo "ZT_ISA: ${ZT_ISA}"
echo "DOCKER_ARCH: ${DOCKER_ARCH}"
echo "RUST_TRIPLET: ${RUST_TRIPLET}"
echo "VERSION: ${VERSION}"
echo "EVENT: ${EVENT}"
echo "PKGFMT: ${PKGFMT}"
echo "PWD: ${PWD}"
echo "DOCKERFILE: ${DOCKERFILE}"
echo "#~~~~~~~~~~~~~~~~~~~~"
if [ ${EVENT} == "push" ]; then
make munge_rpm zerotier-one.spec VERSION=${VERSION}
make munge_deb debian/changelog VERSION=${VERSION}
fi
export DOCKER_BUILDKIT=1
docker run --privileged --rm tonistiigi/binfmt --install all docker run --privileged --rm tonistiigi/binfmt --install all
docker buildx build --platform ${GOOS}/${ARCH} -f ci/Dockerfile.sid --target export -t test . --output out/${GOOS}/${GOARCH}
# docker pull --platform linux/${DOCKER_ARCH} registry.sean.farm/${PLATFORM}-builder
docker buildx build \
--build-arg PLATFORM="${PLATFORM}" \
--build-arg RUST_TRIPLET="${RUST_TRIPLET}" \
--build-arg DOCKER_ARCH="${DOCKER_ARCH}" \
--platform linux/${DOCKER_ARCH} \
-f ${DOCKERFILE} \
-t build \
. \
--output type=local,dest=. \
--target export

View file

@ -0,0 +1,37 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
export FILE=$1
export VERSION=$2
export NAME=$3
export MESSAGE=$4
export DATE=$(date "+%a, %d %b %Y %T %z")
# export DATE=$(date "+%a %b %d %Y")
set +e
grep --version | grep BSD &> /dev/null
if [ $? == 0 ]; then BSDGREP=true ; else BSDGREP=false ; fi
set -e
# echo "#~~~~~~~~~~~~~~~~~~~~"
# echo "$0 variables:"
# echo "VERSION: ${VERSION}"
# echo "NAME: ${NAME}"
# echo "MESSAGE: ${MESSAGE}"
# echo "DATE: ${DATE}"
# echo "BSDGREP: ${BSDGREP}"
# echo "#~~~~~~~~~~~~~~~~~~~~"
# echo
if $BSDGREP ; then
sed -i '' s/^Version:.*/"Version: ${VERSION}"/ ${FILE}
else
sed -i s/^Version:.*/"Version: ${VERSION}"/ ${FILE}
fi
awk -v version=${VERSION} -v date=${DATE} -v name=${NAME} -v message=${MESSAGE} \
'BEGIN{print "zerotier-one (" version ") unstable; urgency=medium\n\n * " message "\n\n -- " name " " date "\n" }{ print }' \
${FILE} > ${FILE}.new
mv ${FILE}.new ${FILE}

36
ci/scripts/munge_rpm_spec.sh Executable file
View file

@ -0,0 +1,36 @@
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'
export FILE=$1
export VERSION=$2
export NAME=$3
export MESSAGE=$4
export DATE=$(date "+%a %b %d %Y")
set +e
grep --version | grep BSD &> /dev/null
if [ $? == 0 ]; then BSDGREP=true ; else BSDGREP=false ; fi
set -e
# echo "#~~~~~~~~~~~~~~~~~~~~"
# echo "$0 variables:"
# echo "VERSION: ${VERSION}"
# echo "NAME: ${NAME}"
# echo "MESSAGE: ${MESSAGE}"
# echo "DATE: ${DATE}"
# echo "BSDGREP: ${BSDGREP}"
# echo "#~~~~~~~~~~~~~~~~~~~~"
# echo
if $BSDGREP ; then
sed -i '' s/^Version:.*/"Version: ${VERSION}"/ ${FILE}
else
sed -i s/^Version:.*/"Version: ${VERSION}"/ ${FILE}
fi
awk -v version=${VERSION} -v date=${DATE} -v name=${NAME} -v message=${MESSAGE} \
'FNR==NR{ if (/%changelog/) p=NR; next} 1; FNR==p{ print "* " date " " name " - " version "\n- " message "\n" }' \
${FILE} ${FILE} > ${FILE}.new
mv ${FILE}.new ${FILE}

View file

@ -196,14 +196,6 @@ void DB::networks(std::set<uint64_t> &networks)
networks.insert(n->first); networks.insert(n->first);
} }
void DB::networkMemberSSOHasExpired(uint64_t nwid, int64_t now) {
std::lock_guard<std::mutex> l(_networks_l);
auto nw = _networks.find(nwid);
if (nw != _networks.end()) {
nw->second->mostRecentDeauthTime = now;
}
}
void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners) void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners)
{ {
uint64_t memberId = 0; uint64_t memberId = 0;

View file

@ -33,7 +33,7 @@
#include <set> #include <set>
#include <map> #include <map>
#include "../ext/json/json.hpp" #include <nlohmann/json.hpp>
#define ZT_MEMBER_AUTH_TIMEOUT_NOTIFY_BEFORE 25000 #define ZT_MEMBER_AUTH_TIMEOUT_NOTIFY_BEFORE 25000
@ -135,7 +135,6 @@ public:
virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) = 0; virtual void nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress) = 0;
virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL) { return AuthInfo(); } virtual AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL) { return AuthInfo(); }
virtual void networkMemberSSOHasExpired(uint64_t nwid, int64_t ts);
inline void addListener(DB::ChangeListener *const listener) inline void addListener(DB::ChangeListener *const listener)
{ {

View file

@ -137,14 +137,6 @@ AuthInfo DBMirrorSet::getSSOAuthInfo(const nlohmann::json &member, const std::st
return AuthInfo(); return AuthInfo();
} }
void DBMirrorSet::networkMemberSSOHasExpired(uint64_t nwid, int64_t ts)
{
std::lock_guard<std::mutex> l(_dbs_l);
for(auto d=_dbs.begin();d!=_dbs.end();++d) {
(*d)->networkMemberSSOHasExpired(nwid, ts);
}
}
void DBMirrorSet::networks(std::set<uint64_t> &networks) void DBMirrorSet::networks(std::set<uint64_t> &networks)
{ {
std::lock_guard<std::mutex> l(_dbs_l); std::lock_guard<std::mutex> l(_dbs_l);
@ -248,47 +240,4 @@ void DBMirrorSet::onNetworkMemberDeauthorize(const void *db,uint64_t networkId,u
_listener->onNetworkMemberDeauthorize(this,networkId,memberId); _listener->onNetworkMemberDeauthorize(this,networkId,memberId);
} }
void DBMirrorSet::membersExpiring(std::set< std::pair<uint64_t, uint64_t> > &soon, std::set< std::pair<uint64_t, uint64_t> > &expired)
{
std::unique_lock<std::mutex> l(_membersExpiringSoon_l);
int64_t now = OSUtils::now();
for(auto next=_membersExpiringSoon.begin();next!=_membersExpiringSoon.end();) {
if (next->first > now) {
const uint64_t nwid = next->second.first;
const uint64_t memberId = next->second.second;
nlohmann::json network, member;
if (this->get(nwid, network, memberId, member)) {
try {
const bool authorized = member["authorized"];
const bool ssoExempt = member["ssoExempt"];
const int64_t authenticationExpiryTime = member["authenticationExpiryTime"];
if ((authenticationExpiryTime == next->first)&&(authorized)&&(!ssoExempt)) {
if ((authenticationExpiryTime - now) > ZT_MEMBER_AUTH_TIMEOUT_NOTIFY_BEFORE) {
// Stop when we get to entries too far in the future.
break;
} else {
const bool ssoEnabled = network["ssoEnabled"];
if (ssoEnabled)
soon.insert(std::pair<uint64_t, uint64_t>(nwid, memberId));
}
} else {
// Obsolete entry, no longer authorized, or SSO exempt.
}
} catch ( ... ) {
// Invalid member object, erase.
}
} else {
// Not found.
}
}
_membersExpiringSoon.erase(next++);
}
}
void DBMirrorSet::memberWillExpire(int64_t expTime, uint64_t nwid, uint64_t memberId)
{
std::unique_lock<std::mutex> l(_membersExpiringSoon_l);
_membersExpiringSoon.insert(std::pair< int64_t, std::pair< uint64_t, uint64_t > >(expTime, std::pair< uint64_t, uint64_t >(nwid, memberId)));
}
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -52,7 +52,6 @@ public:
virtual void onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId); virtual void onNetworkMemberDeauthorize(const void *db,uint64_t networkId,uint64_t memberId);
AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL); AuthInfo getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL);
void networkMemberSSOHasExpired(uint64_t nwid, int64_t ts);
inline void addDB(const std::shared_ptr<DB> &db) inline void addDB(const std::shared_ptr<DB> &db)
{ {
@ -61,17 +60,12 @@ public:
_dbs.push_back(db); _dbs.push_back(db);
} }
void membersExpiring(std::set< std::pair<uint64_t, uint64_t> > &soon, std::set< std::pair<uint64_t, uint64_t> > &expired);
void memberWillExpire(int64_t expTime, uint64_t nwid, uint64_t memberId);
private: private:
DB::ChangeListener *const _listener; DB::ChangeListener *const _listener;
std::atomic_bool _running; std::atomic_bool _running;
std::thread _syncCheckerThread; std::thread _syncCheckerThread;
std::vector< std::shared_ptr< DB > > _dbs; std::vector< std::shared_ptr< DB > > _dbs;
mutable std::mutex _dbs_l; mutable std::mutex _dbs_l;
std::set< std::pair< int64_t, std::pair<uint64_t, uint64_t> > > _membersExpiringSoon;
mutable std::mutex _membersExpiringSoon_l;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -1262,6 +1262,7 @@ void EmbeddedNetworkController::_request(
} }
const bool newMember = ((!member.is_object())||(member.empty())); const bool newMember = ((!member.is_object())||(member.empty()));
DB::initMember(member); DB::initMember(member);
_MemberStatusKey msk(nwid,identity.address().toInt());
{ {
const std::string haveIdStr(OSUtils::jsonString(member["identity"],"")); const std::string haveIdStr(OSUtils::jsonString(member["identity"],""));
@ -1335,43 +1336,21 @@ void EmbeddedNetworkController::_request(
// Should we check SSO Stuff? // Should we check SSO Stuff?
// If network is configured with SSO, and the member is not marked exempt: yes // If network is configured with SSO, and the member is not marked exempt: yes
// Otherwise no, we use standard auth logic. // Otherwise no, we use standard auth logic.
AuthInfo info;
int64_t authenticationExpiryTime = -1;
bool networkSSOEnabled = OSUtils::jsonBool(network["ssoEnabled"], false); bool networkSSOEnabled = OSUtils::jsonBool(network["ssoEnabled"], false);
bool memberSSOExempt = OSUtils::jsonBool(member["ssoExempt"], false); bool memberSSOExempt = OSUtils::jsonBool(member["ssoExempt"], false);
AuthInfo info;
if (networkSSOEnabled && !memberSSOExempt) { if (networkSSOEnabled && !memberSSOExempt) {
// TODO: Get expiry time if auth is still valid authenticationExpiryTime = (int64_t)OSUtils::jsonInt(member["authenticationExpiryTime"], 0);
// else get new auth info & stuff
info = _db.getSSOAuthInfo(member, _ssoRedirectURL); info = _db.getSSOAuthInfo(member, _ssoRedirectURL);
assert(info.enabled == networkSSOEnabled); assert(info.enabled == networkSSOEnabled);
if (authenticationExpiryTime <= now) {
std::string memberId = member["id"];
//fprintf(stderr, "ssoEnabled && !ssoExempt %s-%s\n", nwids, memberId.c_str());
uint64_t authenticationExpiryTime = (int64_t)OSUtils::jsonInt(member["authenticationExpiryTime"], 0);
fprintf(stderr, "authExpiryTime: %lld\n", authenticationExpiryTime);
if (authenticationExpiryTime < now) {
fprintf(stderr, "Handling expired member\n");
if (info.version == 0) { if (info.version == 0) {
if (!info.authenticationURL.empty()) {
_db.networkMemberSSOHasExpired(nwid, now);
onNetworkMemberDeauthorize(&_db, nwid, identity.address().toInt());
Dictionary<4096> authInfo; Dictionary<4096> authInfo;
authInfo.add(ZT_AUTHINFO_DICT_KEY_VERSION, (uint64_t)0ULL); authInfo.add(ZT_AUTHINFO_DICT_KEY_VERSION, (uint64_t)0ULL);
authInfo.add(ZT_AUTHINFO_DICT_KEY_AUTHENTICATION_URL, info.authenticationURL.c_str()); authInfo.add(ZT_AUTHINFO_DICT_KEY_AUTHENTICATION_URL, info.authenticationURL.c_str());
//fprintf(stderr, "sending auth URL: %s\n", authenticationURL.c_str());
DB::cleanMember(member);
_db.save(member,true);
_sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED, authInfo.data(), authInfo.sizeBytes()); _sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED, authInfo.data(), authInfo.sizeBytes());
return; } else if (info.version == 1) {
}
}
else if (info.version == 1) {
_db.networkMemberSSOHasExpired(nwid, now);
onNetworkMemberDeauthorize(&_db, nwid, identity.address().toInt());
Dictionary<8192> authInfo; Dictionary<8192> authInfo;
authInfo.add(ZT_AUTHINFO_DICT_KEY_VERSION, info.version); authInfo.add(ZT_AUTHINFO_DICT_KEY_VERSION, info.version);
authInfo.add(ZT_AUTHINFO_DICT_KEY_ISSUER_URL, info.issuerURL.c_str()); authInfo.add(ZT_AUTHINFO_DICT_KEY_ISSUER_URL, info.issuerURL.c_str());
@ -1379,21 +1358,12 @@ void EmbeddedNetworkController::_request(
authInfo.add(ZT_AUTHINFO_DICT_KEY_NONCE, info.ssoNonce.c_str()); authInfo.add(ZT_AUTHINFO_DICT_KEY_NONCE, info.ssoNonce.c_str());
authInfo.add(ZT_AUTHINFO_DICT_KEY_STATE, info.ssoState.c_str()); authInfo.add(ZT_AUTHINFO_DICT_KEY_STATE, info.ssoState.c_str());
authInfo.add(ZT_AUTHINFO_DICT_KEY_CLIENT_ID, info.ssoClientID.c_str()); authInfo.add(ZT_AUTHINFO_DICT_KEY_CLIENT_ID, info.ssoClientID.c_str());
_sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED, authInfo.data(), authInfo.sizeBytes());
}
DB::cleanMember(member); DB::cleanMember(member);
_db.save(member,true); _db.save(member,true);
fprintf(stderr, "Sending NC_ERROR_AUTHENTICATION_REQUIRED\n");
_sender->ncSendError(nwid,requestPacketId,identity.address(),NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED, authInfo.data(), authInfo.sizeBytes());
return; return;
} }
else {
fprintf(stderr, "invalid sso info.version %llu\n", info.version);
}
} else if (authorized) {
fprintf(stderr, "Setting member will expire to: %lld\n", authenticationExpiryTime);
_db.memberWillExpire(authenticationExpiryTime, nwid, identity.address().toInt());
}
} }
if (authorized) { if (authorized) {
@ -1411,8 +1381,8 @@ void EmbeddedNetworkController::_request(
{ {
std::lock_guard<std::mutex> l(_memberStatus_l); std::lock_guard<std::mutex> l(_memberStatus_l);
_MemberStatus &ms = _memberStatus[_MemberStatusKey(nwid,identity.address().toInt())]; _MemberStatus &ms = _memberStatus[msk];
ms.authenticationExpiryTime = authenticationExpiryTime;
ms.vMajor = (int)vMajor; ms.vMajor = (int)vMajor;
ms.vMinor = (int)vMinor; ms.vMinor = (int)vMinor;
ms.vRev = (int)vRev; ms.vRev = (int)vRev;
@ -1420,9 +1390,13 @@ void EmbeddedNetworkController::_request(
ms.lastRequestMetaData = metaData; ms.lastRequestMetaData = metaData;
ms.identity = identity; ms.identity = identity;
} }
if (authenticationExpiryTime > 0) {
std::lock_guard<std::mutex> l(_expiringSoon_l);
_expiringSoon.insert(std::pair<int64_t, _MemberStatusKey>(authenticationExpiryTime, msk));
}
} }
} else { } else {
// If they are not authorized, STOP! // If they are not authorized, STOP!
DB::cleanMember(member); DB::cleanMember(member);
_db.save(member,true); _db.save(member,true);
@ -1434,18 +1408,13 @@ void EmbeddedNetworkController::_request(
// If we made it this far, they are authorized (and authenticated). // If we made it this far, they are authorized (and authenticated).
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
int64_t credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA; // Default timeout: 15 minutes. Maximum: two hours. Can be specified by an optional field in the network config
if (now > ns.mostRecentDeauthTime) { // if something longer than 15 minutes is desired. Minimum is 5 minutes since shorter than that would be flaky.
// If we recently de-authorized a member, shrink credential TTL/max delta to int64_t credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_DFL_MAX_DELTA;
// be below the threshold required to exclude it. Cap this to a min/max to if (network.contains("certificateTimeoutWindowSize")) {
// prevent jitter or absurdly large values. credentialtmd = (int64_t)network["certificateTimeoutWindowSize"];
const uint64_t deauthWindow = now - ns.mostRecentDeauthTime;
if (deauthWindow < ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA) {
credentialtmd = ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA;
} else if (deauthWindow < (ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA + 5000ULL)) {
credentialtmd = deauthWindow - 5000ULL;
}
} }
credentialtmd = std::max(std::min(credentialtmd, ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA), ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA);
std::unique_ptr<NetworkConfig> nc(new NetworkConfig()); std::unique_ptr<NetworkConfig> nc(new NetworkConfig());
@ -1460,7 +1429,7 @@ void EmbeddedNetworkController::_request(
nc->mtu = std::max(std::min((unsigned int)OSUtils::jsonInt(network["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU); nc->mtu = std::max(std::min((unsigned int)OSUtils::jsonInt(network["mtu"],ZT_DEFAULT_MTU),(unsigned int)ZT_MAX_MTU),(unsigned int)ZT_MIN_MTU);
nc->multicastLimit = (unsigned int)OSUtils::jsonInt(network["multicastLimit"],32ULL); nc->multicastLimit = (unsigned int)OSUtils::jsonInt(network["multicastLimit"],32ULL);
nc->ssoEnabled = OSUtils::jsonBool(network["ssoEnabled"], false); nc->ssoEnabled = networkSSOEnabled; //OSUtils::jsonBool(network["ssoEnabled"], false);
nc->ssoVersion = info.version; nc->ssoVersion = info.version;
if (info.version == 0) { if (info.version == 0) {
@ -1858,6 +1827,8 @@ void EmbeddedNetworkController::_startThreads()
const long hwc = std::max((long)std::thread::hardware_concurrency(),(long)1); const long hwc = std::max((long)std::thread::hardware_concurrency(),(long)1);
for(long t=0;t<hwc;++t) { for(long t=0;t<hwc;++t) {
_threads.emplace_back([this]() { _threads.emplace_back([this]() {
std::vector<_MemberStatusKey> expired;
nlohmann::json network, member;
for(;;) { for(;;) {
_RQEntry *qe = (_RQEntry *)0; _RQEntry *qe = (_RQEntry *)0;
auto timedWaitResult = _queue.get(qe, 1000); auto timedWaitResult = _queue.get(qe, 1000);
@ -1876,28 +1847,31 @@ void EmbeddedNetworkController::_startThreads()
} }
} }
std::set< std::pair<uint64_t, uint64_t> > soon; expired.clear();
std::set< std::pair<uint64_t, uint64_t> > expired; int64_t now = OSUtils::now();
_db.membersExpiring(soon, expired);
for(auto s=soon.begin();s!=soon.end();++s) {
Identity identity;
Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> lastMetaData;
{ {
std::unique_lock<std::mutex> ll(_memberStatus_l); std::lock_guard<std::mutex> l(_expiringSoon_l);
auto ms = _memberStatus.find(_MemberStatusKey(s->first, s->second)); for(auto s=_expiringSoon.begin();s!=_expiringSoon.end();) {
if (ms != _memberStatus.end()) { const int64_t when = s->first;
lastMetaData = ms->second.lastRequestMetaData; if (when <= now) {
identity = ms->second.identity; // The user may have re-authorized, so we must actually look it up and check.
network.clear();
member.clear();
if (_db.get(s->second.networkId, network, s->second.nodeId, member)) {
int64_t authenticationExpiryTime = (int64_t)OSUtils::jsonInt(member["authenticationExpiryTime"], 0);
if (authenticationExpiryTime <= now) {
expired.push_back(s->second);
} }
} }
if (identity) { _expiringSoon.erase(s++);
request(s->first,InetAddress(),0,identity,lastMetaData); } else {
// Don't bother going further into the future than necessary.
break;
}
} }
} }
for(auto e=expired.begin();e!=expired.end();++e) { for(auto e=expired.begin();e!=expired.end();++e) {
onNetworkMemberDeauthorize(nullptr, e->first, e->second); onNetworkMemberDeauthorize(nullptr, e->networkId, e->nodeId);
} }
} }
}); });

View file

@ -35,7 +35,7 @@
#include "../osdep/Thread.hpp" #include "../osdep/Thread.hpp"
#include "../osdep/BlockingQueue.hpp" #include "../osdep/BlockingQueue.hpp"
#include "../ext/json/json.hpp" #include <nlohmann/json.hpp>
#include "DB.hpp" #include "DB.hpp"
#include "DBMirrorSet.hpp" #include "DBMirrorSet.hpp"
@ -109,6 +109,7 @@ private:
RQENTRY_TYPE_REQUEST = 0 RQENTRY_TYPE_REQUEST = 0
} type; } type;
}; };
struct _MemberStatusKey struct _MemberStatusKey
{ {
_MemberStatusKey() : networkId(0),nodeId(0) {} _MemberStatusKey() : networkId(0),nodeId(0) {}
@ -116,11 +117,13 @@ private:
uint64_t networkId; uint64_t networkId;
uint64_t nodeId; uint64_t nodeId;
inline bool operator==(const _MemberStatusKey &k) const { return ((k.networkId == networkId)&&(k.nodeId == nodeId)); } inline bool operator==(const _MemberStatusKey &k) const { return ((k.networkId == networkId)&&(k.nodeId == nodeId)); }
inline bool operator<(const _MemberStatusKey &k) const { return (k.networkId < networkId) || ((k.networkId == networkId)&&(k.nodeId < nodeId)); }
}; };
struct _MemberStatus struct _MemberStatus
{ {
_MemberStatus() : lastRequestTime(0),vMajor(-1),vMinor(-1),vRev(-1),vProto(-1) {} _MemberStatus() : lastRequestTime(0),authenticationExpiryTime(-1),vMajor(-1),vMinor(-1),vRev(-1),vProto(-1) {}
uint64_t lastRequestTime; int64_t lastRequestTime;
int64_t authenticationExpiryTime;
int vMajor,vMinor,vRev,vProto; int vMajor,vMinor,vRev,vProto;
Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> lastRequestMetaData; Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> lastRequestMetaData;
Identity identity; Identity identity;
@ -152,6 +155,9 @@ private:
std::unordered_map< _MemberStatusKey,_MemberStatus,_MemberStatusHash > _memberStatus; std::unordered_map< _MemberStatusKey,_MemberStatus,_MemberStatusHash > _memberStatus;
std::mutex _memberStatus_l; std::mutex _memberStatus_l;
std::set< std::pair<int64_t, _MemberStatusKey> > _expiringSoon;
std::mutex _expiringSoon_l;
RedisConfig *_rc; RedisConfig *_rc;
std::string _ssoRedirectURL; std::string _ssoRedirectURL;
}; };

View file

@ -28,7 +28,7 @@
#include <chrono> #include <chrono>
// #define ZT_TRACE 1 // #define REDIS_TRACE 1
using json = nlohmann::json; using json = nlohmann::json;
@ -783,6 +783,7 @@ void PostgreSQL::initializeMembers()
std::string assignedAddresses = std::get<20>(row); std::string assignedAddresses = std::get<20>(row);
config["id"] = memberId; config["id"] = memberId;
config["address"] = memberId;
config["nwid"] = networkId; config["nwid"] = networkId;
config["activeBridge"] = activeBridge.value_or(false); config["activeBridge"] = activeBridge.value_or(false);
config["authorized"] = authorized.value_or(false); config["authorized"] = authorized.value_or(false);
@ -942,30 +943,31 @@ void PostgreSQL::_membersWatcher_Postgres() {
void PostgreSQL::_membersWatcher_Redis() { void PostgreSQL::_membersWatcher_Redis() {
char buf[11] = {0}; char buf[11] = {0};
std::string key = "member-stream:{" + std::string(_myAddress.toString(buf)) + "}"; std::string key = "member-stream:{" + std::string(_myAddress.toString(buf)) + "}";
std::string lastID = "0";
fprintf(stderr, "Listening to member stream: %s\n", key.c_str()); fprintf(stderr, "Listening to member stream: %s\n", key.c_str());
while (_run == 1) { while (_run == 1) {
try { try {
json tmp; json tmp;
std::unordered_map<std::string, ItemStream> result; std::unordered_map<std::string, ItemStream> result;
if (_rc->clusterMode) { if (_rc->clusterMode) {
_cluster->xread(key, "$", std::chrono::seconds(1), 0, std::inserter(result, result.end())); _cluster->xread(key, lastID, std::chrono::seconds(1), 0, std::inserter(result, result.end()));
} else { } else {
_redis->xread(key, "$", std::chrono::seconds(1), 0, std::inserter(result, result.end())); _redis->xread(key, lastID, std::chrono::seconds(1), 0, std::inserter(result, result.end()));
} }
if (!result.empty()) { if (!result.empty()) {
for (auto element : result) { for (auto element : result) {
#ifdef ZT_TRACE #ifdef REDIS_TRACE
fprintf(stdout, "Received notification from: %s\n", element.first.c_str()); fprintf(stdout, "Received notification from: %s\n", element.first.c_str());
#endif #endif
for (auto rec : element.second) { for (auto rec : element.second) {
std::string id = rec.first; std::string id = rec.first;
auto attrs = rec.second; auto attrs = rec.second;
#ifdef ZT_TRACE #ifdef REDIS_TRACE
fprintf(stdout, "Record ID: %s\n", id.c_str()); fprintf(stdout, "Record ID: %s\n", id.c_str());
fprintf(stdout, "attrs len: %lu\n", attrs.size()); fprintf(stdout, "attrs len: %lu\n", attrs.size());
#endif #endif
for (auto a : attrs) { for (auto a : attrs) {
#ifdef ZT_TRACE #ifdef REDIS_TRACE
fprintf(stdout, "key: %s\nvalue: %s\n", a.first.c_str(), a.second.c_str()); fprintf(stdout, "key: %s\nvalue: %s\n", a.first.c_str(), a.second.c_str());
#endif #endif
try { try {
@ -987,6 +989,7 @@ void PostgreSQL::_membersWatcher_Redis() {
} else { } else {
_redis->xdel(key, id); _redis->xdel(key, id);
} }
lastID = id;
} }
} }
} }
@ -1029,31 +1032,31 @@ void PostgreSQL::_networksWatcher_Postgres() {
void PostgreSQL::_networksWatcher_Redis() { void PostgreSQL::_networksWatcher_Redis() {
char buf[11] = {0}; char buf[11] = {0};
std::string key = "network-stream:{" + std::string(_myAddress.toString(buf)) + "}"; std::string key = "network-stream:{" + std::string(_myAddress.toString(buf)) + "}";
std::string lastID = "0";
while (_run == 1) { while (_run == 1) {
try { try {
json tmp; json tmp;
std::unordered_map<std::string, ItemStream> result; std::unordered_map<std::string, ItemStream> result;
if (_rc->clusterMode) { if (_rc->clusterMode) {
_cluster->xread(key, "$", std::chrono::seconds(1), 0, std::inserter(result, result.end())); _cluster->xread(key, lastID, std::chrono::seconds(1), 0, std::inserter(result, result.end()));
} else { } else {
_redis->xread(key, "$", std::chrono::seconds(1), 0, std::inserter(result, result.end())); _redis->xread(key, lastID, std::chrono::seconds(1), 0, std::inserter(result, result.end()));
} }
if (!result.empty()) { if (!result.empty()) {
for (auto element : result) { for (auto element : result) {
#ifdef ZT_TRACE #ifdef REDIS_TRACE
fprintf(stdout, "Received notification from: %s\n", element.first.c_str()); fprintf(stdout, "Received notification from: %s\n", element.first.c_str());
#endif #endif
for (auto rec : element.second) { for (auto rec : element.second) {
std::string id = rec.first; std::string id = rec.first;
auto attrs = rec.second; auto attrs = rec.second;
#ifdef ZT_TRACE #ifdef REDIS_TRACE
fprintf(stdout, "Record ID: %s\n", id.c_str()); fprintf(stdout, "Record ID: %s\n", id.c_str());
fprintf(stdout, "attrs len: %lu\n", attrs.size()); fprintf(stdout, "attrs len: %lu\n", attrs.size());
#endif #endif
for (auto a : attrs) { for (auto a : attrs) {
#ifdef ZT_TRACE #ifdef REDIS_TRACE
fprintf(stdout, "key: %s\nvalue: %s\n", a.first.c_str(), a.second.c_str()); fprintf(stdout, "key: %s\nvalue: %s\n", a.first.c_str(), a.second.c_str());
#endif #endif
try { try {
@ -1075,6 +1078,7 @@ void PostgreSQL::_networksWatcher_Redis() {
} else { } else {
_redis->xdel(key, id); _redis->xdel(key, id);
} }
lastID = id;
} }
} }
} }

24
debian/changelog vendored
View file

@ -1,3 +1,27 @@
zerotier-one (1.10.0) unstable; urgency=medium
* See RELEASE-NOTES.md for release notes.
-- Adam Ierymenko <adam.ierymenko@zerotier.com> Fri, 03 Jun 2022 01:00:00 -0700
zerotier-one (1.8.10) unstable; urgency=medium
* See RELEASE-NOTES.md for release notes.
-- Adam Ierymenko <adam.ierymenko@zerotier.com> Tue, 10 May 2022 01:00:00 -0700
zerotier-one (1.8.9) unstable; urgency=medium
* See RELEASE-NOTES.md for release notes.
-- Adam Ierymenko <adam.ierymenko@zerotier.com> Mon, 25 Apr 2022 01:00:00 -0700
zerotier-one (1.8.8) unstable; urgency=medium
* See RELEASE-NOTES.md for release notes.
-- Adam Ierymenko <adam.ierymenko@zerotier.com> Mon, 11 Apr 2022 01:00:00 -0700
zerotier-one (1.8.7) unstable; urgency=medium zerotier-one (1.8.7) unstable; urgency=medium
* See RELEASE-NOTES.md for release notes. * See RELEASE-NOTES.md for release notes.

2
debian/control vendored
View file

@ -10,7 +10,7 @@ Homepage: https://www.zerotier.com/
Package: zerotier-one Package: zerotier-one
Architecture: any Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, iproute2, adduser, libstdc++6, openssl Depends: iproute2, adduser, libstdc++6 (>= 5), openssl
Homepage: https://www.zerotier.com/ Homepage: https://www.zerotier.com/
Description: ZeroTier network virtualization service Description: ZeroTier network virtualization service
ZeroTier One lets you join ZeroTier virtual networks and ZeroTier One lets you join ZeroTier virtual networks and

View file

@ -1,4 +1,4 @@
FROM alpine:3.11.3 FROM alpine:3.15
ARG go_pkg_url ARG go_pkg_url

View file

@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
grepzt() { grepzt() {
[ -f /var/lib/zerotier-one/zerotier-one.pid -a -n "$(cat /var/lib/zerotier-one/zerotier-one.pid)" -a -d "/proc/$(cat /var/lib/zerotier-one/zerotier-one.pid)" ] [ -f /var/lib/zerotier-one/zerotier-one.pid -a -n "$(cat /var/lib/zerotier-one/zerotier-one.pid 2>/dev/null)" -a -d "/proc/$(cat /var/lib/zerotier-one/zerotier-one.pid 2>/dev/null)" ]
return $? return $?
} }
@ -33,29 +33,57 @@ fi
mkztfile zerotier-one.port 0600 "9993" mkztfile zerotier-one.port 0600 "9993"
killzerotier() { killzerotier() {
echo "Killing zerotier" log "Killing zerotier"
kill $(cat /var/lib/zerotier-one/zerotier-one.pid) kill $(cat /var/lib/zerotier-one/zerotier-one.pid 2>/dev/null)
exit 0 exit 0
} }
log_header() {
echo -n "\r=>"
}
log_detail_header() {
echo -n "\r===>"
}
log() {
echo "$(log_header)" "$@"
}
log_params() {
title=$1
shift
log "$title" "[$@]"
}
log_detail() {
echo "$(log_detail_header)" "$@"
}
log_detail_params() {
title=$1
shift
log_detail "$title" "[$@]"
}
trap killzerotier INT TERM trap killzerotier INT TERM
echo "Configuring networks to join" log "Configuring networks to join"
mkdir -p /var/lib/zerotier-one/networks.d mkdir -p /var/lib/zerotier-one/networks.d
echo "joining networks: $@" log_params "Joining networks:" $@
for i in "$@" for i in "$@"
do do
echo "Configuring join for $i" log_detail_params "Configuring join:" "$i"
touch "/var/lib/zerotier-one/networks.d/${i}.conf" touch "/var/lib/zerotier-one/networks.d/${i}.conf"
done done
echo "starting zerotier" log "Starting ZeroTier"
nohup /usr/sbin/zerotier-one & nohup /usr/sbin/zerotier-one &
while ! grepzt while ! grepzt
do do
echo "zerotier hasn't started, waiting a second" log_detail "ZeroTier hasn't started, waiting a second"
if [ -f nohup.out ] if [ -f nohup.out ]
then then
@ -65,7 +93,7 @@ do
sleep 1 sleep 1
done done
echo "Writing healthcheck for networks: $@" log_params "Writing healthcheck for networks:" $@
cat >/healthcheck.sh <<EOF cat >/healthcheck.sh <<EOF
#!/bin/bash #!/bin/bash
@ -77,7 +105,9 @@ EOF
chmod +x /healthcheck.sh chmod +x /healthcheck.sh
echo "Sleeping infinitely" log_params "zerotier-cli info:" "$(zerotier-cli info)"
log "Sleeping infinitely"
while true while true
do do
sleep 1 sleep 1

21
ext/inja/LICENSE Normal file
View file

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018-2021 Berscheid
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

391
ext/inja/README.md Normal file
View file

@ -0,0 +1,391 @@
[<div align="center"><img width="500" src="https://raw.githubusercontent.com/pantor/inja/master/doc/logo.svg?sanitize=true"></div>](https://github.com/pantor/inja/releases)
<p align="center">
<a href="https://github.com/pantor/inja/actions">
<img src="https://github.com/pantor/inja/workflows/CI/badge.svg" alt="CI Status">
</a>
<a href="https://github.com/pantor/inja/actions">
<img src="https://github.com/pantor/inja/workflows/Documentation/badge.svg" alt="Documentation Status">
</a>
<a href="https://www.codacy.com/manual/pantor/inja?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=pantor/inja&amp;utm_campaign=Badge_Grade">
<img src="https://app.codacy.com/project/badge/Grade/211718f7a36541819d1244c0e2ee6f08"/>
</a>
<a href="https://github.com/pantor/inja/releases">
<img src="https://img.shields.io/github/release/pantor/inja.svg" alt="Github Releases">
</a>
<a href="http://github.com/pantor/inja/issues">
<img src="https://img.shields.io/github/issues/pantor/inja.svg" alt="Github Issues">
</a>
<a href="https://raw.githubusercontent.com/pantor/inja/master/LICENSE">
<img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="GitHub License">
</a>
</p>
Inja is a template engine for modern C++, loosely inspired by [jinja](http://jinja.pocoo.org) for python. It has an easy and yet powerful template syntax with all variables, loops, conditions, includes, callbacks, and comments you need, nested and combined as you like. Inja uses the wonderful [json](https://github.com/nlohmann/json) library by nlohmann for data input. Most importantly, inja needs only two header files, which is (nearly) as trivial as integration in C++ can get. Of course, everything is tested on all relevant compilers. Here is what it looks like:
```.cpp
json data;
data["name"] = "world";
inja::render("Hello {{ name }}!", data); // Returns "Hello world!"
```
## Integration
Inja is a headers only library, which can be downloaded from the [releases](https://github.com/pantor/inja/releases) or directly from the `include/` or `single_include/` folder. Inja uses `nlohmann/json.hpp` (>= v3.8.0) as its single dependency, so make sure it can be included from `inja.hpp`. json can be downloaded [here](https://github.com/nlohmann/json/releases). Then integration is as easy as:
```.cpp
#include <inja.hpp>
// Just for convenience
using namespace inja;
```
If you are using the [Meson Build System](http://mesonbuild.com), then you can wrap this repository as a subproject.
If you are using [Conan](https://conan.io) to manage your dependencies, have a look at [this repository](https://github.com/DEGoodmanWilson/conan-inja). Please file issues [here](https://github.com/DEGoodmanWilson/conan-inja/issues) if you experience problems with the packages.
You can also integrate inja in your project using [Hunter](https://github.com/cpp-pm/hunter), a package manager for C++.
If you are using [vcpkg](https://github.com/Microsoft/vcpkg) on your project for external dependencies, then you can use the [inja package](https://github.com/Microsoft/vcpkg/tree/master/ports/inja). Please see the vcpkg project for any issues regarding the packaging.
If you are using [cget](https://cget.readthedocs.io/en/latest/), you can install the latest development version with `cget install pantor/inja`. A specific version can be installed with `cget install pantor/inja@v2.1.0`.
On macOS, you can install inja via [Homebrew](https://formulae.brew.sh/formula/inja#default) and `brew install inja`.
If you are using [conda](https://docs.conda.io/en/latest/), you can install the latest version from [conda-forge](https://anaconda.org/conda-forge/inja) with `conda install -c conda-forge inja`.
## Tutorial
This tutorial will give you an idea how to use inja. It will explain the most important concepts and give practical advices using examples and executable code. Beside this tutorial, you may check out the [documentation](https://pantor.github.io/inja).
### Template Rendering
The basic template rendering takes a template as a `std::string` and a `json` object for all data. It returns the rendered template as an `std::string`.
```.cpp
json data;
data["name"] = "world";
render("Hello {{ name }}!", data); // Returns std::string "Hello world!"
render_to(std::cout, "Hello {{ name }}!", data); // Writes "Hello world!" to stream
```
For more advanced usage, an environment is recommended.
```.cpp
Environment env;
// Render a string with json data
std::string result = env.render("Hello {{ name }}!", data); // "Hello world!"
// Or directly read a template file
Template temp = env.parse_template("./templates/greeting.txt");
std::string result = env.render(temp, data); // "Hello world!"
data["name"] = "Inja";
std::string result = env.render(temp, data); // "Hello Inja!"
// Or read the template file (and/or the json file) directly from the environment
result = env.render_file("./templates/greeting.txt", data);
result = env.render_file_with_json_file("./templates/greeting.txt", "./data.json");
// Or write a rendered template file
env.write(temp, data, "./result.txt");
env.write_with_json_file("./templates/greeting.txt", "./data.json", "./result.txt");
```
The environment class can be configured to your needs.
```.cpp
// With default settings
Environment env_default;
// With global path to template files and where files will be saved
Environment env_1 {"../path/templates/"};
// With separate input and output path
Environment env_2 {"../path/templates/", "../path/results/"};
// With other opening and closing strings (here the defaults)
env.set_expression("{{", "}}"); // Expressions
env.set_comment("{#", "#}"); // Comments
env.set_statement("{%", "%}"); // Statements {% %} for many things, see below
env.set_line_statement("##"); // Line statements ## (just an opener)
```
### Variables
Variables are rendered within the `{{ ... }}` expressions.
```.cpp
json data;
data["neighbour"] = "Peter";
data["guests"] = {"Jeff", "Tom", "Patrick"};
data["time"]["start"] = 16;
data["time"]["end"] = 22;
// Indexing in array
render("{{ guests.1 }}", data); // "Tom"
// Objects
render("{{ time.start }} to {{ time.end + 1 }}pm", data); // "16 to 23pm"
```
If no variable is found, valid JSON is printed directly, otherwise an `inja::RenderError` is thrown.
### Statements
Statements can be written either with the `{% ... %}` syntax or the `##` syntax for entire lines. Note that `##` needs to start the line without indentation. The most important statements are loops, conditions and file includes. All statements can be nested.
#### Loops
```.cpp
// Combining loops and line statements
render(R"(Guest List:
## for guest in guests
{{ loop.index1 }}: {{ guest }}
## endfor )", data)
/* Guest List:
1: Jeff
2: Tom
3: Patrick */
```
In a loop, the special variables `loop.index (number)`, `loop.index1 (number)`, `loop.is_first (boolean)` and `loop.is_last (boolean)` are defined. In nested loops, the parent loop variables are available e.g. via `loop.parent.index`. You can also iterate over objects like `{% for key, value in time %}`.
#### Conditions
Conditions support the typical if, else if and else statements. Following conditions are for example possible:
```.cpp
// Standard comparisons with a variable
render("{% if time.hour >= 20 %}Serve{% else if time.hour >= 18 %}Make{% endif %} dinner.", data); // Serve dinner.
// Variable in list
render("{% if neighbour in guests %}Turn up the music!{% endif %}", data); // Turn up the music!
// Logical operations
render("{% if guest_count < (3+2) and all_tired %}Sleepy...{% else %}Keep going...{% endif %}", data); // Sleepy...
// Negations
render("{% if not guest_count %}The End{% endif %}", data); // The End
```
#### Includes
You can either include other in-memory templates or from the file system.
```.cpp
// To include in-memory templates, add them to the environment first
inja::Template content_template = env.parse("Hello {{ neighbour }}!");
env.include_template("content", content_template);
env.render("Content: {% include \"content\" %}", data); // "Content: Hello Peter!"
// Other template files are included relative from the current file location
render("{% include \"footer.html\" %}", data);
```
If a corresponding template could not be found in the file system, the *include callback* is called:
```.cpp
// The callback takes the current path and the wanted include name and returns a template
env.set_include_callback([&env](const std::string& path, const std::string& template_name) {
return env.parse("Hello {{ neighbour }} from " + template_name);
});
// You can disable to search for templates in the file system via
env.set_search_included_templates_in_files(false);
```
Inja will throw an `inja::RenderError` if an included file is not found and no callback is specified. To disable this error, you can call `env.set_throw_at_missing_includes(false)`.
#### Assignments
Variables can also be defined within the template using the set statment.
```.cpp
render("{% set new_hour=23 %}{{ new_hour }}pm", data); // "23pm"
render("{% set time.start=18 %}{{ time.start }}pm", data); // using json pointers
```
Assignments only set the value within the rendering context; they do not modify the json object passed into the `render` call.
### Functions
A few functions are implemented within the inja template syntax. They can be called with
```.cpp
// Upper and lower function, for string cases
render("Hello {{ upper(neighbour) }}!", data); // "Hello PETER!"
render("Hello {{ lower(neighbour) }}!", data); // "Hello peter!"
// Range function, useful for loops
render("{% for i in range(4) %}{{ loop.index1 }}{% endfor %}", data); // "1234"
render("{% for i in range(3) %}{{ at(guests, i) }} {% endfor %}", data); // "Jeff Tom Patrick "
// Length function (please don't combine with range, use list directly...)
render("I count {{ length(guests) }} guests.", data); // "I count 3 guests."
// Get first and last element in a list
render("{{ first(guests) }} was first.", data); // "Jeff was first."
render("{{ last(guests) }} was last.", data); // "Patir was last."
// Sort a list
render("{{ sort([3,2,1]) }}", data); // "[1,2,3]"
render("{{ sort(guests) }}", data); // "[\"Jeff\", \"Patrick\", \"Tom\"]"
// Join a list with a separator
render("{{ join([1,2,3], \" + \") }}", data); // "1 + 2 + 3"
render("{{ join(guests, \", \") }}", data); // "Jeff, Patrick, Tom"
// Round numbers to a given precision
render("{{ round(3.1415, 0) }}", data); // 3
render("{{ round(3.1415, 3) }}", data); // 3.142
// Check if a value is odd, even or divisible by a number
render("{{ odd(42) }}", data); // false
render("{{ even(42) }}", data); // true
render("{{ divisibleBy(42, 7) }}", data); // true
// Maximum and minimum values from a list
render("{{ max([1, 2, 3]) }}", data); // 3
render("{{ min([-2.4, -1.2, 4.5]) }}", data); // -2.4
// Convert strings to numbers
render("{{ int(\"2\") == 2 }}", data); // true
render("{{ float(\"1.8\") > 2 }}", data); // false
// Set default values if variables are not defined
render("Hello {{ default(neighbour, \"my friend\") }}!", data); // "Hello Peter!"
render("Hello {{ default(colleague, \"my friend\") }}!", data); // "Hello my friend!"
// Access an objects value dynamically
render("{{ at(time, \"start\") }} to {{ time.end }}", data); // "16 to 22"
// Check if a key exists in an object
render("{{ exists(\"guests\") }}", data); // "true"
render("{{ exists(\"city\") }}", data); // "false"
render("{{ existsIn(time, \"start\") }}", data); // "true"
render("{{ existsIn(time, neighbour) }}", data); // "false"
// Check if a key is a specific type
render("{{ isString(neighbour) }}", data); // "true"
render("{{ isArray(guests) }}", data); // "true"
// Implemented type checks: isArray, isBoolean, isFloat, isInteger, isNumber, isObject, isString,
```
### Callbacks
You can create your own and more complex functions with callbacks. These are implemented with `std::function`, so you can for example use C++ lambdas. Inja `Arguments` are a vector of json pointers.
```.cpp
Environment env;
/*
* Callbacks are defined by its:
* - name,
* - (optional) number of arguments,
* - callback function.
*/
env.add_callback("double", 1, [](Arguments& args) {
int number = args.at(0)->get<int>(); // Adapt the index and type of the argument
return 2 * number;
});
// You can then use a callback like a regular function
env.render("{{ double(16) }}", data); // "32"
// Inja falls back to variadic callbacks if the number of expected arguments is omitted.
env.add_callback("argmax", [](Arguments& args) {
auto result = std::max_element(args.begin(), args.end(), [](const json* a, const json* b) { return *a < *b;});
return std::distance(args.begin(), result);
});
env.render("{{ argmax(4, 2, 6) }}", data); // "2"
env.render("{{ argmax(0, 2, 6, 8, 3) }}", data); // "3"
// A callback without argument can be used like a dynamic variable:
std::string greet = "Hello";
env.add_callback("double-greetings", 0, [greet](Arguments args) {
return greet + " " + greet + "!";
});
env.render("{{ double-greetings }}", data); // "Hello Hello!"
```
You can also add a void callback without return variable, e.g. for debugging:
```.cpp
env.add_void_callback("log", 1, [greet](Arguments args) {
std::cout << "logging: " << args[0] << std::endl;
});
env.render("{{ log(neighbour) }}", data); // Prints nothing to result, only to cout...
```
### Template Inheritance
Template inheritance allows you to build a base *skeleton* template that contains all the common elements and defines blocks that child templates can override. Lets show an example: The base template
```.html
<!DOCTYPE html>
<html>
<head>
{% block head %}
<link rel="stylesheet" href="style.css" />
<title>{% block title %}{% endblock %} - My Webpage</title>
{% endblock %}
</head>
<body>
<div id="content">{% block content %}{% endblock %}</div>
</body>
</html>
```
contains three `blocks` that child templates can fill in. The child template
```.html
{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
{{ super() }}
<style type="text/css">
.important { color: #336699; }
</style>
{% endblock %}
{% block content %}
<h1>Index</h1>
<p class="important">
Welcome to my blog!
</p>
{% endblock %}
```
calls a parent template with the `extends` keyword; it should be the first element in the template. It is possible to render the contents of the parent block by calling `super()`. In the case of multiple levels of `{% extends %}`, super references may be called with an argument (e.g. `super(2)`) to skip levels in the inheritance tree.
### Whitespace Control
In the default configuration, no whitespace is removed while rendering the file. To support a more readable template style, you can configure the environment to control whitespaces before and after a statement automatically. While enabling `set_trim_blocks` removes the first newline after a statement, `set_lstrip_blocks` strips tabs and spaces from the beginning of a line to the start of a block.
```.cpp
Environment env;
env.set_trim_blocks(true);
env.set_lstrip_blocks(true);
```
With both `trim_blocks` and `lstrip_blocks` enabled, you can put statements on their own lines. Furthermore, you can also strip whitespaces for both statements and expressions by hand. If you add a minus sign (`-`) to the start or end, the whitespaces before or after that block will be removed:
```.cpp
render("Hello {{- name -}} !", data); // "Hello Inja!"
render("{% if neighbour in guests -%} I was there{% endif -%} !", data); // Renders without any whitespaces
```
Stripping behind a statement or expression also removes any newlines.
### Comments
Comments can be written with the `{# ... #}` syntax.
```.cpp
render("Hello{# Todo #}!", data); // "Hello!"
```
### Exceptions
Inja uses exceptions to handle ill-formed template input. However, exceptions can be switched off with either using the compiler flag `-fno-exceptions` or by defining the symbol `INJA_NOEXCEPTION`. In this case, exceptions are replaced by `abort()` calls.
## Supported compilers
Inja uses the `string_view` feature of the C++17 STL. Currently, the following compilers are tested:
- GCC 7 - 11 (and possibly later)
- Clang 5 - 12 (and possibly later)
- Microsoft Visual C++ 2017 15.0 - 2022 (and possibly later)
A list of supported compiler / os versions can be found in the [CI definition](https://github.com/pantor/inja/blob/master/.github/workflows/ci.yml).

2949
ext/inja/inja.hpp Normal file

File diff suppressed because it is too large Load diff

View file

@ -701,7 +701,7 @@
<key>USE_HFS+_COMPRESSION</key> <key>USE_HFS+_COMPRESSION</key>
<false/> <false/>
<key>VERSION</key> <key>VERSION</key>
<string>1.8.7</string> <string>1.10.0</string>
</dict> </dict>
<key>TYPE</key> <key>TYPE</key>
<integer>0</integer> <integer>0</integer>

View file

@ -1,12 +1,17 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<DOCUMENT Type="Advanced Installer" CreateVersion="10.9" version="19.2" Modules="enterprise" RootPath="." Language="en" Id="{DC564647-6BF0-4550-87F4-89C938D0159C}"> <DOCUMENT Type="Advanced Installer" CreateVersion="10.9" version="19.5" Modules="enterprise" RootPath="." Language="en" Id="{DC564647-6BF0-4550-87F4-89C938D0159C}">
<COMPONENT cid="caphyon.advinst.msicomp.ProjectOptionsComponent">
<ROW Name="HiddenItems" Value="ActSyncAppComponent;CPLAppletComponent;AutorunComponent;GameUxComponent;SilverlightSlnComponent;AppXAppDetailsComponent;FixupComponent;AppXCapabilitiesComponent;AppXDependenciesComponent;AppXProductDetailsComponent;AppXVisualAssetsComponent;AppXAppDeclarationsComponent;AppXUriRulesComponent;MsiXDiffComponent;MsixManifestEditorComponent"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiPropsComponent"> <COMPONENT cid="caphyon.advinst.msicomp.MsiPropsComponent">
<ROW Property="AI_BITMAP_DISPLAY_MODE" Value="0"/> <ROW Property="AI_BITMAP_DISPLAY_MODE" Value="0"/>
<ROW Property="AI_CURRENT_YEAR" Value="2022" ValueLocId="-"/> <ROW Property="AI_CURRENT_YEAR" Value="2022" ValueLocId="-"/>
<ROW Property="AI_EMBD_MSI_EXTR_PATH" Value="[TempFolder]" ValueLocId="-"/> <ROW Property="AI_EMBD_MSI_EXTR_PATH" Value="[TempFolder]" ValueLocId="-"/>
<ROW Property="AI_EXTERNALUIUNINSTALLERNAME" MultiBuildValue="DefaultBuild:aiui"/> <ROW Property="AI_EXTERNALUIUNINSTALLERNAME" MultiBuildValue="DefaultBuild:aiui"/>
<ROW Property="AI_FINDEXE_TITLE" Value="Select the installation package for [|ProductName]" ValueLocId="AI.Property.FindExeTitle"/> <ROW Property="AI_FINDEXE_TITLE" Value="Select the installation package for [|ProductName]" ValueLocId="AI.Property.FindExeTitle"/>
<ROW Property="AI_PACKAGING_TOOL" Value="Advanced Installer 19.5 build 36301275" ValueLocId="-"/>
<ROW Property="AI_PREDEF_LCONDS_PROPS" Value="AI_DETECTED_DOTNET_VERSION"/> <ROW Property="AI_PREDEF_LCONDS_PROPS" Value="AI_DETECTED_DOTNET_VERSION"/>
<ROW Property="AI_PREREQ_REPAIR_ENABLED" MultiBuildValue="ExeBuild:1"/>
<ROW Property="AI_PRODUCTNAME_ARP" Value="ZeroTier One"/> <ROW Property="AI_PRODUCTNAME_ARP" Value="ZeroTier One"/>
<ROW Property="AI_REQUIRED_DOTNET_DISPLAY" MultiBuildValue="DefaultBuild:4.5" ValueLocId="-"/> <ROW Property="AI_REQUIRED_DOTNET_DISPLAY" MultiBuildValue="DefaultBuild:4.5" ValueLocId="-"/>
<ROW Property="AI_REQUIRED_DOTNET_VERSION" MultiBuildValue="DefaultBuild:4.5" ValueLocId="-"/> <ROW Property="AI_REQUIRED_DOTNET_VERSION" MultiBuildValue="DefaultBuild:4.5" ValueLocId="-"/>
@ -27,10 +32,10 @@
<ROW Property="LIMITUI" MultiBuildValue="DefaultBuild:1"/> <ROW Property="LIMITUI" MultiBuildValue="DefaultBuild:1"/>
<ROW Property="MSIFASTINSTALL" MultiBuildValue="DefaultBuild:2"/> <ROW Property="MSIFASTINSTALL" MultiBuildValue="DefaultBuild:2"/>
<ROW Property="Manufacturer" Value="ZeroTier, Inc."/> <ROW Property="Manufacturer" Value="ZeroTier, Inc."/>
<ROW Property="ProductCode" Value="1033:{1CF2BF7E-ADE7-440B-A50A-F2912D8B4D0D} " Type="16"/> <ROW Property="ProductCode" Value="1033:{5FF7375F-69D4-4CAA-800B-3EA1E587AAAE} " Type="16"/>
<ROW Property="ProductLanguage" Value="1033"/> <ROW Property="ProductLanguage" Value="1033"/>
<ROW Property="ProductName" Value="ZeroTier One"/> <ROW Property="ProductName" Value="ZeroTier One"/>
<ROW Property="ProductVersion" Value="1.8.6"/> <ROW Property="ProductVersion" Value="1.10.0"/>
<ROW Property="REBOOT" MultiBuildValue="DefaultBuild:ReallySuppress"/> <ROW Property="REBOOT" MultiBuildValue="DefaultBuild:ReallySuppress"/>
<ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND;AI_SETUPEXEPATH;SETUPEXEDIR"/> <ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND;AI_SETUPEXEPATH;SETUPEXEDIR"/>
<ROW Property="UpgradeCode" Value="{B0E2A5F3-88B6-4E77-B922-CB4739B4C4C8}"/> <ROW Property="UpgradeCode" Value="{B0E2A5F3-88B6-4E77-B922-CB4739B4C4C8}"/>
@ -49,33 +54,38 @@
<ROW Property="ZTHEADLESS" Value="No"/> <ROW Property="ZTHEADLESS" Value="No"/>
</COMPONENT> </COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiDirsComponent"> <COMPONENT cid="caphyon.advinst.msicomp.MsiDirsComponent">
<ROW Directory="APPDIR" Directory_Parent="TARGETDIR" DefaultDir="APPDIR:." IsPseudoRoot="1" DirectoryOptions="3"/> <ROW Directory="APPDIR" Directory_Parent="TARGETDIR" DefaultDir="APPDIR:." IsPseudoRoot="1" DirectoryOptions="15"/>
<ROW Directory="CommonAppDataFolder" Directory_Parent="TARGETDIR" DefaultDir="COMMON~1|CommonAppDataFolder" IsPseudoRoot="1"/> <ROW Directory="CommonAppDataFolder" Directory_Parent="TARGETDIR" DefaultDir="COMMON~1|CommonAppDataFolder" IsPseudoRoot="1"/>
<ROW Directory="One_Dir" Directory_Parent="ZeroTier_Dir" DefaultDir="One"/> <ROW Directory="One_Dir" Directory_Parent="ZeroTier_Dir" DefaultDir="One" DirectoryOptions="12"/>
<ROW Directory="ProgramFilesFolder" Directory_Parent="TARGETDIR" DefaultDir="PROGRA~1|ProgramFilesFolder" IsPseudoRoot="1"/> <ROW Directory="ProgramFilesFolder" Directory_Parent="TARGETDIR" DefaultDir="PROGRA~1|ProgramFilesFolder" IsPseudoRoot="1"/>
<ROW Directory="ProgramMenuFolder" Directory_Parent="TARGETDIR" DefaultDir="PROGRA~2|ProgramMenuFolder" IsPseudoRoot="1"/> <ROW Directory="ProgramMenuFolder" Directory_Parent="TARGETDIR" DefaultDir="PROGRA~2|ProgramMenuFolder" IsPseudoRoot="1"/>
<ROW Directory="TARGETDIR" DefaultDir="SourceDir"/> <ROW Directory="TARGETDIR" DefaultDir="SourceDir"/>
<ROW Directory="ZeroTier_Dir" Directory_Parent="CommonAppDataFolder" DefaultDir="ZeroTier"/> <ROW Directory="ZeroTier_Dir" Directory_Parent="CommonAppDataFolder" DefaultDir="ZeroTier" DirectoryOptions="12"/>
<ROW Directory="i686_1_Dir" Directory_Parent="ProgramMenuFolder" DefaultDir=".:i686"/> <ROW Directory="i686_1_Dir" Directory_Parent="ProgramMenuFolder" DefaultDir=".:i686"/>
<ROW Directory="i686_Dir" Directory_Parent="APPDIR" DefaultDir=".:i686" DirectoryOptions="3"/> <ROW Directory="i686_Dir" Directory_Parent="APPDIR" DefaultDir=".:i686" DirectoryOptions="15"/>
<ROW Directory="networks.d_Dir" Directory_Parent="One_Dir" DefaultDir="networks.d"/> <ROW Directory="networks.d_Dir" Directory_Parent="One_Dir" DefaultDir="networks.d" DirectoryOptions="12"/>
<ROW Directory="regid.201001.com.zerotier_Dir" Directory_Parent="CommonAppDataFolder" DefaultDir="REGID2~1.ZER|regid.2010-01.com.zerotier"/> <ROW Directory="regid.201001.com.zerotier_Dir" Directory_Parent="CommonAppDataFolder" DefaultDir="REGID2~1.ZER|regid.2010-01.com.zerotier" DirectoryOptions="12"/>
<ROW Directory="tapwindows_Dir" Directory_Parent="One_Dir" DefaultDir="TAP-WI~1|tap-windows"/> <ROW Directory="tapwindows_Dir" Directory_Parent="One_Dir" DefaultDir="TAP-WI~1|tap-windows" DirectoryOptions="12"/>
<ROW Directory="x64_Dir" Directory_Parent="tapwindows_Dir" DefaultDir="x64"/> <ROW Directory="x64_Dir" Directory_Parent="tapwindows_Dir" DefaultDir="x64" DirectoryOptions="12"/>
<ROW Directory="x86_Dir" Directory_Parent="tapwindows_Dir" DefaultDir="x86"/> <ROW Directory="x86_Dir" Directory_Parent="tapwindows_Dir" DefaultDir="x86" DirectoryOptions="12"/>
</COMPONENT> </COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiCompsComponent"> <COMPONENT cid="caphyon.advinst.msicomp.MsiCompsComponent">
<ROW Component="A918597FE054CCCB65ABDBA0AD8F63C" ComponentId="{458A5336-4527-4409-BB9D-D074790820A6}" Directory_="APPDIR" Attributes="4" KeyPath="A918597FE054CCCB65ABDBA0AD8F63C" Options="2"/> <ROW Component="A918597FE054CCCB65ABDBA0AD8F63C" ComponentId="{9EBBA2D0-7170-4C6C-9B07-9405F08DC282}" Directory_="APPDIR" Attributes="4" KeyPath="A918597FE054CCCB65ABDBA0AD8F63C" Options="2"/>
<ROW Component="AI_CustomARPName" ComponentId="{B098B41F-3C1C-4D4E-BB89-FF0C81A26E9C}" Directory_="APPDIR" Attributes="4" KeyPath="DisplayName" Options="1"/> <ROW Component="AI_CustomARPName" ComponentId="{B1226053-207C-4922-AF29-49542B56F5FB}" Directory_="APPDIR" Attributes="4" KeyPath="DisplayName" Options="1"/>
<ROW Component="AI_DisableModify" ComponentId="{46FFA8C5-A0CB-4E05-9AD3-911D543DE8CA}" Directory_="APPDIR" Attributes="4" KeyPath="NoModify" Options="1"/> <ROW Component="AI_DisableModify" ComponentId="{46FFA8C5-A0CB-4E05-9AD3-911D543DE8CA}" Directory_="APPDIR" Attributes="4" KeyPath="NoModify" Options="1"/>
<ROW Component="AI_ExePath" ComponentId="{8E02B36C-7A19-429B-A93E-77A9261AC918}" Directory_="APPDIR" Attributes="4" KeyPath="AI_ExePath"/> <ROW Component="AI_ExePath" ComponentId="{8E02B36C-7A19-429B-A93E-77A9261AC918}" Directory_="APPDIR" Attributes="4" KeyPath="AI_ExePath"/>
<ROW Component="APPDIR" ComponentId="{4DD7907D-D7FE-4CD6-B1A0-B5C1625F5133}" Directory_="APPDIR" Attributes="0"/> <ROW Component="APPDIR" ComponentId="{4DD7907D-D7FE-4CD6-B1A0-B5C1625F5133}" Directory_="APPDIR" Attributes="0"/>
<ROW Component="C4FE6FD5B7C4D07B3A313E754A9A6A8" ComponentId="{7A501107-9EEE-45A6-9609-F5E1A7372448}" Directory_="APPDIR" Attributes="260" KeyPath="C4FE6FD5B7C4D07B3A313E754A9A6A8" Options="2"/> <ROW Component="C4FE6FD5B7C4D07B3A313E754A9A6A8" ComponentId="{8F2CBC66-14B3-4DF4-8F6E-4B79B080BB12}" Directory_="APPDIR" Attributes="4" KeyPath="C4FE6FD5B7C4D07B3A313E754A9A6A8" Options="2"/>
<ROW Component="One" ComponentId="{41AB11E7-066E-414A-96F8-F051D3D3B353}" Directory_="One_Dir" Attributes="0"/>
<ROW Component="ProductInformation" ComponentId="{DB078D04-EA8E-4A7C-9001-89BAD932F9D9}" Directory_="APPDIR" Attributes="4" KeyPath="Version"/> <ROW Component="ProductInformation" ComponentId="{DB078D04-EA8E-4A7C-9001-89BAD932F9D9}" Directory_="APPDIR" Attributes="4" KeyPath="Version"/>
<ROW Component="RequiredApplication" ComponentId="{92E37C98-F8B3-4A85-AE77-3D8D9A223776}" Directory_="APPDIR" Attributes="4" Condition="VersionNT &gt;= 1000" KeyPath="RequiredApplication" Options="2"/> <ROW Component="ZeroTier" ComponentId="{8864F744-9BDF-4891-88A1-6D23D76BCCB1}" Directory_="ZeroTier_Dir" Attributes="0"/>
<ROW Component="i686" ComponentId="{6EC46014-3BFD-4017-ACBC-C4417D1D6361}" Directory_="i686_1_Dir" Attributes="0"/> <ROW Component="i686" ComponentId="{6EC46014-3BFD-4017-ACBC-C4417D1D6361}" Directory_="i686_1_Dir" Attributes="0"/>
<ROW Component="i686_1" ComponentId="{60156BDC-31D7-47EE-A307-B62129607DD5}" Directory_="i686_Dir" Attributes="0"/>
<ROW Component="networks.d" ComponentId="{EF54D0DF-889F-41DC-AF5C-4E7F96AB1C8B}" Directory_="networks.d_Dir" Attributes="0"/> <ROW Component="networks.d" ComponentId="{EF54D0DF-889F-41DC-AF5C-4E7F96AB1C8B}" Directory_="networks.d_Dir" Attributes="0"/>
<ROW Component="regid.201001.com.zerotier" ComponentId="{A39C80FC-6A8F-454F-9052-10DAC3C3B139}" Directory_="regid.201001.com.zerotier_Dir" Attributes="0"/> <ROW Component="regid.201001.com.zerotier" ComponentId="{A39C80FC-6A8F-454F-9052-10DAC3C3B139}" Directory_="regid.201001.com.zerotier_Dir" Attributes="0"/>
<ROW Component="tapwindows" ComponentId="{3E9CBCCE-EC9D-4802-B8FD-DADB4CC532A2}" Directory_="tapwindows_Dir" Attributes="0"/>
<ROW Component="x64" ComponentId="{4DD1F90B-53F1-4390-BDF1-E6D9B39B8D80}" Directory_="x64_Dir" Attributes="0"/>
<ROW Component="x86" ComponentId="{8E83C577-3C22-49B7-82A8-369BE1F19224}" Directory_="x86_Dir" Attributes="0"/>
<ROW Component="zerotier_desktop_ui.exe" ComponentId="{61A7F53C-C6C3-418D-A652-2E4D9F8173AA}" Directory_="APPDIR" Attributes="256" Condition="ZTHEADLESS = &quot;No&quot; AND VersionNT64" KeyPath="zerotier_desktop_ui.exe"/> <ROW Component="zerotier_desktop_ui.exe" ComponentId="{61A7F53C-C6C3-418D-A652-2E4D9F8173AA}" Directory_="APPDIR" Attributes="256" Condition="ZTHEADLESS = &quot;No&quot; AND VersionNT64" KeyPath="zerotier_desktop_ui.exe"/>
<ROW Component="zerotier_desktop_ui.exe_1" ComponentId="{5CFEA823-6D17-4EAA-BBAA-810E1C89555D}" Directory_="i686_Dir" Attributes="0" Condition="ZTHEADLESS = &quot;No&quot; AND NOT VersionNT64" KeyPath="zerotier_desktop_ui.exe_1"/> <ROW Component="zerotier_desktop_ui.exe_1" ComponentId="{5CFEA823-6D17-4EAA-BBAA-810E1C89555D}" Directory_="i686_Dir" Attributes="0" Condition="ZTHEADLESS = &quot;No&quot; AND NOT VersionNT64" KeyPath="zerotier_desktop_ui.exe_1"/>
<ROW Component="zerotierone_x64.exe" ComponentId="{DFCFB72D-B055-4E60-B6D8-81FF585C2183}" Directory_="One_Dir" Attributes="256" Condition="VersionNT64" KeyPath="zerotierone_x64.exe"/> <ROW Component="zerotierone_x64.exe" ComponentId="{DFCFB72D-B055-4E60-B6D8-81FF585C2183}" Directory_="One_Dir" Attributes="256" Condition="VersionNT64" KeyPath="zerotierone_x64.exe"/>
@ -84,10 +94,9 @@
<ROW Component="zttap300_x86_win10" ComponentId="{9F913E48-095B-4EA3-98DA-EDAB1593F3E3}" Directory_="x86_Dir" Attributes="0" Condition="NOT VersionNT64" KeyPath="zttap300.cat_3" Type="0"/> <ROW Component="zttap300_x86_win10" ComponentId="{9F913E48-095B-4EA3-98DA-EDAB1593F3E3}" Directory_="x86_Dir" Attributes="0" Condition="NOT VersionNT64" KeyPath="zttap300.cat_3" Type="0"/>
</COMPONENT> </COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiFeatsComponent"> <COMPONENT cid="caphyon.advinst.msicomp.MsiFeatsComponent">
<ROW Feature="A918597FE054CCCB65ABDBA0AD8F63C" Title="Visual C++ Redistributable for Visual Studio 2015-2019 x86" Description="Visual C++ Redistributable for Visual Studio 2015-2019 x86" Display="3" Level="1" Attributes="0"/> <ROW Feature="A918597FE054CCCB65ABDBA0AD8F63C" Title="Visual C++ Redistributable for Visual Studio 2015-2022 x86" Description="Visual C++ Redistributable for Visual Studio 2015-2022 x86" Display="5" Level="1" Attributes="0"/>
<ROW Feature="C4FE6FD5B7C4D07B3A313E754A9A6A8" Title="Visual C++ Redistributable for Visual Studio 2015-2019 x64" Description="Visual C++ Redistributable for Visual Studio 2015-2019 x64" Display="5" Level="1" Attributes="0"/> <ROW Feature="C4FE6FD5B7C4D07B3A313E754A9A6A8" Title="Visual C++ Redistributable for Visual Studio 2015-2022 x64" Description="Visual C++ Redistributable for Visual Studio 2015-2022 x64" Display="3" Level="1" Attributes="0"/>
<ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" Attributes="0"/> <ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" Attributes="0"/>
<ROW Feature="RequiredApplication" Title="Microsoft Edge Webview2 Runtime" Description="Microsoft Edge Webview2 Runtime" Display="7" Level="1" Attributes="0"/>
<ROW Feature="ZeroTierOne" Title="MainFeature" Description="ZeroTier One" Display="0" Level="1" Directory_="APPDIR" Attributes="0"/> <ROW Feature="ZeroTierOne" Title="MainFeature" Description="ZeroTier One" Display="0" Level="1" Directory_="APPDIR" Attributes="0"/>
<ATTRIBUTE name="CurrentFeature" value="ZeroTierOne"/> <ATTRIBUTE name="CurrentFeature" value="ZeroTierOne"/>
</COMPONENT> </COMPONENT>
@ -242,9 +251,6 @@
<ROW Dialog_="VerifyReadyDlg" Control_="Install" Event="EndDialog" Argument="Return" Condition="AI_PATCH" Ordering="199"/> <ROW Dialog_="VerifyReadyDlg" Control_="Install" Event="EndDialog" Argument="Return" Condition="AI_PATCH" Ordering="199"/>
<ROW Dialog_="VerifyReadyDlg" Control_="Back" Event="NewDialog" Argument="PatchWelcomeDlg" Condition="AI_PATCH" Ordering="203"/> <ROW Dialog_="VerifyReadyDlg" Control_="Back" Event="NewDialog" Argument="PatchWelcomeDlg" Condition="AI_PATCH" Ordering="203"/>
<ROW Dialog_="ResumeDlg" Control_="Install" Event="EndDialog" Argument="Return" Condition="AI_RESUME" Ordering="299"/> <ROW Dialog_="ResumeDlg" Control_="Install" Event="EndDialog" Argument="Return" Condition="AI_RESUME" Ordering="299"/>
<ROW Dialog_="ExitDialog" Control_="Finish" Event="DoAction" Argument="AI_CleanPrereq" Condition="1" Ordering="301"/>
<ROW Dialog_="FatalError" Control_="Finish" Event="DoAction" Argument="AI_CleanPrereq" Condition="1" Ordering="102"/>
<ROW Dialog_="UserExit" Control_="Finish" Event="DoAction" Argument="AI_CleanPrereq" Condition="1" Ordering="101"/>
<ROW Dialog_="Windows7Warning" Control_="Cancel" Event="SpawnDialog" Argument="CancelDlg" Condition="1" Ordering="100"/> <ROW Dialog_="Windows7Warning" Control_="Cancel" Event="SpawnDialog" Argument="CancelDlg" Condition="1" Ordering="100"/>
<ROW Dialog_="WelcomeDlg" Control_="Next" Event="SpawnDialog" Argument="OutOfRbDiskDlg" Condition="AI_INSTALL AND OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND (PROMPTROLLBACKCOST=&quot;P&quot; OR NOT PROMPTROLLBACKCOST)" Ordering="5" Options="2"/> <ROW Dialog_="WelcomeDlg" Control_="Next" Event="SpawnDialog" Argument="OutOfRbDiskDlg" Condition="AI_INSTALL AND OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND (PROMPTROLLBACKCOST=&quot;P&quot; OR NOT PROMPTROLLBACKCOST)" Ordering="5" Options="2"/>
<ROW Dialog_="WelcomeDlg" Control_="Next" Event="EnableRollback" Argument="False" Condition="AI_INSTALL AND OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST=&quot;D&quot;" Ordering="6" Options="2"/> <ROW Dialog_="WelcomeDlg" Control_="Next" Event="EnableRollback" Argument="False" Condition="AI_INSTALL AND OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 0 AND PROMPTROLLBACKCOST=&quot;D&quot;" Ordering="6" Options="2"/>
@ -256,12 +262,21 @@
<ROW Dialog_="WelcomeDlg" Control_="Back" Event="[ButtonText_Next]" Argument="[AI_ButtonText_Next_Orig]" Condition="AI_INSTALL" Ordering="0" Options="2"/> <ROW Dialog_="WelcomeDlg" Control_="Back" Event="[ButtonText_Next]" Argument="[AI_ButtonText_Next_Orig]" Condition="AI_INSTALL" Ordering="0" Options="2"/>
<ROW Dialog_="WelcomeDlg" Control_="Back" Event="[Text_Next]" Argument="[AI_Text_Next_Orig]" Condition="AI_INSTALL" Ordering="1" Options="2"/> <ROW Dialog_="WelcomeDlg" Control_="Back" Event="[Text_Next]" Argument="[AI_Text_Next_Orig]" Condition="AI_INSTALL" Ordering="1" Options="2"/>
<ROW Dialog_="ExitDialog" Control_="Finish" Event="DoAction" Argument="AI_ChainerScheduleReboot" Condition="Not AIEXTERNALUI" Ordering="302"/> <ROW Dialog_="ExitDialog" Control_="Finish" Event="DoAction" Argument="AI_ChainerScheduleReboot" Condition="Not AIEXTERNALUI" Ordering="302"/>
<ROW Dialog_="ExitDialog" Control_="Finish" Event="DoAction" Argument="AI_CleanPrereq" Condition="1" Ordering="303"/>
<ROW Dialog_="FatalError" Control_="Finish" Event="DoAction" Argument="AI_CleanPrereq" Condition="1" Ordering="102"/>
<ROW Dialog_="UserExit" Control_="Finish" Event="DoAction" Argument="AI_CleanPrereq" Condition="1" Ordering="101"/>
</COMPONENT> </COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiCreateFolderComponent"> <COMPONENT cid="caphyon.advinst.msicomp.MsiCreateFolderComponent">
<ROW Directory_="networks.d_Dir" Component_="networks.d" ManualDelete="false"/> <ROW Directory_="networks.d_Dir" Component_="networks.d" ManualDelete="false"/>
<ROW Directory_="regid.201001.com.zerotier_Dir" Component_="regid.201001.com.zerotier" ManualDelete="false"/> <ROW Directory_="regid.201001.com.zerotier_Dir" Component_="regid.201001.com.zerotier" ManualDelete="false"/>
<ROW Directory_="APPDIR" Component_="APPDIR" ManualDelete="true"/> <ROW Directory_="APPDIR" Component_="APPDIR" ManualDelete="true"/>
<ROW Directory_="i686_1_Dir" Component_="i686" ManualDelete="false"/> <ROW Directory_="i686_1_Dir" Component_="i686" ManualDelete="false"/>
<ROW Directory_="ZeroTier_Dir" Component_="ZeroTier" ManualDelete="true"/>
<ROW Directory_="One_Dir" Component_="One" ManualDelete="false"/>
<ROW Directory_="tapwindows_Dir" Component_="tapwindows" ManualDelete="false"/>
<ROW Directory_="x64_Dir" Component_="x64" ManualDelete="false"/>
<ROW Directory_="x86_Dir" Component_="x86" ManualDelete="false"/>
<ROW Directory_="i686_Dir" Component_="i686_1" ManualDelete="false"/>
</COMPONENT> </COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiCustActComponent"> <COMPONENT cid="caphyon.advinst.msicomp.MsiCustActComponent">
<ROW Action="AI_AppSearchEx" Type="1" Source="Prereq.dll" Target="DoAppSearchEx"/> <ROW Action="AI_AppSearchEx" Type="1" Source="Prereq.dll" Target="DoAppSearchEx"/>
@ -308,6 +323,7 @@
<ROW Action="AI_RESTORE_LOCATION" Type="65" Source="aicustact.dll" Target="RestoreLocation"/> <ROW Action="AI_RESTORE_LOCATION" Type="65" Source="aicustact.dll" Target="RestoreLocation"/>
<ROW Action="AI_RemoveExternalUIStub" Type="1" Source="ExternalUICleaner.dll" Target="RemoveExternalUIStub"/> <ROW Action="AI_RemoveExternalUIStub" Type="1" Source="ExternalUICleaner.dll" Target="RemoveExternalUIStub"/>
<ROW Action="AI_ResolveKnownFolders" Type="1" Source="aicustact.dll" Target="AI_ResolveKnownFolders"/> <ROW Action="AI_ResolveKnownFolders" Type="1" Source="aicustact.dll" Target="AI_ResolveKnownFolders"/>
<ROW Action="AI_ResolveLocalizedCredentials" Type="1" Source="aicustact.dll" Target="GetLocalizedCredentials"/>
<ROW Action="AI_RollbackChainers" Type="11585" Source="chainersupport.dll" Target="RollbackChainedPackages" WithoutSeq="true"/> <ROW Action="AI_RollbackChainers" Type="11585" Source="chainersupport.dll" Target="RollbackChainedPackages" WithoutSeq="true"/>
<ROW Action="AI_SHOW_LOG" Type="65" Source="aicustact.dll" Target="LaunchLogFile" WithoutSeq="true"/> <ROW Action="AI_SHOW_LOG" Type="65" Source="aicustact.dll" Target="LaunchLogFile" WithoutSeq="true"/>
<ROW Action="AI_STORE_LOCATION" Type="51" Source="ARPINSTALLLOCATION" Target="[APPDIR]"/> <ROW Action="AI_STORE_LOCATION" Type="51" Source="ARPINSTALLLOCATION" Target="[APPDIR]"/>
@ -353,11 +369,16 @@
<ROW Feature_="ZeroTierOne" Component_="AI_DisableModify"/> <ROW Feature_="ZeroTierOne" Component_="AI_DisableModify"/>
<ROW Feature_="ZeroTierOne" Component_="zerotier_desktop_ui.exe"/> <ROW Feature_="ZeroTierOne" Component_="zerotier_desktop_ui.exe"/>
<ROW Feature_="ZeroTierOne" Component_="zerotier_desktop_ui.exe_1"/> <ROW Feature_="ZeroTierOne" Component_="zerotier_desktop_ui.exe_1"/>
<ROW Feature_="A918597FE054CCCB65ABDBA0AD8F63C" Component_="A918597FE054CCCB65ABDBA0AD8F63C"/>
<ROW Feature_="C4FE6FD5B7C4D07B3A313E754A9A6A8" Component_="C4FE6FD5B7C4D07B3A313E754A9A6A8"/>
<ROW Feature_="RequiredApplication" Component_="RequiredApplication"/>
<ROW Feature_="ZeroTierOne" Component_="AI_ExePath"/> <ROW Feature_="ZeroTierOne" Component_="AI_ExePath"/>
<ROW Feature_="ZeroTierOne" Component_="i686"/> <ROW Feature_="ZeroTierOne" Component_="i686"/>
<ROW Feature_="ZeroTierOne" Component_="ZeroTier"/>
<ROW Feature_="ZeroTierOne" Component_="One"/>
<ROW Feature_="ZeroTierOne" Component_="tapwindows"/>
<ROW Feature_="ZeroTierOne" Component_="x64"/>
<ROW Feature_="ZeroTierOne" Component_="x86"/>
<ROW Feature_="ZeroTierOne" Component_="i686_1"/>
<ROW Feature_="C4FE6FD5B7C4D07B3A313E754A9A6A8" Component_="C4FE6FD5B7C4D07B3A313E754A9A6A8"/>
<ROW Feature_="A918597FE054CCCB65ABDBA0AD8F63C" Component_="A918597FE054CCCB65ABDBA0AD8F63C"/>
</COMPONENT> </COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiIconsComponent"> <COMPONENT cid="caphyon.advinst.msicomp.MsiIconsComponent">
<ROW Name="ZeroTierIcon.exe" SourcePath="..\..\..\artwork\ZeroTierIcon.ico" Index="0"/> <ROW Name="ZeroTierIcon.exe" SourcePath="..\..\..\artwork\ZeroTierIcon.ico" Index="0"/>
@ -367,12 +388,12 @@
<ROW Action="AI_RESTORE_LOCATION" Condition="APPDIR=&quot;&quot;" Sequence="749"/> <ROW Action="AI_RESTORE_LOCATION" Condition="APPDIR=&quot;&quot;" Sequence="749"/>
<ROW Action="AI_STORE_LOCATION" Condition="(Not Installed) OR REINSTALL" Sequence="1502"/> <ROW Action="AI_STORE_LOCATION" Condition="(Not Installed) OR REINSTALL" Sequence="1502"/>
<ROW Action="AI_PREPARE_UPGRADE" Condition="AI_UPGRADE=&quot;No&quot; AND (Not Installed)" Sequence="1397"/> <ROW Action="AI_PREPARE_UPGRADE" Condition="AI_UPGRADE=&quot;No&quot; AND (Not Installed)" Sequence="1397"/>
<ROW Action="AI_ResolveKnownFolders" Sequence="52"/> <ROW Action="AI_ResolveKnownFolders" Sequence="53"/>
<ROW Action="AI_XmlInstall" Condition="(REMOVE &lt;&gt; &quot;ALL&quot;)" Sequence="5103"/> <ROW Action="AI_XmlInstall" Condition="(REMOVE &lt;&gt; &quot;ALL&quot;)" Sequence="5103"/>
<ROW Action="AI_DATA_SETTER" Condition="(REMOVE &lt;&gt; &quot;ALL&quot;)" Sequence="5102"/> <ROW Action="AI_DATA_SETTER" Condition="(REMOVE &lt;&gt; &quot;ALL&quot;)" Sequence="5102"/>
<ROW Action="AI_XmlUninstall" Condition="(REMOVE)" Sequence="3102"/> <ROW Action="AI_XmlUninstall" Condition="(REMOVE)" Sequence="3102"/>
<ROW Action="AI_DATA_SETTER_1" Condition="(REMOVE)" Sequence="3101"/> <ROW Action="AI_DATA_SETTER_1" Condition="(REMOVE)" Sequence="3101"/>
<ROW Action="InstallFinalize" Sequence="6602" SeqType="0" MsiKey="InstallFinalize"/> <ROW Action="InstallFinalize" Sequence="6604" SeqType="0" MsiKey="InstallFinalize"/>
<ROW Action="AI_RemoveExternalUIStub" Condition="(REMOVE=&quot;ALL&quot;) AND ((VersionNT &gt; 500) OR((VersionNT = 500) AND (ServicePackLevel &gt;= 4)))" Sequence="1501"/> <ROW Action="AI_RemoveExternalUIStub" Condition="(REMOVE=&quot;ALL&quot;) AND ((VersionNT &gt; 500) OR((VersionNT = 500) AND (ServicePackLevel &gt;= 4)))" Sequence="1501"/>
<ROW Action="TapDeviceRemove32" Condition="( Installed AND ( REMOVE = &quot;ALL&quot; OR AI_INSTALL_MODE = &quot;Remove&quot; ) AND NOT UPGRADINGPRODUCTCODE ) AND ( NOT VersionNT64 )" Sequence="1605"/> <ROW Action="TapDeviceRemove32" Condition="( Installed AND ( REMOVE = &quot;ALL&quot; OR AI_INSTALL_MODE = &quot;Remove&quot; ) AND NOT UPGRADINGPRODUCTCODE ) AND ( NOT VersionNT64 )" Sequence="1605"/>
<ROW Action="TapDeviceRemove64" Condition="( Installed AND ( REMOVE = &quot;ALL&quot; OR AI_INSTALL_MODE = &quot;Remove&quot; ) AND NOT UPGRADINGPRODUCTCODE ) AND ( VersionNT64 )" Sequence="1606"/> <ROW Action="TapDeviceRemove64" Condition="( Installed AND ( REMOVE = &quot;ALL&quot; OR AI_INSTALL_MODE = &quot;Remove&quot; ) AND NOT UPGRADINGPRODUCTCODE ) AND ( VersionNT64 )" Sequence="1606"/>
@ -393,7 +414,7 @@
<ROW Action="AI_DeleteLzma" Condition="SETUPEXEDIR=&quot;&quot; AND Installed AND (REMOVE&lt;&gt;&quot;ALL&quot;) AND (AI_INSTALL_MODE&lt;&gt;&quot;Remove&quot;) AND (NOT PATCH)" Sequence="6594" Builds="ExeBuild"/> <ROW Action="AI_DeleteLzma" Condition="SETUPEXEDIR=&quot;&quot; AND Installed AND (REMOVE&lt;&gt;&quot;ALL&quot;) AND (AI_INSTALL_MODE&lt;&gt;&quot;Remove&quot;) AND (NOT PATCH)" Sequence="6594" Builds="ExeBuild"/>
<ROW Action="TerminateUIOld" Sequence="1602"/> <ROW Action="TerminateUIOld" Sequence="1602"/>
<ROW Action="AI_DATA_SETTER_6" Sequence="1601"/> <ROW Action="AI_DATA_SETTER_6" Sequence="1601"/>
<ROW Action="AI_EnableDebugLog" Sequence="51"/> <ROW Action="AI_EnableDebugLog" Sequence="52"/>
<ROW Action="AI_AppSearchEx" Sequence="101"/> <ROW Action="AI_AppSearchEx" Sequence="101"/>
<ROW Action="AI_PrepareChainers" Condition="VersionMsi &gt;= &quot;4.05&quot;" Sequence="5851"/> <ROW Action="AI_PrepareChainers" Condition="VersionMsi &gt;= &quot;4.05&quot;" Sequence="5851"/>
<ROW Action="AI_ExtractFiles" Sequence="1399" Builds="ExeBuild"/> <ROW Action="AI_ExtractFiles" Sequence="1399" Builds="ExeBuild"/>
@ -401,21 +422,24 @@
<ROW Action="AI_GetArpIconPath" Sequence="1401"/> <ROW Action="AI_GetArpIconPath" Sequence="1401"/>
<ROW Action="TerminateUINew" Sequence="1604"/> <ROW Action="TerminateUINew" Sequence="1604"/>
<ROW Action="AI_DATA_SETTER_5" Sequence="1603"/> <ROW Action="AI_DATA_SETTER_5" Sequence="1603"/>
<ROW Action="AI_ConfigureChainer" Condition="((UILevel = 2) OR (UILevel = 3)) AND (NOT UPGRADINGPRODUCTCODE)" Sequence="6600"/> <ROW Action="LaunchUI" Condition="( NOT Installed ) AND ( ZTHEADLESS = &quot;No&quot; )" Sequence="6605"/>
<ROW Action="AI_LaunchChainer" Condition="AI_PREREQ_CHAINER AND (NOT UPGRADINGPRODUCTCODE)" Sequence="6601"/> <ROW Action="AI_DETECT_MODERNWIN" Condition="(VersionNT &gt;= 603)" Sequence="54" MsiKey="AI_DETECT_MODERNWIN"/>
<ROW Action="AI_ResolveLocalizedCredentials" Sequence="51"/>
<ROW Action="AI_ConfigureChainer" Condition="((UILevel = 2) OR (UILevel = 3)) AND (NOT UPGRADINGPRODUCTCODE)" Sequence="6602"/>
<ROW Action="AI_LaunchChainer" Condition="AI_PREREQ_CHAINER AND (NOT UPGRADINGPRODUCTCODE)" Sequence="6603"/>
<ROW Action="AI_VerifyPrereq" Sequence="1101"/> <ROW Action="AI_VerifyPrereq" Sequence="1101"/>
<ROW Action="LaunchUI" Condition="( NOT Installed ) AND ( ZTHEADLESS = &quot;No&quot; )" Sequence="6603"/>
</COMPONENT> </COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiInstallUISequenceComponent"> <COMPONENT cid="caphyon.advinst.msicomp.MsiInstallUISequenceComponent">
<ROW Action="AI_RESTORE_LOCATION" Condition="APPDIR=&quot;&quot;" Sequence="749"/> <ROW Action="AI_RESTORE_LOCATION" Condition="APPDIR=&quot;&quot;" Sequence="749"/>
<ROW Action="AI_ResolveKnownFolders" Sequence="53"/> <ROW Action="AI_ResolveKnownFolders" Sequence="54"/>
<ROW Action="AI_DpiContentScale" Sequence="52"/> <ROW Action="AI_DpiContentScale" Sequence="53"/>
<ROW Action="AI_BACKUP_AI_SETUPEXEPATH" Sequence="99"/> <ROW Action="AI_BACKUP_AI_SETUPEXEPATH" Sequence="99"/>
<ROW Action="AI_RESTORE_AI_SETUPEXEPATH" Condition="AI_SETUPEXEPATH_ORIGINAL" Sequence="103"/> <ROW Action="AI_RESTORE_AI_SETUPEXEPATH" Condition="AI_SETUPEXEPATH_ORIGINAL" Sequence="103"/>
<ROW Action="ExecuteAction" Sequence="1299" SeqType="0" MsiKey="ExecuteAction"/> <ROW Action="ExecuteAction" Sequence="1299" SeqType="0" MsiKey="ExecuteAction"/>
<ROW Action="AI_DetectSoftware" Sequence="102"/> <ROW Action="AI_DetectSoftware" Sequence="102"/>
<ROW Action="AI_EnableDebugLog" Sequence="51"/> <ROW Action="AI_EnableDebugLog" Sequence="52"/>
<ROW Action="AI_AppSearchEx" Sequence="101"/> <ROW Action="AI_AppSearchEx" Sequence="101"/>
<ROW Action="AI_ResolveLocalizedCredentials" Sequence="51"/>
<ROW Action="AI_DownloadPrereq" Sequence="1296"/> <ROW Action="AI_DownloadPrereq" Sequence="1296"/>
<ROW Action="AI_ExtractPrereq" Sequence="1297"/> <ROW Action="AI_ExtractPrereq" Sequence="1297"/>
<ROW Action="AI_InstallPrerequisite" Sequence="1298"/> <ROW Action="AI_InstallPrerequisite" Sequence="1298"/>
@ -433,6 +457,23 @@
<ROW Condition="SETUPEXEDIR OR (REMOVE=&quot;ALL&quot;)" Description="This package can only be run from a bootstrapper." DescriptionLocId="AI.LaunchCondition.RequireBootstrapper" IsPredefined="true" Builds="ExeBuild"/> <ROW Condition="SETUPEXEDIR OR (REMOVE=&quot;ALL&quot;)" Description="This package can only be run from a bootstrapper." DescriptionLocId="AI.LaunchCondition.RequireBootstrapper" IsPredefined="true" Builds="ExeBuild"/>
<ROW Condition="VersionNT" Description="[ProductName] cannot be installed on [WindowsType9XDisplay]." DescriptionLocId="AI.LaunchCondition.No9X" IsPredefined="true" Builds="DefaultBuild;ExeBuild"/> <ROW Condition="VersionNT" Description="[ProductName] cannot be installed on [WindowsType9XDisplay]." DescriptionLocId="AI.LaunchCondition.No9X" IsPredefined="true" Builds="DefaultBuild;ExeBuild"/>
</COMPONENT> </COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiLockPermComponent">
<ROW LockObject="ZeroTier_Dir" Table="CreateFolder" User="[GRP_EVERYONE]" Permission="1179817" Flags="0"/>
<ROW LockObject="ZeroTier_Dir" Table="CreateFolder" User="[GRP_ADMINISTRATORS]" Permission="1245631" Flags="0"/>
<ROW LockObject="One_Dir" Table="CreateFolder" User="[GRP_ADMINISTRATORS]" Permission="1245631" Flags="0"/>
<ROW LockObject="One_Dir" Table="CreateFolder" User="[GRP_EVERYONE]" Permission="1179817" Flags="0"/>
<ROW LockObject="networks.d_Dir" Table="CreateFolder" User="[GRP_ADMINISTRATORS]" Permission="1245631" Flags="0"/>
<ROW LockObject="networks.d_Dir" Table="CreateFolder" User="[GRP_EVERYONE]" Permission="1179817" Flags="0"/>
<ROW LockObject="tapwindows_Dir" Table="CreateFolder" User="[GRP_EVERYONE]" Permission="1179817" Flags="0"/>
<ROW LockObject="tapwindows_Dir" Table="CreateFolder" User="[GRP_ADMINISTRATORS]" Permission="1245631" Flags="0"/>
<ROW LockObject="x64_Dir" Table="CreateFolder" User="[GRP_ADMINISTRATORS]" Permission="1245631" Flags="0"/>
<ROW LockObject="x64_Dir" Table="CreateFolder" User="[GRP_EVERYONE]" Permission="1179817" Flags="0"/>
<ROW LockObject="x86_Dir" Table="CreateFolder" User="[GRP_ADMINISTRATORS]" Permission="1245631" Flags="0"/>
<ROW LockObject="x86_Dir" Table="CreateFolder" User="[GRP_EVERYONE]" Permission="1179817" Flags="0"/>
<ROW LockObject="regid.201001.com.zerotier_Dir" Table="CreateFolder" User="[GRP_EVERYONE]" Permission="1179817" Flags="0"/>
<ROW LockObject="APPDIR" Table="CreateFolder" User="[GRP_EVERYONE]" Permission="1179817" Flags="0"/>
<ROW LockObject="i686_Dir" Table="CreateFolder" User="[GRP_EVERYONE]" Permission="1179817" Flags="0"/>
</COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.MsiRegLocatorComponent"> <COMPONENT cid="caphyon.advinst.msicomp.MsiRegLocatorComponent">
<ROW Signature_="AI_EXE_PATH_CU" Root="1" Key="Software\Caphyon\Advanced Installer\LZMA\[ProductCode]\[ProductVersion]" Name="AI_ExePath" Type="2"/> <ROW Signature_="AI_EXE_PATH_CU" Root="1" Key="Software\Caphyon\Advanced Installer\LZMA\[ProductCode]\[ProductVersion]" Name="AI_ExePath" Type="2"/>
<ROW Signature_="AI_EXE_PATH_LM" Root="2" Key="Software\Caphyon\Advanced Installer\LZMA\[ProductCode]\[ProductVersion]" Name="AI_ExePath" Type="2"/> <ROW Signature_="AI_EXE_PATH_LM" Root="2" Key="Software\Caphyon\Advanced Installer\LZMA\[ProductCode]\[ProductVersion]" Name="AI_ExePath" Type="2"/>
@ -469,7 +510,6 @@
<ROW Registry="ProductVersion_1" Root="-1" Key="Software\Caphyon\Advanced Installer\LZMA\[ProductCode]\[ProductVersion]" Name="\"/> <ROW Registry="ProductVersion_1" Root="-1" Key="Software\Caphyon\Advanced Installer\LZMA\[ProductCode]\[ProductVersion]" Name="\"/>
<ROW Registry="Publisher" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="Publisher" Value="[Manufacturer]" Component_="AI_CustomARPName"/> <ROW Registry="Publisher" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="Publisher" Value="[Manufacturer]" Component_="AI_CustomARPName"/>
<ROW Registry="Readme" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="Readme" Value="[ARPREADME]" Component_="AI_CustomARPName"/> <ROW Registry="Readme" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="Readme" Value="[ARPREADME]" Component_="AI_CustomARPName"/>
<ROW Registry="RequiredApplication" Root="-1" Key="Software\Caphyon\Advanced Installer\Prereqs\[ProductCode]\[ProductVersion]" Name="RequiredApplication" Value="1" Component_="RequiredApplication"/>
<ROW Registry="Software" Root="-1" Key="Software" Name="\"/> <ROW Registry="Software" Root="-1" Key="Software" Name="\"/>
<ROW Registry="URLInfoAbout" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="URLInfoAbout" Value="[ARPURLINFOABOUT]" Component_="AI_CustomARPName"/> <ROW Registry="URLInfoAbout" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="URLInfoAbout" Value="[ARPURLINFOABOUT]" Component_="AI_CustomARPName"/>
<ROW Registry="URLUpdateInfo" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="URLUpdateInfo" Value="[ARPURLUPDATEINFO]" Component_="AI_CustomARPName"/> <ROW Registry="URLUpdateInfo" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="URLUpdateInfo" Value="[ARPURLUPDATEINFO]" Component_="AI_CustomARPName"/>
@ -501,17 +541,14 @@
<ROW UpgradeCode="[|UpgradeCode]" VersionMin="[|ProductVersion]" Attributes="2" ActionProperty="AI_NEWERPRODUCTFOUND"/> <ROW UpgradeCode="[|UpgradeCode]" VersionMin="[|ProductVersion]" Attributes="2" ActionProperty="AI_NEWERPRODUCTFOUND"/>
</COMPONENT> </COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.PreReqComponent"> <COMPONENT cid="caphyon.advinst.msicomp.PreReqComponent">
<ROW PrereqKey="A918597FE054CCCB65ABDBA0AD8F63C" DisplayName="Visual C++ Redistributable for Visual Studio 2015-2019 x86" VersionMin="14.26" SetupFileUrl="https://download.visualstudio.microsoft.com/download/pr/d60aa805-26e9-47df-b4e3-cd6fcc392333/A06AAC66734A618AB33C1522920654DDFC44FC13CAFAA0F0AB85B199C3D51DC0/VC_redist.x86.exe" Location="1" ExactSize="14413048" WinNT64Versions="Windows XP/Vista/Windows 7/Windows 8 x64/Windows 8.1 x64/Windows 10 x64/Windows 11 x64" Operator="0" ComLine="/q /norestart" BasicUiComLine="/q /norestart" NoUiComLine="/q /norestart" Options="f" MD5="fe6eae1c34528d1ea224569dcdc35618" TargetName="Visual C++ Redistributable for Visual Studio 2015-2019" Feature="A918597FE054CCCB65ABDBA0AD8F63C"/> <ROW PrereqKey="A918597FE054CCCB65ABDBA0AD8F63C" DisplayName="Visual C++ Redistributable for Visual Studio 2015-2022 x86" VersionMin="14.30" SetupFileUrl="Prerequisites\Visual C++ Redistributable for Visual Studio 2015-2022\VC_redist.x86.exe" Location="0" ExactSize="0" WinNTVersions="Windows Vista RTM x86, Windows Vista SP1 x86, Windows Server 2008 RTM x86, Windows 7 RTM x86" WinNT64Versions="Windows Vista RTM x64, Windows Vista SP1 x64, Windows Server 2008 RTM x64, Windows 7 RTM x64, Windows Server 2008 R2 RTM x64" Operator="0" NoUiComLine="/q /norestart" Options="f" TargetName="Visual C++ Redistributable for Visual Studio 2015-2022\VC_redist.x86.exe" Feature="A918597FE054CCCB65ABDBA0AD8F63C"/>
<ROW PrereqKey="C4FE6FD5B7C4D07B3A313E754A9A6A8" DisplayName="Visual C++ Redistributable for Visual Studio 2015-2019 x64" VersionMin="14.26" SetupFileUrl="https://download.visualstudio.microsoft.com/download/pr/d60aa805-26e9-47df-b4e3-cd6fcc392333/7D7105C52FCD6766BEEE1AE162AA81E278686122C1E44890712326634D0B055E/VC_redist.x64.exe" Location="1" ExactSize="14974616" WinNTVersions="Windows 9x/ME/NT/2000/XP/Vista/Windows 7/Windows 8 x86/Windows 8.1 x86/Windows 10 x86" Operator="1" ComLine="/q /norestart" BasicUiComLine="/q /norestart" NoUiComLine="/q /norestart" Options="xf" MD5="264c296cc0bf00db6ba8e7bf8cc4e706" TargetName="Visual C++ Redistributable for Visual Studio 2015-2019" Feature="C4FE6FD5B7C4D07B3A313E754A9A6A8"/> <ROW PrereqKey="C4FE6FD5B7C4D07B3A313E754A9A6A8" DisplayName="Visual C++ Redistributable for Visual Studio 2015-2022 x64" VersionMin="14.30" SetupFileUrl="Prerequisites\Visual C++ Redistributable for Visual Studio 2015-2022\VC_redist.x64.exe" Location="0" ExactSize="0" WinNTVersions="Windows 9x/ME/NT/2000/XP/Vista/Windows 7/Windows 8 x86/Windows 8.1 x86/Windows 10 x86" WinNT64Versions="Windows Vista RTM x64, Windows Vista SP1 x64, Windows Server 2008 RTM x64, Windows 7 RTM x64, Windows Server 2008 R2 RTM x64" Operator="1" NoUiComLine="/q /norestart" Options="xf" TargetName="Visual C++ Redistributable for Visual Studio 2015-2022\VC_redist.x64.exe" Feature="C4FE6FD5B7C4D07B3A313E754A9A6A8"/>
<ROW PrereqKey="RequiredApplication" DisplayName="Microsoft Edge Webview2 Runtime" SetupFileUrl="https://go.microsoft.com/fwlink/p/?LinkId=2124703" Location="1" ExactSize="0" Operator="1" ComLine="/silent /install" BasicUiComLine="/silent /install" NoUiComLine="/silent /install" Options="fx" TargetName="MicrosoftEdgeWebview2Setup.exe" Feature="RequiredApplication"/> <ATTRIBUTE name="PrereqsOrder" value="C4FE6FD5B7C4D07B3A313E754A9A6A8 A918597FE054CCCB65ABDBA0AD8F63C"/>
<ATTRIBUTE name="PrereqsOrder" value="A918597FE054CCCB65ABDBA0AD8F63C C4FE6FD5B7C4D07B3A313E754A9A6A8 RequiredApplication"/>
</COMPONENT> </COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.PreReqSearchComponent"> <COMPONENT cid="caphyon.advinst.msicomp.PreReqSearchComponent">
<ROW SearchKey="A918597FE054CCCB65ABDBA0AD8F63CSyst" Prereq="A918597FE054CCCB65ABDBA0AD8F63C" SearchType="0" SearchString="[SystemFolder]vcruntime140.dll" VerMin="14.26.28720" Order="2" Property="PreReqSearch_1_A918597FE054CCCB65AB"/> <ROW SearchKey="A918597FE054CCCB65ABDBA0AD8F63CSyst" Prereq="A918597FE054CCCB65ABDBA0AD8F63C" SearchType="0" SearchString="[SystemFolder]vcruntime140.dll" VerMin="14.30.30704" Order="2" Property="PreReqSearch_1_A918597FE054CCCB65AB"/>
<ROW SearchKey="A918597FE054CCCB65ABDBA0AD8F63CVers" Prereq="A918597FE054CCCB65ABDBA0AD8F63C" SearchType="2" SearchString="HKLM\SOFTWARE\Microsoft\DevDiv\VC\Servicing\14.0\RuntimeMinimum\Version" VerMin="14.26.28720" Order="1" Property="PreReqSearch_A918597FE054CCCB65ABDB"/> <ROW SearchKey="A918597FE054CCCB65ABDBA0AD8F63CVers" Prereq="A918597FE054CCCB65ABDBA0AD8F63C" SearchType="2" SearchString="HKLM\SOFTWARE\Microsoft\DevDiv\VC\Servicing\14.0\RuntimeMinimum\Version" VerMin="14.30.30704" Order="1" Property="PreReqSearch_A918597FE054CCCB65ABDB"/>
<ROW SearchKey="C4FE6FD5B7C4D07B3A313E754A9A6A8Vers" Prereq="C4FE6FD5B7C4D07B3A313E754A9A6A8" SearchType="2" SearchString="HKLM\SOFTWARE\Microsoft\DevDiv\VC\Servicing\14.0\RuntimeMinimum\Version" VerMin="14.26.28720" Order="1" Property="PreReqSearch_C4FE6FD5B7C4D07B3A313E" Platform="1"/> <ROW SearchKey="C4FE6FD5B7C4D07B3A313E754A9A6A8Vers" Prereq="C4FE6FD5B7C4D07B3A313E754A9A6A8" SearchType="2" SearchString="HKLM\SOFTWARE\Microsoft\DevDiv\VC\Servicing\14.0\RuntimeMinimum\Version" VerMin="14.30.30704" Order="1" Property="PreReqSearch_C4FE6FD5B7C4D07B3A313E"/>
<ROW SearchKey="F3017226FE2A42958BDF00C3A9A7E4C5" Prereq="RequiredApplication" SearchType="5" SearchString="HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" Order="2" Property="PreReqSearch_1" Platform="1"/>
<ROW SearchKey="SystemFolderfile.dll" Prereq="RequiredApplication" SearchType="5" SearchString="HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\EdgeUpdate\Clients\{F3017226-FE2A-4295-8BDF-00C3A9A7E4C5}" Order="1" Property="PreReqSearch" Platform="1"/>
<ROW SearchKey="UpgradeCode" SearchType="4" SearchString="{88AA80DE-14CA-4443-B024-6EC13F3EDDAD}" Order="2" Property="ZTTAP300_X86_INSTALLED"/> <ROW SearchKey="UpgradeCode" SearchType="4" SearchString="{88AA80DE-14CA-4443-B024-6EC13F3EDDAD}" Order="2" Property="ZTTAP300_X86_INSTALLED"/>
<ROW SearchKey="_" SearchType="4" SearchString="{88AA80DE-14CA-4443-B024-6EC13F3EDDAD}" Order="1" Property="ZTTAP300_X64_INSTALLED"/> <ROW SearchKey="_" SearchType="4" SearchString="{88AA80DE-14CA-4443-B024-6EC13F3EDDAD}" Order="1" Property="ZTTAP300_X64_INSTALLED"/>
</COMPONENT> </COMPONENT>
@ -536,10 +573,10 @@
<ROW XmlAttribute="xsischemaLocation" XmlElement="swidsoftware_identification_tag" Name="xsi:schemaLocation" Flags="14" Order="3" Value="http://standards.iso.org/iso/19770/-2/2008/schema.xsd software_identification_tag.xsd"/> <ROW XmlAttribute="xsischemaLocation" XmlElement="swidsoftware_identification_tag" Name="xsi:schemaLocation" Flags="14" Order="3" Value="http://standards.iso.org/iso/19770/-2/2008/schema.xsd software_identification_tag.xsd"/>
</COMPONENT> </COMPONENT>
<COMPONENT cid="caphyon.advinst.msicomp.XmlElementComponent"> <COMPONENT cid="caphyon.advinst.msicomp.XmlElementComponent">
<ROW XmlElement="swidbuild" ParentElement="swidnumeric" Name="swid:build" Condition="1" Order="2" Flags="14" Text="6" UpdateIndexInParent="0"/> <ROW XmlElement="swidbuild" ParentElement="swidnumeric" Name="swid:build" Condition="1" Order="2" Flags="14" Text="0" UpdateIndexInParent="0"/>
<ROW XmlElement="swidentitlement_required_indicator" ParentElement="swidsoftware_identification_tag" Name="swid:entitlement_required_indicator" Condition="1" Order="0" Flags="14" Text="false" UpdateIndexInParent="0"/> <ROW XmlElement="swidentitlement_required_indicator" ParentElement="swidsoftware_identification_tag" Name="swid:entitlement_required_indicator" Condition="1" Order="0" Flags="14" Text="false" UpdateIndexInParent="0"/>
<ROW XmlElement="swidmajor" ParentElement="swidnumeric" Name="swid:major" Condition="1" Order="0" Flags="14" Text="1" UpdateIndexInParent="0"/> <ROW XmlElement="swidmajor" ParentElement="swidnumeric" Name="swid:major" Condition="1" Order="0" Flags="14" Text="1" UpdateIndexInParent="0"/>
<ROW XmlElement="swidminor" ParentElement="swidnumeric" Name="swid:minor" Condition="1" Order="1" Flags="14" Text="8" UpdateIndexInParent="0"/> <ROW XmlElement="swidminor" ParentElement="swidnumeric" Name="swid:minor" Condition="1" Order="1" Flags="14" Text="10" UpdateIndexInParent="0"/>
<ROW XmlElement="swidname" ParentElement="swidproduct_version" Name="swid:name" Condition="1" Order="0" Flags="14" Text="[ProductVersion]" UpdateIndexInParent="0"/> <ROW XmlElement="swidname" ParentElement="swidproduct_version" Name="swid:name" Condition="1" Order="0" Flags="14" Text="[ProductVersion]" UpdateIndexInParent="0"/>
<ROW XmlElement="swidname_1" ParentElement="swidsoftware_creator" Name="swid:name" Condition="1" Order="0" Flags="14" Text="ZeroTier, Inc." UpdateIndexInParent="0"/> <ROW XmlElement="swidname_1" ParentElement="swidsoftware_creator" Name="swid:name" Condition="1" Order="0" Flags="14" Text="ZeroTier, Inc." UpdateIndexInParent="0"/>
<ROW XmlElement="swidname_2" ParentElement="swidsoftware_licensor" Name="swid:name" Condition="1" Order="0" Flags="14" Text="ZeroTier, Inc." UpdateIndexInParent="0"/> <ROW XmlElement="swidname_2" ParentElement="swidsoftware_licensor" Name="swid:name" Condition="1" Order="0" Flags="14" Text="ZeroTier, Inc." UpdateIndexInParent="0"/>

View file

@ -1079,7 +1079,8 @@ enum ZT_Architecture
ZT_ARCHITECTURE_DOTNET_CLR = 13, ZT_ARCHITECTURE_DOTNET_CLR = 13,
ZT_ARCHITECTURE_JAVA_JVM = 14, ZT_ARCHITECTURE_JAVA_JVM = 14,
ZT_ARCHITECTURE_WEB = 15, ZT_ARCHITECTURE_WEB = 15,
ZT_ARCHITECTURE_S390X = 16 ZT_ARCHITECTURE_S390X = 16,
ZT_ARCHITECTURE_LOONGARCH64 = 17
}; };
/** /**
@ -1404,11 +1405,6 @@ typedef struct
*/ */
int bondingPolicy; int bondingPolicy;
/**
* The health status of the bond to this peer
*/
bool isHealthy;
/** /**
* The number of links that comprise the bond to this peer that are considered alive * The number of links that comprise the bond to this peer that are considered alive
*/ */

View file

@ -1,6 +1,6 @@
# This requires GNU make, which is typically "gmake" on BSD systems # This requires GNU make, which is typically "gmake" on BSD systems
INCLUDES= INCLUDES=-isystem ext
DEFS= DEFS=
LIBS= LIBS=
@ -152,7 +152,7 @@ endif
override DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\"" override DEFS+=-DZT_BUILD_PLATFORM=$(ZT_BUILD_PLATFORM) -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\""
CXXFLAGS+=$(CFLAGS) -std=c++11 #-D_GLIBCXX_USE_C99 -D_GLIBCXX_USE_C99_MATH -D_GLIBCXX_USE_C99_MATH_TR1 CXXFLAGS+=$(CFLAGS) -std=c++17 #-D_GLIBCXX_USE_C99 -D_GLIBCXX_USE_C99_MATH -D_GLIBCXX_USE_C99_MATH_TR1
all: one all: one

View file

@ -9,7 +9,7 @@ ifeq ($(origin CXX),default)
CXX:=$(shell if [ -e /opt/rh/devtoolset-8/root/usr/bin/g++ ]; then echo /opt/rh/devtoolset-8/root/usr/bin/g++; else echo $(CXX); fi) CXX:=$(shell if [ -e /opt/rh/devtoolset-8/root/usr/bin/g++ ]; then echo /opt/rh/devtoolset-8/root/usr/bin/g++; else echo $(CXX); fi)
endif endif
INCLUDES?=-Izeroidc/target INCLUDES?=-Izeroidc/target -isystem ext
DEFS?= DEFS?=
LDLIBS?= LDLIBS?=
DESTDIR?= DESTDIR?=
@ -31,7 +31,7 @@ ifeq ($(MINIUPNPC_IS_NEW_ENOUGH),1)
override DEFS+=-DZT_USE_SYSTEM_MINIUPNPC override DEFS+=-DZT_USE_SYSTEM_MINIUPNPC
LDLIBS+=-lminiupnpc LDLIBS+=-lminiupnpc
else else
override DEFS+=-DMINIUPNP_STATICLIB -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DOS_STRING=\"Linux\" -DMINIUPNPC_VERSION_STRING=\"2.0\" -DUPNP_VERSION_STRING=\"UPnP/1.1\" -DENABLE_STRNATPMPERR override DEFS+=-DMINIUPNP_STATICLIB -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -D_XOPEN_SOURCE=600 -DOS_STRING="\"Linux\"" -DMINIUPNPC_VERSION_STRING="\"2.0\"" -DUPNP_VERSION_STRING="\"UPnP/1.1\"" -DENABLE_STRNATPMPERR
ONE_OBJS+=ext/miniupnpc/connecthostport.o ext/miniupnpc/igd_desc_parse.o ext/miniupnpc/minisoap.o ext/miniupnpc/minissdpc.o ext/miniupnpc/miniupnpc.o ext/miniupnpc/miniwget.o ext/miniupnpc/minixml.o ext/miniupnpc/portlistingparse.o ext/miniupnpc/receivedata.o ext/miniupnpc/upnpcommands.o ext/miniupnpc/upnpdev.o ext/miniupnpc/upnperrors.o ext/miniupnpc/upnpreplyparse.o ONE_OBJS+=ext/miniupnpc/connecthostport.o ext/miniupnpc/igd_desc_parse.o ext/miniupnpc/minisoap.o ext/miniupnpc/minissdpc.o ext/miniupnpc/miniupnpc.o ext/miniupnpc/miniwget.o ext/miniupnpc/minixml.o ext/miniupnpc/portlistingparse.o ext/miniupnpc/receivedata.o ext/miniupnpc/upnpcommands.o ext/miniupnpc/upnpdev.o ext/miniupnpc/upnperrors.o ext/miniupnpc/upnpreplyparse.o
endif endif
ifeq ($(wildcard /usr/include/natpmp.h),) ifeq ($(wildcard /usr/include/natpmp.h),)
@ -59,32 +59,33 @@ ifeq ($(ZT_SANITIZE),1)
endif endif
ifeq ($(ZT_DEBUG),1) ifeq ($(ZT_DEBUG),1)
override CFLAGS+=-Wall -Wno-deprecated -g -O -pthread $(INCLUDES) $(DEFS) override CFLAGS+=-Wall -Wno-deprecated -g -O -pthread $(INCLUDES) $(DEFS)
override CXXFLAGS+=-Wall -Wno-deprecated -g -O -std=c++11 -pthread $(INCLUDES) $(DEFS) override CXXFLAGS+=-Wall -Wno-deprecated -g -O -std=c++17 -pthread $(INCLUDES) $(DEFS)
ZT_TRACE=1 ZT_TRACE=1
RUSTFLAGS= RUSTFLAGS=
# The following line enables optimization for the crypto code, since # The following line enables optimization for the crypto code, since
# C25519 in particular is almost UNUSABLE in -O0 even on a 3ghz box! # C25519 in particular is almost UNUSABLE in -O0 even on a 3ghz box!
node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CXXFLAGS=-Wall -O2 -g -pthread $(INCLUDES) $(DEFS) node/Salsa20.o node/SHA512.o node/C25519.o node/Poly1305.o: CXXFLAGS=-Wall -O2 -g -pthread $(INCLUDES) $(DEFS)
else else
CFLAGS?=-O3 -fstack-protector -fPIE CFLAGS?=-O3 -fstack-protector
override CFLAGS+=-Wall -Wno-deprecated -pthread $(INCLUDES) -DNDEBUG $(DEFS) override CFLAGS+=-Wall -Wno-deprecated -pthread $(INCLUDES) -DNDEBUG $(DEFS)
CXXFLAGS?=-O3 -fstack-protector -fPIE CXXFLAGS?=-O3 -fstack-protector
override CXXFLAGS+=-Wall -Wno-deprecated -std=c++11 -pthread $(INCLUDES) -DNDEBUG $(DEFS) override CXXFLAGS+=-Wall -Wno-deprecated -std=c++17 -pthread $(INCLUDES) -DNDEBUG $(DEFS)
LDFLAGS=-pie -Wl,-z,relro,-z,now LDFLAGS=-pie -Wl,-z,relro,-z,now
RUSTFLAGS=--release RUSTFLAGS=--release
endif endif
ifeq ($(ZT_QNAP), 1) ifeq ($(ZT_QNAP), 1)
override DEFS+=-D__QNAP__ override DEFS+=-D__QNAP__
ZT_EMBEDDED=1
endif endif
ifeq ($(ZT_UBIQUITI), 1) ifeq ($(ZT_UBIQUITI), 1)
override DEFS+=-D__UBIQUITI__ override DEFS+=-D__UBIQUITI__
ZT_EMBEDDED=1
endif endif
ifeq ($(ZT_SYNOLOGY), 1) ifeq ($(ZT_SYNOLOGY), 1)
override CFLAGS+=-fPIC
override CXXFLAGS+=-fPIC
override DEFS+=-D__SYNOLOGY__ override DEFS+=-D__SYNOLOGY__
ZT_EMBEDDED=1
endif endif
ifeq ($(ZT_DISABLE_COMPRESSION), 1) ifeq ($(ZT_DISABLE_COMPRESSION), 1)
@ -249,6 +250,10 @@ endif
ifeq ($(CC_MACH),riscv64) ifeq ($(CC_MACH),riscv64)
ZT_ARCHITECTURE=0 ZT_ARCHITECTURE=0
endif endif
ifeq ($(CC_MACH),loongarch64)
ZT_ARCHITECTURE=17
override DEFS+=-DZT_NO_TYPE_PUNNING
endif
# Fail if system architecture could not be determined # Fail if system architecture could not be determined
ifeq ($(ZT_ARCHITECTURE),999) ifeq ($(ZT_ARCHITECTURE),999)
@ -268,12 +273,15 @@ ifeq ($(ZT_IA32),1)
endif endif
ifeq ($(ZT_SSO_SUPPORTED), 1) ifeq ($(ZT_SSO_SUPPORTED), 1)
ifeq ($(ZT_EMBEDDED),)
override DEFS+=-DZT_SSO_SUPPORTED=1
ifeq ($(ZT_DEBUG),1) ifeq ($(ZT_DEBUG),1)
LDLIBS+=zeroidc/target/debug/libzeroidc.a -ldl -lssl -lcrypto LDLIBS+=zeroidc/target/debug/libzeroidc.a -ldl -lssl -lcrypto
else else
LDLIBS+=zeroidc/target/release/libzeroidc.a -ldl -lssl -lcrypto LDLIBS+=zeroidc/target/release/libzeroidc.a -ldl -lssl -lcrypto
endif endif
endif endif
endif
# Disable software updates by default on Linux since that is normally done with package management # Disable software updates by default on Linux since that is normally done with package management
override DEFS+=-DZT_BUILD_PLATFORM=1 -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\"" override DEFS+=-DZT_BUILD_PLATFORM=1 -DZT_BUILD_ARCHITECTURE=$(ZT_ARCHITECTURE) -DZT_SOFTWARE_UPDATE_DEFAULT="\"disable\""
@ -306,8 +314,8 @@ ifeq ($(ZT_ARCHITECTURE),3)
override CXXFLAGS+=-march=armv5t -mfloat-abi=soft -msoft-float -mno-unaligned-access -marm override CXXFLAGS+=-march=armv5t -mfloat-abi=soft -msoft-float -mno-unaligned-access -marm
ZT_USE_ARM32_NEON_ASM_CRYPTO=0 ZT_USE_ARM32_NEON_ASM_CRYPTO=0
else else
override CFLAGS+=-mfloat-abi=hard -march=armv6kz -marm -mfpu=vfp -mno-unaligned-access -mtp=cp15 -mcpu=arm1176jzf-s override CFLAGS+=-mfloat-abi=hard -march=armv6zk -marm -mfpu=vfp -mno-unaligned-access -mtp=cp15 -mcpu=arm1176jzf-s
override CXXFLAGS+=-mfloat-abi=hard -march=armv6kz -marm -mfpu=vfp -fexceptions -mno-unaligned-access -mtp=cp15 -mcpu=arm1176jzf-s override CXXFLAGS+=-mfloat-abi=hard -march=armv6zk -marm -mfpu=vfp -fexceptions -mno-unaligned-access -mtp=cp15 -mcpu=arm1176jzf-s
ZT_USE_ARM32_NEON_ASM_CRYPTO=0 ZT_USE_ARM32_NEON_ASM_CRYPTO=0
endif endif
endif endif
@ -326,12 +334,20 @@ ifeq ($(ZT_USE_ARM32_NEON_ASM_CRYPTO),1)
override CORE_OBJS+=ext/arm32-neon-salsa2012-asm/salsa2012.o override CORE_OBJS+=ext/arm32-neon-salsa2012-asm/salsa2012.o
endif endif
# Position Independence
override CFLAGS+=-fPIC -fPIE
override CXXFLAGS+=-fPIC -fPIE
.PHONY: all .PHONY: all
all: one all: one
.PHONY: one .PHONY: one
one: zerotier-one zerotier-idtool zerotier-cli one: zerotier-one zerotier-idtool zerotier-cli
from_builder:
ln -sf zerotier-one zerotier-idtool
ln -sf zerotier-one zerotier-cli
zerotier-one: $(CORE_OBJS) $(ONE_OBJS) one.o zerotier-one: $(CORE_OBJS) $(ONE_OBJS) one.o
$(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LDLIBS) $(CXX) $(CXXFLAGS) $(LDFLAGS) -o zerotier-one $(CORE_OBJS) $(ONE_OBJS) one.o $(LDLIBS)
@ -344,7 +360,7 @@ zerotier-cli: zerotier-one
$(ONE_OBJS): zeroidc $(ONE_OBJS): zeroidc
libzerotiercore.a: FORCE libzerotiercore.a: FORCE
make CFLAGS="-O3 -fstack-protector -fPIC" CXXFLAGS="-O3 -std=c++11 -fstack-protector -fPIC" $(CORE_OBJS) make CFLAGS="-O3 -fstack-protector -fPIC" CXXFLAGS="-O3 -std=c++17 -fstack-protector -fPIC" $(CORE_OBJS)
ar rcs libzerotiercore.a $(CORE_OBJS) ar rcs libzerotiercore.a $(CORE_OBJS)
ranlib libzerotiercore.a ranlib libzerotiercore.a
@ -384,9 +400,11 @@ debug: FORCE
make ZT_DEBUG=1 selftest make ZT_DEBUG=1 selftest
ifeq ($(ZT_SSO_SUPPORTED), 1) ifeq ($(ZT_SSO_SUPPORTED), 1)
ifeq ($(ZT_EMBEDDED),)
zeroidc: FORCE zeroidc: FORCE
# export PATH=/root/.cargo/bin:$$PATH; cd zeroidc && cargo build -j1 $(RUSTFLAGS) # export PATH=/root/.cargo/bin:$$PATH; cd zeroidc && cargo build -j1 $(RUSTFLAGS)
export PATH=/root/.cargo/bin:$$PATH; cd zeroidc && cargo build $(RUSTFLAGS) export PATH=/${HOME}/.cargo/bin:$$PATH; cd zeroidc && cargo build $(RUSTFLAGS)
endif
else else
zeroidc: zeroidc:
endif endif
@ -440,6 +458,20 @@ uninstall: FORCE
# These are just for convenience for building Linux packages # These are just for convenience for building Linux packages
echo_flags:
@echo "=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~"
@echo "echo_flags :: CC=$(CC)"
@echo "echo_flags :: CXX=$(CXX)"
@echo "echo_flags :: CFLAGS=$(CFLAGS)"
@echo "echo_flags :: CXXFLAGS=$(CXXFLAGS)"
@echo "echo_flags :: LDFLAGS=$(LDFLAGS)"
@echo "echo_flags :: RUSTFLAGS=$(RUSTFLAGS)"
@echo "=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~"
# debian: echo_flags
# @echo "building deb package"
# debuild --no-lintian -b -uc -us
debian: FORCE debian: FORCE
debuild --no-lintian -I -i -us -uc -nc -b debuild --no-lintian -I -i -us -uc -nc -b
@ -478,4 +510,20 @@ snap-upload-stable: FORCE
snapcraft upload --release=stable $${SNAPFILE};\ snapcraft upload --release=stable $${SNAPFILE};\
done done
synology-pkg: FORCE
cd pkg/synology ; ./build.sh build
synology-docker: FORCE
cd pkg/synology/dsm7-docker/; ./build.sh build-and-push
munge_rpm:
@:$(call check_defined, VERSION)
@echo "Updating rpm spec to $(VERSION)"
ci/scripts/munge_rpm_spec.sh zerotier-one.spec $(VERSION) "Adam Ierymenko <adam.ierymenko@zerotier.com>" "see https://github.com/zerotier/ZeroTierOne for release notes"
munge_deb:
@:$(call check_defined, VERSION)
@echo "Updating debian/changelog to $(VERSION)"
ci/scripts/munge_debian_changelog.sh debian/changelog $(VERSION) "Adam Ierymenko <adam.ierymenko@zerotier.com>" "see https://github.com/zerotier/ZeroTierOne for release notes"
FORCE: FORCE:

View file

@ -2,7 +2,7 @@ CC=clang
CXX=clang++ CXX=clang++
TOPDIR=$(shell PWD) TOPDIR=$(shell PWD)
INCLUDES=-I$(shell PWD)/zeroidc/target INCLUDES=-I$(shell PWD)/zeroidc/target -isystem $(TOPDIR)/ext
DEFS= DEFS=
LIBS= LIBS=
ARCH_FLAGS=-arch x86_64 -arch arm64 ARCH_FLAGS=-arch x86_64 -arch arm64
@ -47,10 +47,10 @@ endif
# Use fast ASM Salsa20/12 for x64 processors # Use fast ASM Salsa20/12 for x64 processors
DEFS+=-DZT_USE_X64_ASM_SALSA2012 DEFS+=-DZT_USE_X64_ASM_SALSA2012
CORE_OBJS+=ext/x64-salsa2012-asm/salsa2012.o CORE_OBJS+=ext/x64-salsa2012-asm/salsa2012.o
CXXFLAGS=$(CFLAGS) -std=c++11 -stdlib=libc++ CXXFLAGS=$(CFLAGS) -std=c++17 -stdlib=libc++
# Build miniupnpc and nat-pmp as included libraries -- extra defs are required for these sources # Build miniupnpc and nat-pmp as included libraries -- extra defs are required for these sources
DEFS+=-DMACOSX -DZT_USE_MINIUPNPC -DMINIUPNP_STATICLIB -D_DARWIN_C_SOURCE -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -DOS_STRING=\"Darwin/15.0.0\" -DMINIUPNPC_VERSION_STRING=\"2.0\" -DUPNP_VERSION_STRING=\"UPnP/1.1\" -DENABLE_STRNATPMPERR DEFS+=-DMACOSX -DZT_SSO_SUPPORTED -DZT_USE_MINIUPNPC -DMINIUPNP_STATICLIB -D_DARWIN_C_SOURCE -DMINIUPNPC_SET_SOCKET_TIMEOUT -DMINIUPNPC_GET_SRC_ADDR -D_BSD_SOURCE -D_DEFAULT_SOURCE -DOS_STRING=\"Darwin/15.0.0\" -DMINIUPNPC_VERSION_STRING=\"2.0\" -DUPNP_VERSION_STRING=\"UPnP/1.1\" -DENABLE_STRNATPMPERR
ONE_OBJS+=ext/libnatpmp/natpmp.o ext/libnatpmp/getgateway.o ext/miniupnpc/connecthostport.o ext/miniupnpc/igd_desc_parse.o ext/miniupnpc/minisoap.o ext/miniupnpc/minissdpc.o ext/miniupnpc/miniupnpc.o ext/miniupnpc/miniwget.o ext/miniupnpc/minixml.o ext/miniupnpc/portlistingparse.o ext/miniupnpc/receivedata.o ext/miniupnpc/upnpcommands.o ext/miniupnpc/upnpdev.o ext/miniupnpc/upnperrors.o ext/miniupnpc/upnpreplyparse.o osdep/PortMapper.o ONE_OBJS+=ext/libnatpmp/natpmp.o ext/libnatpmp/getgateway.o ext/miniupnpc/connecthostport.o ext/miniupnpc/igd_desc_parse.o ext/miniupnpc/minisoap.o ext/miniupnpc/minissdpc.o ext/miniupnpc/miniupnpc.o ext/miniupnpc/miniwget.o ext/miniupnpc/minixml.o ext/miniupnpc/portlistingparse.o ext/miniupnpc/receivedata.o ext/miniupnpc/upnpcommands.o ext/miniupnpc/upnpdev.o ext/miniupnpc/upnperrors.o ext/miniupnpc/upnpreplyparse.o osdep/PortMapper.o
ifeq ($(ZT_CONTROLLER),1) ifeq ($(ZT_CONTROLLER),1)
MACOS_VERSION_MIN=10.15 MACOS_VERSION_MIN=10.15
@ -154,6 +154,10 @@ selftest: $(CORE_OBJS) $(ONE_OBJS) selftest.o
zerotier-selftest: selftest zerotier-selftest: selftest
# Make compile_commands.json for clangd editor extensions. Probably works on Linux too.
compile_commands: FORCE
compiledb make ZT_DEBUG=1
# Requires Packages: http://s.sudre.free.fr/Software/Packages/about.html # Requires Packages: http://s.sudre.free.fr/Software/Packages/about.html
mac-dist-pkg: FORCE mac-dist-pkg: FORCE
packagesbuild "ext/installfiles/mac/ZeroTier One.pkgproj" packagesbuild "ext/installfiles/mac/ZeroTier One.pkgproj"

View file

@ -12,11 +12,12 @@
/****/ /****/
#include "Bond.hpp" #include "Bond.hpp"
#include "Switch.hpp" #include "Switch.hpp"
#include <cmath> #include <cmath>
#include <string>
#include <cstdio> #include <cstdio>
#include <string>
namespace ZeroTier { namespace ZeroTier {
@ -39,6 +40,9 @@ std::map<std::string, std::map<std::string, SharedPtr<Link> > > Bond::_interface
bool Bond::linkAllowed(std::string& policyAlias, SharedPtr<Link> link) bool Bond::linkAllowed(std::string& policyAlias, SharedPtr<Link> link)
{ {
if (! link) {
return false;
}
bool foundInDefinitions = false; bool foundInDefinitions = false;
if (_linkDefinitions.count(policyAlias)) { if (_linkDefinitions.count(policyAlias)) {
auto it = _linkDefinitions[policyAlias].begin(); auto it = _linkDefinitions[policyAlias].begin();
@ -90,7 +94,7 @@ SharedPtr<Bond> Bond::getBondByPeerId(int64_t identity)
return _bonds.count(identity) ? _bonds[identity] : SharedPtr<Bond>(); return _bonds.count(identity) ? _bonds[identity] : SharedPtr<Bond>();
} }
SharedPtr<Bond> Bond::createTransportTriggeredBond(const RuntimeEnvironment* renv, const SharedPtr<Peer>& peer) SharedPtr<Bond> Bond::createBond(const RuntimeEnvironment* renv, const SharedPtr<Peer>& peer)
{ {
Mutex::Lock _l(_bonds_m); Mutex::Lock _l(_bonds_m);
int64_t identity = peer->identity().address().toInt(); int64_t identity = peer->identity().address().toInt();
@ -145,7 +149,13 @@ SharedPtr<Bond> Bond::createTransportTriggeredBond(const RuntimeEnvironment* ren
return SharedPtr<Bond>(); return SharedPtr<Bond>();
} }
SharedPtr<Link> Bond::getLinkBySocket(const std::string& policyAlias, uint64_t localSocket) void Bond::destroyBond(uint64_t peerId)
{
Mutex::Lock _l(_bonds_m);
_bonds.erase(peerId);
}
SharedPtr<Link> Bond::getLinkBySocket(const std::string& policyAlias, uint64_t localSocket, bool createIfNeeded = false)
{ {
Mutex::Lock _l(_links_m); Mutex::Lock _l(_links_m);
char ifname[64] = { 0 }; char ifname[64] = { 0 };
@ -153,11 +163,15 @@ SharedPtr<Link> Bond::getLinkBySocket(const std::string& policyAlias, uint64_t l
std::string ifnameStr(ifname); std::string ifnameStr(ifname);
auto search = _interfaceToLinkMap[policyAlias].find(ifnameStr); auto search = _interfaceToLinkMap[policyAlias].find(ifnameStr);
if (search == _interfaceToLinkMap[policyAlias].end()) { if (search == _interfaceToLinkMap[policyAlias].end()) {
// If the link wasn't already known, add a new entry if (createIfNeeded) {
SharedPtr<Link> s = new Link(ifnameStr, 0, 0, true, ZT_BOND_SLAVE_MODE_SPARE, "", 0.0); SharedPtr<Link> s = new Link(ifnameStr, 0, 0, true, ZT_BOND_SLAVE_MODE_SPARE, "", 0.0);
_interfaceToLinkMap[policyAlias].insert(std::pair<std::string, SharedPtr<Link> >(ifnameStr, s)); _interfaceToLinkMap[policyAlias].insert(std::pair<std::string, SharedPtr<Link> >(ifnameStr, s));
return s; return s;
} }
else {
return SharedPtr<Link>();
}
}
else { else {
return search->second; return search->second;
} }
@ -218,10 +232,12 @@ Bond::Bond(const RuntimeEnvironment* renv, SharedPtr<Bond> originalBond, const S
void Bond::nominatePathToBond(const SharedPtr<Path>& path, int64_t now) void Bond::nominatePathToBond(const SharedPtr<Path>& path, int64_t now)
{ {
Mutex::Lock _l(_paths_m); Mutex::Lock _l(_paths_m);
debug("attempting to nominate link %s", pathToStr(path).c_str());
/** /**
* Ensure the link is allowed and the path is not already present * Ensure the link is allowed and the path is not already present
*/ */
if (! RR->bc->linkAllowed(_policyAlias, getLink(path))) { if (! RR->bc->linkAllowed(_policyAlias, getLinkBySocket(_policyAlias, path->localSocket(), true))) {
debug("link %s is not permitted according to user-specified rules", pathToStr(path).c_str());
return; return;
} }
bool alreadyPresent = false; bool alreadyPresent = false;
@ -229,6 +245,7 @@ void Bond::nominatePathToBond(const SharedPtr<Path>& path, int64_t now)
// Sanity check // Sanity check
if (path.ptr() == _paths[i].p.ptr()) { if (path.ptr() == _paths[i].p.ptr()) {
alreadyPresent = true; alreadyPresent = true;
debug("link %s already exists", pathToStr(path).c_str());
break; break;
} }
} }
@ -247,9 +264,10 @@ void Bond::nominatePathToBond(const SharedPtr<Path>& path, int64_t now)
// Determine if there are any other paths on this link // Determine if there are any other paths on this link
bool bFoundCommonLink = false; bool bFoundCommonLink = false;
SharedPtr<Link> commonLink = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); SharedPtr<Link> commonLink = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket());
if (commonLink) {
for (unsigned int j = 0; j < ZT_MAX_PEER_NETWORK_PATHS; ++j) { for (unsigned int j = 0; j < ZT_MAX_PEER_NETWORK_PATHS; ++j) {
if (_paths[j].p && _paths[j].p.ptr() != _paths[i].p.ptr()) { if (_paths[j].p && _paths[j].p.ptr() != _paths[i].p.ptr()) {
if (RR->bc->getLinkBySocket(_policyAlias, _paths[j].p->localSocket()) == commonLink) { if (RR->bc->getLinkBySocket(_policyAlias, _paths[j].p->localSocket()) == commonLink, true) {
bFoundCommonLink = true; bFoundCommonLink = true;
_paths[j].onlyPathOnLink = false; _paths[j].onlyPathOnLink = false;
} }
@ -260,7 +278,8 @@ void Bond::nominatePathToBond(const SharedPtr<Path>& path, int64_t now)
_paths[i].enabled = sl->enabled(); _paths[i].enabled = sl->enabled();
_paths[i].onlyPathOnLink = ! bFoundCommonLink; _paths[i].onlyPathOnLink = ! bFoundCommonLink;
} }
log("nominate link %s", pathToStr(path).c_str()); }
log("nominated link %s", pathToStr(path).c_str());
break; break;
} }
} }
@ -367,7 +386,7 @@ void Bond::recordIncomingInvalidPacket(const SharedPtr<Path>& path)
Mutex::Lock _l(_paths_m); Mutex::Lock _l(_paths_m);
for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p == path) { if (_paths[i].p == path) {
_paths[i].packetValiditySamples.push(false); //_paths[i].packetValiditySamples.push(false);
} }
} }
} }
@ -388,9 +407,10 @@ void Bond::recordOutgoingPacket(const SharedPtr<Path>& path, uint64_t packetId,
_lastFrame = now; _lastFrame = now;
} }
if (shouldRecord) { if (shouldRecord) {
//_paths[pathIdx].expectingAckAsOf = now;
//_paths[pathIdx].totalBytesSentSinceLastAckRecieved += payloadLength;
//_paths[pathIdx].unackedBytes += payloadLength; //_paths[pathIdx].unackedBytes += payloadLength;
// Take note that we're expecting a VERB_ACK on this path as of a specific time if (_paths[pathIdx].qosStatsOut.size() < ZT_QOS_MAX_PENDING_RECORDS) {
if (_paths[pathIdx].qosStatsOut.size() < ZT_QOS_MAX_OUTSTANDING_RECORDS) {
_paths[pathIdx].qosStatsOut[packetId] = now; _paths[pathIdx].qosStatsOut[packetId] = now;
} }
} }
@ -423,9 +443,25 @@ void Bond::recordIncomingPacket(const SharedPtr<Path>& path, uint64_t packetId,
_lastFrame = now; _lastFrame = now;
} }
if (shouldRecord) { if (shouldRecord) {
if (_paths[pathIdx].qosStatsIn.size() < ZT_QOS_MAX_PENDING_RECORDS) {
// debug("Recording QoS information (table size = %d)", _paths[pathIdx].qosStatsIn.size());
_paths[pathIdx].qosStatsIn[packetId] = now; _paths[pathIdx].qosStatsIn[packetId] = now;
++(_paths[pathIdx].packetsReceivedSinceLastQoS); ++(_paths[pathIdx].packetsReceivedSinceLastQoS);
_paths[pathIdx].packetValiditySamples.push(true); //_paths[pathIdx].packetValiditySamples.push(true);
}
else {
debug("QoS buffer full, will not record information");
}
/*
if (_paths[pathIdx].ackStatsIn.size() < ZT_ACK_MAX_PENDING_RECORDS) {
//debug("Recording ACK information (table size = %d)", _paths[pathIdx].ackStatsIn.size());
_paths[pathIdx].ackStatsIn[packetId] = payloadLength;
++(_paths[pathIdx].packetsReceivedSinceLastAck);
}
else {
debug("ACK buffer full, will not record information");
}
*/
} }
} }
} }
@ -470,6 +506,16 @@ void Bond::receivedQoS(const SharedPtr<Path>& path, int64_t now, int count, uint
_paths[pathIdx].qosRecordSize.push(count); _paths[pathIdx].qosRecordSize.push(count);
} }
void Bond::receivedAck(int pathIdx, int64_t now, int32_t ackedBytes)
{
/*
Mutex::Lock _l(_paths_m);
debug("received ACK of %d bytes on path %s, there are still %d un-acked bytes", ackedBytes, pathToStr(_paths[pathIdx].p).c_str(), _paths[pathIdx].unackedBytes);
_paths[pathIdx].lastAckReceived = now;
_paths[pathIdx].unackedBytes = (ackedBytes > _paths[pathIdx].unackedBytes) ? 0 : _paths[pathIdx].unackedBytes - ackedBytes;
*/
}
int32_t Bond::generateQoSPacket(int pathIdx, int64_t now, char* qosBuffer) int32_t Bond::generateQoSPacket(int pathIdx, int64_t now, char* qosBuffer)
{ {
int32_t len = 0; int32_t len = 0;
@ -544,7 +590,6 @@ bool Bond::assignFlowToBondedPath(SharedPtr<Flow>& flow, int64_t now)
} }
flow->assignPath(_abPathIdx, now); flow->assignPath(_abPathIdx, now);
} }
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[flow->assignedPath].p->localSocket());
debug("assign out-flow %04x to link %s (%lu / %lu flows)", flow->id, pathToStr(_paths[flow->assignedPath].p).c_str(), _paths[flow->assignedPath].assignedFlowCount, (unsigned long)_flows.size()); debug("assign out-flow %04x to link %s (%lu / %lu flows)", flow->id, pathToStr(_paths[flow->assignedPath].p).c_str(), _paths[flow->assignedPath].assignedFlowCount, (unsigned long)_flows.size());
return true; return true;
} }
@ -631,6 +676,7 @@ void Bond::processIncomingPathNegotiationRequest(uint64_t now, SharedPtr<Path>&
return; return;
} }
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[pathIdx].p->localSocket()); SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[pathIdx].p->localSocket());
if (link) {
if (remoteUtility > _localUtility) { if (remoteUtility > _localUtility) {
_paths[pathIdx].p->address().toString(pathStr); _paths[pathIdx].p->address().toString(pathStr);
debug("peer suggests alternate link %s/%s, remote utility (%d) greater than local utility (%d), switching to suggested link\n", link->ifname().c_str(), pathStr, remoteUtility, _localUtility); debug("peer suggests alternate link %s/%s, remote utility (%d) greater than local utility (%d), switching to suggested link\n", link->ifname().c_str(), pathStr, remoteUtility, _localUtility);
@ -650,6 +696,7 @@ void Bond::processIncomingPathNegotiationRequest(uint64_t now, SharedPtr<Path>&
} }
} }
} }
}
void Bond::pathNegotiationCheck(void* tPtr, int64_t now) void Bond::pathNegotiationCheck(void* tPtr, int64_t now)
{ {
@ -717,16 +764,42 @@ void Bond::sendPATH_NEGOTIATION_REQUEST(void* tPtr, int pathIdx)
if (_paths[pathIdx].p->address()) { if (_paths[pathIdx].p->address()) {
outp.armor(_peer->key(), false, _peer->aesKeysIfSupported()); outp.armor(_peer->key(), false, _peer->aesKeysIfSupported());
RR->node->putPacket(tPtr, _paths[pathIdx].p->localSocket(), _paths[pathIdx].p->address(), outp.data(), outp.size()); RR->node->putPacket(tPtr, _paths[pathIdx].p->localSocket(), _paths[pathIdx].p->address(), outp.data(), outp.size());
_overheadBytes += outp.size();
} }
} }
void Bond::sendACK(void* tPtr, int pathIdx, int64_t localSocket, const InetAddress& atAddress, int64_t now)
{
/*
Packet outp(_peer->_id.address(), RR->identity.address(), Packet::VERB_ACK);
int32_t bytesToAck = 0;
std::map<uint64_t, uint64_t>::iterator it = _paths[pathIdx].ackStatsIn.begin();
while (it != _paths[pathIdx].ackStatsIn.end()) {
bytesToAck += it->second;
++it;
}
debug("sending ACK of %d bytes on path %s (table size = %d)", bytesToAck, pathToStr(_paths[pathIdx].p).c_str(), _paths[pathIdx].ackStatsIn.size());
outp.append<uint32_t>(bytesToAck);
if (atAddress) {
outp.armor(_peer->key(), false, _peer->aesKeysIfSupported());
RR->node->putPacket(tPtr, localSocket, atAddress, outp.data(), outp.size());
}
else {
RR->sw->send(tPtr, outp, false);
}
_paths[pathIdx].ackStatsIn.clear();
_paths[pathIdx].packetsReceivedSinceLastAck = 0;
_paths[pathIdx].lastAckSent = now;
*/
}
void Bond::sendQOS_MEASUREMENT(void* tPtr, int pathIdx, int64_t localSocket, const InetAddress& atAddress, int64_t now) void Bond::sendQOS_MEASUREMENT(void* tPtr, int pathIdx, int64_t localSocket, const InetAddress& atAddress, int64_t now)
{ {
int64_t _now = RR->node->now(); int64_t _now = RR->node->now();
Packet outp(_peer->_id.address(), RR->identity.address(), Packet::VERB_QOS_MEASUREMENT); Packet outp(_peer->_id.address(), RR->identity.address(), Packet::VERB_QOS_MEASUREMENT);
char qosData[ZT_QOS_MAX_PACKET_SIZE]; char qosData[ZT_QOS_MAX_PACKET_SIZE];
int16_t len = generateQoSPacket(pathIdx, _now, qosData); int16_t len = generateQoSPacket(pathIdx, _now, qosData);
_overheadBytes += len; // debug("sending QOS via link %s (len=%d)", pathToStr(_paths[pathIdx].p).c_str(), len);
if (len) { if (len) {
outp.append(qosData, len); outp.append(qosData, len);
if (atAddress) { if (atAddress) {
@ -738,8 +811,8 @@ void Bond::sendQOS_MEASUREMENT(void* tPtr, int pathIdx, int64_t localSocket, con
} }
_paths[pathIdx].packetsReceivedSinceLastQoS = 0; _paths[pathIdx].packetsReceivedSinceLastQoS = 0;
_paths[pathIdx].lastQoSMeasurement = now; _paths[pathIdx].lastQoSMeasurement = now;
_overheadBytes += outp.size();
} }
// debug("send QOS via link %s (len=%d)", pathToStr(_paths[pathIdx].p).c_str(), len);
} }
void Bond::processBackgroundBondTasks(void* tPtr, int64_t now) void Bond::processBackgroundBondTasks(void* tPtr, int64_t now)
@ -761,7 +834,7 @@ void Bond::processBackgroundBondTasks(void* tPtr, int64_t now)
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p && _paths[i].allowed()) { if (_paths[i].p && _paths[i].allowed()) {
if (_isLeaf) { if (_isLeaf) {
if ((_monitorInterval > 0) && (((now - _paths[i].p->_lastIn) >= _monitorInterval) /*|| ((now - _paths[i].p->_lastOut) >= _monitorInterval)*/)) { if ((_monitorInterval > 0) && (((now - _paths[i].p->_lastIn) >= (_paths[i].alive ? _monitorInterval : _failoverInterval)))) {
if ((_peer->remoteVersionProtocol() >= 5) && (! ((_peer->remoteVersionMajor() == 1) && (_peer->remoteVersionMinor() == 1) && (_peer->remoteVersionRevision() == 0)))) { if ((_peer->remoteVersionProtocol() >= 5) && (! ((_peer->remoteVersionMajor() == 1) && (_peer->remoteVersionMinor() == 1) && (_peer->remoteVersionRevision() == 0)))) {
Packet outp(_peer->address(), RR->identity.address(), Packet::VERB_ECHO); // ECHO (this is our bond's heartbeat) Packet outp(_peer->address(), RR->identity.address(), Packet::VERB_ECHO); // ECHO (this is our bond's heartbeat)
outp.armor(_peer->key(), true, _peer->aesKeysIfSupported()); outp.armor(_peer->key(), true, _peer->aesKeysIfSupported());
@ -776,6 +849,12 @@ void Bond::processBackgroundBondTasks(void* tPtr, int64_t now)
if (_paths[i].needsToSendQoS(now, _qosSendInterval)) { if (_paths[i].needsToSendQoS(now, _qosSendInterval)) {
sendQOS_MEASUREMENT(tPtr, i, _paths[i].p->localSocket(), _paths[i].p->address(), now); sendQOS_MEASUREMENT(tPtr, i, _paths[i].p->localSocket(), _paths[i].p->address(), now);
} }
// ACK
/*
if (_paths[i].needsToSendAck(now, _ackSendInterval)) {
sendACK(tPtr, i, _paths[i].p->localSocket(), _paths[i].p->address(), now);
}
*/
} }
} }
} }
@ -815,6 +894,24 @@ void Bond::curateBond(int64_t now, bool rebuildBond)
if (! _paths[i].p) { if (! _paths[i].p) {
continue; continue;
} }
/**
* Remove expired or invalid links from bond
*/
SharedPtr<Link> link = getLink(_paths[i].p);
if (! link) {
log("link is no longer valid, removing from bond");
_paths[i] = NominatedPath();
_paths[i].p = SharedPtr<Path>();
continue;
}
if ((now - _paths[i].p->_lastIn) > (ZT_PEER_EXPIRED_PATH_TRIAL_PERIOD)) {
log("link (%s) has expired or is invalid, removing from bond", pathToStr(_paths[i].p).c_str());
_paths[i] = NominatedPath();
_paths[i].p = SharedPtr<Path>();
continue;
}
tmpNumTotalLinks++; tmpNumTotalLinks++;
if (_paths[i].eligible) { if (_paths[i].eligible) {
tmpNumAliveLinks++; tmpNumAliveLinks++;
@ -875,42 +972,18 @@ void Bond::curateBond(int64_t now, bool rebuildBond)
} }
/** /**
* Determine health status to report to user * Trigger status report if number of links change
*/ */
_numAliveLinks = tmpNumAliveLinks; _numAliveLinks = tmpNumAliveLinks;
_numTotalLinks = tmpNumTotalLinks; _numTotalLinks = tmpNumTotalLinks;
bool tmpHealthStatus = true; if ((_numAliveLinks != tmpNumAliveLinks) || (_numTotalLinks != tmpNumTotalLinks)) {
if (_policy == ZT_BOND_POLICY_BROADCAST) {
if (_numAliveLinks < 1) {
// Considered healthy if we're able to send frames at all
tmpHealthStatus = false;
}
}
if ((_policy == ZT_BOND_POLICY_BALANCE_RR) || (_policy == ZT_BOND_POLICY_BALANCE_XOR) || (_policy == ZT_BOND_POLICY_BALANCE_AWARE || (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP))) {
if (_numAliveLinks < _numTotalLinks) {
tmpHealthStatus = false;
}
}
if (tmpHealthStatus != _isHealthy) {
std::string healthStatusStr;
if (tmpHealthStatus == true) {
healthStatusStr = "HEALTHY";
}
else {
healthStatusStr = "DEGRADED";
}
log("bond is %s (%d/%d links)", healthStatusStr.c_str(), _numAliveLinks, _numTotalLinks);
dumpInfo(now, true); dumpInfo(now, true);
} }
_isHealthy = tmpHealthStatus;
/** /**
* Curate the set of paths that are part of the bond proper. Select a set of paths * Curate the set of paths that are part of the bond proper. Select a set of paths
* per logical link according to eligibility and user-specified constraints. * per logical link according to eligibility and user-specified constraints.
*/ */
if ((_policy == ZT_BOND_POLICY_BALANCE_RR) || (_policy == ZT_BOND_POLICY_BALANCE_XOR) || (_policy == ZT_BOND_POLICY_BALANCE_AWARE)) { if ((_policy == ZT_BOND_POLICY_BALANCE_RR) || (_policy == ZT_BOND_POLICY_BALANCE_XOR) || (_policy == ZT_BOND_POLICY_BALANCE_AWARE)) {
if (! _numBondedPaths) { if (! _numBondedPaths) {
rebuildBond = true; rebuildBond = true;
@ -923,9 +996,11 @@ void Bond::curateBond(int64_t now, bool rebuildBond)
for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) { if (_paths[i].p) {
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket());
if (link) {
linkMap[link].push_back(i); linkMap[link].push_back(i);
} }
} }
}
// Re-form bond from link<->path map // Re-form bond from link<->path map
std::map<SharedPtr<Link>, std::vector<int> >::iterator it = linkMap.begin(); std::map<SharedPtr<Link>, std::vector<int> >::iterator it = linkMap.begin();
while (it != linkMap.end()) { while (it != linkMap.end()) {
@ -1008,18 +1083,22 @@ void Bond::estimatePathQuality(int64_t now)
uint32_t totUserSpecifiedLinkSpeed = 0; uint32_t totUserSpecifiedLinkSpeed = 0;
if (_numBondedPaths) { // Compute relative user-specified speeds of links if (_numBondedPaths) { // Compute relative user-specified speeds of links
for (unsigned int i = 0; i < _numBondedPaths; ++i) { for (unsigned int i = 0; i < _numBondedPaths; ++i) {
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket());
if (_paths[i].p && _paths[i].allowed()) { if (_paths[i].p && _paths[i].allowed()) {
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket());
if (link) {
totUserSpecifiedLinkSpeed += link->speed(); totUserSpecifiedLinkSpeed += link->speed();
} }
} }
}
for (unsigned int i = 0; i < _numBondedPaths; ++i) { for (unsigned int i = 0; i < _numBondedPaths; ++i) {
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket());
if (_paths[i].p && _paths[i].allowed()) { if (_paths[i].p && _paths[i].allowed()) {
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket());
if (link) {
link->setRelativeSpeed((uint8_t)round(((float)link->speed() / (float)totUserSpecifiedLinkSpeed) * 255)); link->setRelativeSpeed((uint8_t)round(((float)link->speed() / (float)totUserSpecifiedLinkSpeed) * 255));
} }
} }
} }
}
float lat[ZT_MAX_PEER_NETWORK_PATHS] = { 0 }; float lat[ZT_MAX_PEER_NETWORK_PATHS] = { 0 };
float pdv[ZT_MAX_PEER_NETWORK_PATHS] = { 0 }; float pdv[ZT_MAX_PEER_NETWORK_PATHS] = { 0 };
@ -1044,7 +1123,7 @@ void Bond::estimatePathQuality(int64_t now)
// Compute/Smooth average of real-world observations // Compute/Smooth average of real-world observations
_paths[i].latencyMean = _paths[i].latencySamples.mean(); _paths[i].latencyMean = _paths[i].latencySamples.mean();
_paths[i].latencyVariance = _paths[i].latencySamples.stddev(); _paths[i].latencyVariance = _paths[i].latencySamples.stddev();
_paths[i].packetErrorRatio = 1.0 - (_paths[i].packetValiditySamples.count() ? _paths[i].packetValiditySamples.mean() : 1.0); //_paths[i].packetErrorRatio = 1.0 - (_paths[i].packetValiditySamples.count() ? _paths[i].packetValiditySamples.mean() : 1.0);
if (userHasSpecifiedLinkSpeeds()) { if (userHasSpecifiedLinkSpeeds()) {
// Use user-reported metrics // Use user-reported metrics
@ -1054,20 +1133,52 @@ void Bond::estimatePathQuality(int64_t now)
_paths[i].throughputVariance = 0; _paths[i].throughputVariance = 0;
} }
} }
// Drain unacknowledged QoS records // Drain unacknowledged QoS records
int qosRecordTimeout = (_qosSendInterval * 3);
std::map<uint64_t, uint64_t>::iterator it = _paths[i].qosStatsOut.begin(); std::map<uint64_t, uint64_t>::iterator it = _paths[i].qosStatsOut.begin();
uint64_t currentLostRecords = 0; int numDroppedQosOutRecords = 0;
while (it != _paths[i].qosStatsOut.end()) { while (it != _paths[i].qosStatsOut.end()) {
int qosRecordTimeout = 5000; //_paths[i].p->monitorInterval() * ZT_BOND_QOS_ACK_INTERVAL_MULTIPLIER * 8;
if ((now - it->second) >= qosRecordTimeout) { if ((now - it->second) >= qosRecordTimeout) {
// Packet was lost
it = _paths[i].qosStatsOut.erase(it); it = _paths[i].qosStatsOut.erase(it);
++currentLostRecords; ++numDroppedQosOutRecords;
} }
else { else {
++it; ++it;
} }
} }
if (numDroppedQosOutRecords) {
log("Dropped %d QOS out-records", numDroppedQosOutRecords);
}
/*
for (unsigned int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (! _paths[i].p) {
continue;
}
// if ((now - _paths[i].lastAckReceived) > ackSendInterval) {
// debug("been a while since ACK");
// if (_paths[i].unackedBytes > 0) {
// _paths[i].unackedBytes / _paths[i].bytesSen
// }
// }
}
*/
it = _paths[i].qosStatsIn.begin();
int numDroppedQosInRecords = 0;
while (it != _paths[i].qosStatsIn.end()) {
if ((now - it->second) >= qosRecordTimeout) {
it = _paths[i].qosStatsIn.erase(it);
++numDroppedQosInRecords;
}
else {
++it;
}
}
if (numDroppedQosInRecords) {
log("Dropped %d QOS in-records", numDroppedQosInRecords);
}
quality[i] = 0; quality[i] = 0;
totQuality = 0; totQuality = 0;
@ -1197,6 +1308,7 @@ void Bond::dequeueNextActiveBackupPath(uint64_t now)
bool Bond::abForciblyRotateLink() bool Bond::abForciblyRotateLink()
{ {
Mutex::Lock _l(_paths_m);
if (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP) { if (_policy == ZT_BOND_POLICY_ACTIVE_BACKUP) {
int prevPathIdx = _abPathIdx; int prevPathIdx = _abPathIdx;
dequeueNextActiveBackupPath(RR->node->now()); dequeueNextActiveBackupPath(RR->node->now());
@ -1209,9 +1321,14 @@ bool Bond::abForciblyRotateLink()
void Bond::processActiveBackupTasks(void* tPtr, int64_t now) void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
{ {
int prevActiveBackupPathIdx = _abPathIdx; int prevActiveBackupPathIdx = _abPathIdx;
int nonPreferredPathIdx; int nonPreferredPathIdx = ZT_MAX_PEER_NETWORK_PATHS;
bool bFoundPrimaryLink = false; bool bFoundPrimaryLink = false;
if (_abPathIdx != ZT_MAX_PEER_NETWORK_PATHS && ! _paths[_abPathIdx].p) {
_abPathIdx = ZT_MAX_PEER_NETWORK_PATHS;
log("main active-backup path has been removed");
}
/** /**
* Generate periodic status report * Generate periodic status report
*/ */
@ -1227,7 +1344,6 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
log("failover queue is empty, bond is no longer fault-tolerant"); log("failover queue is empty, bond is no longer fault-tolerant");
} }
} }
/** /**
* Select initial "active" active-backup link * Select initial "active" active-backup link
*/ */
@ -1241,7 +1357,6 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
* simply find the next eligible path. * simply find the next eligible path.
*/ */
if (! userHasSpecifiedLinks()) { if (! userHasSpecifiedLinks()) {
debug("no user-specified links");
for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p && _paths[i].eligible) { if (_paths[i].p && _paths[i].eligible) {
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket());
@ -1253,6 +1368,7 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
} }
} }
} }
/** /**
* [Manual mode] * [Manual mode]
* The user has specified links or failover rules that the bonding policy should adhere to. * The user has specified links or failover rules that the bonding policy should adhere to.
@ -1264,6 +1380,7 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
continue; continue;
} }
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket());
if (link) {
if (_paths[i].eligible && link->primary()) { if (_paths[i].eligible && link->primary()) {
if (! _paths[i].preferred()) { if (! _paths[i].preferred()) {
// Found path on primary link, take note in case we don't find a preferred path // Found path on primary link, take note in case we don't find a preferred path
@ -1273,25 +1390,28 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
if (_paths[i].preferred()) { if (_paths[i].preferred()) {
_abPathIdx = i; _abPathIdx = i;
bFoundPrimaryLink = true; bFoundPrimaryLink = true;
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[_abPathIdx].p->localSocket()); if (_paths[_abPathIdx].p) {
if (link) { SharedPtr<Link> abLink = RR->bc->getLinkBySocket(_policyAlias, _paths[_abPathIdx].p->localSocket());
if (abLink) {
log("found preferred primary link %s", pathToStr(_paths[_abPathIdx].p).c_str()); log("found preferred primary link %s", pathToStr(_paths[_abPathIdx].p).c_str());
} }
break; // Found preferred path on primary link break; // Found preferred path on primary link
} }
} }
} }
if (bFoundPrimaryLink && nonPreferredPathIdx) { }
}
if (bFoundPrimaryLink && (nonPreferredPathIdx != ZT_MAX_PEER_NETWORK_PATHS)) {
log("found non-preferred primary link"); log("found non-preferred primary link");
_abPathIdx = nonPreferredPathIdx; _abPathIdx = nonPreferredPathIdx;
} }
if (_abPathIdx == ZT_MAX_PEER_NETWORK_PATHS) { if (_abPathIdx == ZT_MAX_PEER_NETWORK_PATHS) {
log("user-designated primary link is not yet ready"); log("user-designated primary link is not available");
// TODO: Should wait for some time (failover interval?) and then switch to spare link // TODO: Should wait for some time (failover interval?) and then switch to spare link
} }
} }
else if (! userHasSpecifiedPrimaryLink()) { else if (! userHasSpecifiedPrimaryLink()) {
log("user did not specify a primary link, select first available link");
for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p && _paths[i].eligible) { if (_paths[i].p && _paths[i].eligible) {
_abPathIdx = i; _abPathIdx = i;
@ -1299,6 +1419,7 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
} }
} }
if (_abPathIdx != ZT_MAX_PEER_NETWORK_PATHS) { if (_abPathIdx != ZT_MAX_PEER_NETWORK_PATHS) {
if (_paths[_abPathIdx].p) {
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[_abPathIdx].p->localSocket()); SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[_abPathIdx].p->localSocket());
if (link) { if (link) {
log("select non-primary link %s", pathToStr(_paths[_abPathIdx].p).c_str()); log("select non-primary link %s", pathToStr(_paths[_abPathIdx].p).c_str());
@ -1307,20 +1428,27 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
} }
} }
} }
}
// Short-circuit if we don't have an active link yet // Short-circuit if we don't have an active link yet. Everything below is optimization from the base case
if (_abPathIdx == ZT_MAX_PEER_NETWORK_PATHS) { if (_abPathIdx < 0 || _abPathIdx == ZT_MAX_PEER_NETWORK_PATHS || (! _paths[_abPathIdx].p)) {
return; return;
} }
// Remove ineligible paths from the failover link queue // Remove ineligible paths from the failover link queue
for (std::deque<int>::iterator it(_abFailoverQueue.begin()); it != _abFailoverQueue.end();) { for (std::deque<int>::iterator it(_abFailoverQueue.begin()); it != _abFailoverQueue.end();) {
if (! _paths[(*it)].p) {
log("link is no longer valid, removing from failover queue (%zu links remain in queue)", _abFailoverQueue.size());
it = _abFailoverQueue.erase(it);
continue;
}
if (_paths[(*it)].p && ! _paths[(*it)].eligible) { if (_paths[(*it)].p && ! _paths[(*it)].eligible) {
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[(*it)].p->localSocket()); SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[(*it)].p->localSocket());
it = _abFailoverQueue.erase(it); it = _abFailoverQueue.erase(it);
if (link) { if (link) {
log("link %s is ineligible, removing from failover queue (%zu links in queue)", pathToStr(_paths[_abPathIdx].p).c_str(), _abFailoverQueue.size()); log("link %s is ineligible, removing from failover queue (%zu links remain in queue)", pathToStr(_paths[_abPathIdx].p).c_str(), _abFailoverQueue.size());
} }
continue;
} }
else { else {
++it; ++it;
@ -1345,7 +1473,9 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
continue; continue;
} }
SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket()); SharedPtr<Link> link = RR->bc->getLinkBySocket(_policyAlias, _paths[i].p->localSocket());
if (! link) {
continue;
}
int failoverScoreHandicap = _paths[i].failoverScore; int failoverScoreHandicap = _paths[i].failoverScore;
if (_paths[i].preferred()) { if (_paths[i].preferred()) {
failoverScoreHandicap += ZT_BOND_FAILOVER_HANDICAP_PREFERRED; failoverScoreHandicap += ZT_BOND_FAILOVER_HANDICAP_PREFERRED;
@ -1375,10 +1505,11 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
} }
} }
} }
if (_paths[i].p) {
if (_paths[i].p.ptr() != _paths[_abPathIdx].p.ptr()) { if (_paths[i].p.ptr() != _paths[_abPathIdx].p.ptr()) {
bool bFoundPathInQueue = false; bool bFoundPathInQueue = false;
for (std::deque<int>::iterator it(_abFailoverQueue.begin()); it != _abFailoverQueue.end(); ++it) { for (std::deque<int>::iterator it(_abFailoverQueue.begin()); it != _abFailoverQueue.end(); ++it) {
if (_paths[i].p.ptr() == _paths[(*it)].p.ptr()) { if (_paths[(*it)].p && (_paths[i].p.ptr() == _paths[(*it)].p.ptr())) {
bFoundPathInQueue = true; bFoundPathInQueue = true;
} }
} }
@ -1390,6 +1521,7 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
} }
} }
} }
}
/** /**
* No failover instructions provided by user, build queue according to performance * No failover instructions provided by user, build queue according to performance
* and IPv preference. * and IPv preference.
@ -1406,7 +1538,11 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
if (! _paths[i].eligible) { if (! _paths[i].eligible) {
failoverScoreHandicap = -10000; failoverScoreHandicap = -10000;
} }
if (getLink(_paths[i].p)->primary() && _abLinkSelectMethod != ZT_BOND_RESELECTION_POLICY_OPTIMIZE) { SharedPtr<Link> link = getLink(_paths[i].p);
if (! link) {
continue;
}
if (link->primary() && _abLinkSelectMethod != ZT_BOND_RESELECTION_POLICY_OPTIMIZE) {
// If using "optimize" primary re-select mode, ignore user link designations // If using "optimize" primary re-select mode, ignore user link designations
failoverScoreHandicap = ZT_BOND_FAILOVER_HANDICAP_PRIMARY; failoverScoreHandicap = ZT_BOND_FAILOVER_HANDICAP_PRIMARY;
} }
@ -1458,7 +1594,7 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
/** /**
* Fulfill primary re-select obligations * Fulfill primary re-select obligations
*/ */
if (_paths[_abPathIdx].p && ! _paths[_abPathIdx].eligible) { // Implicit ZT_BOND_RESELECTION_POLICY_FAILURE if (! _paths[_abPathIdx].eligible) { // Implicit ZT_BOND_RESELECTION_POLICY_FAILURE
log("link %s has failed, select link from failover queue (%zu links in queue)", pathToStr(_paths[_abPathIdx].p).c_str(), _abFailoverQueue.size()); log("link %s has failed, select link from failover queue (%zu links in queue)", pathToStr(_paths[_abPathIdx].p).c_str(), _abFailoverQueue.size());
if (! _abFailoverQueue.empty()) { if (! _abFailoverQueue.empty()) {
dequeueNextActiveBackupPath(now); dequeueNextActiveBackupPath(now);
@ -1474,16 +1610,29 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
if (prevActiveBackupPathIdx != _abPathIdx) { if (prevActiveBackupPathIdx != _abPathIdx) {
_lastActiveBackupPathChange = now; _lastActiveBackupPathChange = now;
} }
if (_abFailoverQueue.empty()) {
return; // No sense in continuing since there are no links to switch to
}
if (_abLinkSelectMethod == ZT_BOND_RESELECTION_POLICY_ALWAYS) { if (_abLinkSelectMethod == ZT_BOND_RESELECTION_POLICY_ALWAYS) {
if (_paths[_abPathIdx].p && ! getLink(_paths[_abPathIdx].p)->primary() && getLink(_paths[_abFailoverQueue.front()].p)->primary()) { SharedPtr<Link> abLink = getLink(_paths[_abPathIdx].p);
if (! _paths[_abFailoverQueue.front()].p) {
log("invalid link. not switching");
return;
}
SharedPtr<Link> abFailoverLink = getLink(_paths[_abFailoverQueue.front()].p);
if (abLink && ! abLink->primary() && _paths[_abFailoverQueue.front()].p && abFailoverLink && abFailoverLink->primary()) {
dequeueNextActiveBackupPath(now); dequeueNextActiveBackupPath(now);
log("switch back to available primary link %s (select mode: always)", pathToStr(_paths[_abPathIdx].p).c_str()); log("switch back to available primary link %s (select mode: always)", pathToStr(_paths[_abPathIdx].p).c_str());
} }
} }
if (_abLinkSelectMethod == ZT_BOND_RESELECTION_POLICY_BETTER) { if (_abLinkSelectMethod == ZT_BOND_RESELECTION_POLICY_BETTER) {
if (_paths[_abPathIdx].p && ! getLink(_paths[_abPathIdx].p)->primary()) { SharedPtr<Link> abLink = getLink(_paths[_abPathIdx].p);
if (abLink && ! abLink->primary()) {
// Active backup has switched to "better" primary link according to re-select policy. // Active backup has switched to "better" primary link according to re-select policy.
if (getLink(_paths[_abFailoverQueue.front()].p)->primary() && (_paths[_abFailoverQueue.front()].failoverScore > _paths[_abPathIdx].failoverScore)) { SharedPtr<Link> abFailoverLink = getLink(_paths[_abFailoverQueue.front()].p);
if (_paths[_abFailoverQueue.front()].p && abFailoverLink && abFailoverLink->primary() && (_paths[_abFailoverQueue.front()].failoverScore > _paths[_abPathIdx].failoverScore)) {
dequeueNextActiveBackupPath(now); dequeueNextActiveBackupPath(now);
log("switch back to user-defined primary link %s (select mode: better)", pathToStr(_paths[_abPathIdx].p).c_str()); log("switch back to user-defined primary link %s (select mode: better)", pathToStr(_paths[_abPathIdx].p).c_str());
} }
@ -1510,11 +1659,7 @@ void Bond::processActiveBackupTasks(void* tPtr, int64_t now)
if ((failoverScoreDifference > 0) && (failoverScoreDifference > thresholdQuantity)) { if ((failoverScoreDifference > 0) && (failoverScoreDifference > thresholdQuantity)) {
SharedPtr<Path> oldPath = _paths[_abPathIdx].p; SharedPtr<Path> oldPath = _paths[_abPathIdx].p;
dequeueNextActiveBackupPath(now); dequeueNextActiveBackupPath(now);
log("switch from %s (score: %d) to better link %s (score: %d) (select mode: optimize)", log("switch from %s (score: %d) to better link %s (score: %d) (select mode: optimize)", pathToStr(oldPath).c_str(), prevFScore, pathToStr(_paths[_abPathIdx].p).c_str(), newFScore);
pathToStr(oldPath).c_str(),
prevFScore,
pathToStr(_paths[_abPathIdx].p).c_str(),
newFScore);
} }
} }
} }
@ -1530,6 +1675,7 @@ void Bond::initTimers()
_lastPathNegotiationCheck = 0; _lastPathNegotiationCheck = 0;
_lastPathNegotiationReceived = 0; _lastPathNegotiationReceived = 0;
_lastQoSRateCheck = 0; _lastQoSRateCheck = 0;
_lastAckRateCheck = 0;
_lastQualityEstimation = 0; _lastQualityEstimation = 0;
_lastBondStatusLog = 0; _lastBondStatusLog = 0;
_lastSummaryDump = 0; _lastSummaryDump = 0;
@ -1562,10 +1708,6 @@ void Bond::setBondParameters(int policy, SharedPtr<Bond> templateBond, bool useT
_localUtility = 0; _localUtility = 0;
_negotiatedPathIdx = 0; _negotiatedPathIdx = 0;
// QOS Verb (and related checks)
_qosCutoffCount = 0;
// User preferences which may override the default bonding algorithm's behavior // User preferences which may override the default bonding algorithm's behavior
_userHasSpecifiedPrimaryLink = false; _userHasSpecifiedPrimaryLink = false;
@ -1574,7 +1716,6 @@ void Bond::setBondParameters(int policy, SharedPtr<Bond> templateBond, bool useT
// Bond status // Bond status
_isHealthy = false;
_numAliveLinks = 0; _numAliveLinks = 0;
_numTotalLinks = 0; _numTotalLinks = 0;
_numBondedPaths = 0; _numBondedPaths = 0;
@ -1659,7 +1800,9 @@ void Bond::setBondParameters(int policy, SharedPtr<Bond> templateBond, bool useT
_monitorInterval = _failoverInterval / ZT_BOND_ECHOS_PER_FAILOVER_INTERVAL; _monitorInterval = _failoverInterval / ZT_BOND_ECHOS_PER_FAILOVER_INTERVAL;
_qualityEstimationInterval = _failoverInterval * 2; _qualityEstimationInterval = _failoverInterval * 2;
_qosSendInterval = _failoverInterval * 2; _qosSendInterval = _failoverInterval * 2;
_ackSendInterval = _failoverInterval * 2;
_qosCutoffCount = 0; _qosCutoffCount = 0;
_ackCutoffCount = 0;
_defaultPathRefractoryPeriod = 8000; _defaultPathRefractoryPeriod = 8000;
} }
@ -1678,17 +1821,24 @@ void Bond::setUserQualityWeights(float weights[], int len)
SharedPtr<Link> Bond::getLink(const SharedPtr<Path>& path) SharedPtr<Link> Bond::getLink(const SharedPtr<Path>& path)
{ {
return RR->bc->getLinkBySocket(_policyAlias, path->localSocket()); return ! path ? SharedPtr<Link>() : RR->bc->getLinkBySocket(_policyAlias, path->localSocket());
} }
std::string Bond::pathToStr(const SharedPtr<Path>& path) std::string Bond::pathToStr(const SharedPtr<Path>& path)
{ {
#ifdef ZT_TRACE #ifdef ZT_TRACE
if (path) {
char pathStr[64] = { 0 }; char pathStr[64] = { 0 };
char fullPathStr[384] = { 0 }; char fullPathStr[384] = { 0 };
path->address().toString(pathStr); path->address().toString(pathStr);
snprintf(fullPathStr, 384, "%.16llx-%s/%s", (unsigned long long)(path->localSocket()), getLink(path)->ifname().c_str(), pathStr); SharedPtr<Link> link = getLink(path);
if (link) {
std::string ifnameStr = std::string(link->ifname());
snprintf(fullPathStr, 384, "%.16llx-%s/%s", (unsigned long long)(path->localSocket()), ifnameStr.c_str(), pathStr);
return std::string(fullPathStr); return std::string(fullPathStr);
}
}
return "";
#else #else
return ""; return "";
#endif #endif
@ -1700,11 +1850,11 @@ void Bond::dumpPathStatus(int64_t now, int pathIdx)
std::string aliveOrDead = _paths[pathIdx].alive ? std::string("alive") : std::string("dead"); std::string aliveOrDead = _paths[pathIdx].alive ? std::string("alive") : std::string("dead");
std::string eligibleOrNot = _paths[pathIdx].eligible ? std::string("eligible") : std::string("ineligible"); std::string eligibleOrNot = _paths[pathIdx].eligible ? std::string("eligible") : std::string("ineligible");
std::string bondedOrNot = _paths[pathIdx].bonded ? std::string("bonded") : std::string("unbonded"); std::string bondedOrNot = _paths[pathIdx].bonded ? std::string("bonded") : std::string("unbonded");
log("path[%2d] --- %5s (in %7d, out: %7d), %10s, %8s, flows=%-6d lat=%-8.3f pdv=%-7.3f err=%-6.4f loss=%-6.4f alloc=%-3d --- (%s)", log("path[%2u] --- %5s (in %7lld, out: %7lld), %10s, %8s, flows=%-6u lat=%-8.3f pdv=%-7.3f err=%-6.4f loss=%-6.4f alloc=%-3u --- (%s)",
pathIdx, pathIdx,
aliveOrDead.c_str(), aliveOrDead.c_str(),
_paths[pathIdx].p->age(now), static_cast<long long int>(_paths[pathIdx].p->age(now)),
(now - _paths[pathIdx].p->_lastOut), static_cast<long long int>(_paths[pathIdx].p->_lastOut == 0 ? 0 : now - _paths[pathIdx].p->_lastOut),
eligibleOrNot.c_str(), eligibleOrNot.c_str(),
bondedOrNot.c_str(), bondedOrNot.c_str(),
_paths[pathIdx].assignedFlowCount, _paths[pathIdx].assignedFlowCount,
@ -1727,7 +1877,7 @@ void Bond::dumpInfo(int64_t now, bool force)
_lastSummaryDump = now; _lastSummaryDump = now;
float overhead = (_overheadBytes / (timeSinceLastDump / 1000.0f) / 1000.0f); float overhead = (_overheadBytes / (timeSinceLastDump / 1000.0f) / 1000.0f);
_overheadBytes = 0; _overheadBytes = 0;
log("bond: bp=%d, fi=%d, mi=%d, ud=%d, dd=%d, flows=%lu, leaf=%d, overhead=%f KB/s", log("bond: bp=%d, fi=%d, mi=%d, ud=%d, dd=%d, flows=%lu, leaf=%d, overhead=%f KB/s, links=(%d/%d)",
_policy, _policy,
_failoverInterval, _failoverInterval,
_monitorInterval, _monitorInterval,
@ -1735,7 +1885,9 @@ void Bond::dumpInfo(int64_t now, bool force)
_downDelay, _downDelay,
(unsigned long)_flows.size(), (unsigned long)_flows.size(),
_isLeaf, _isLeaf,
overhead); overhead,
_numAliveLinks,
_numTotalLinks);
for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) { for (int i = 0; i < ZT_MAX_PEER_NETWORK_PATHS; ++i) {
if (_paths[i].p) { if (_paths[i].p) {
dumpPathStatus(now, i); dumpPathStatus(now, i);

View file

@ -436,7 +436,14 @@ class Bond {
* @param peer Remote peer that this bond services * @param peer Remote peer that this bond services
* @return A pointer to the newly created Bond * @return A pointer to the newly created Bond
*/ */
static SharedPtr<Bond> createTransportTriggeredBond(const RuntimeEnvironment* renv, const SharedPtr<Peer>& peer); static SharedPtr<Bond> createBond(const RuntimeEnvironment* renv, const SharedPtr<Peer>& peer);
/**
* Remove a bond from the bond controller.
*
* @param peerId Remote peer that this bond services
*/
static void destroyBond(uint64_t peerId);
/** /**
* Periodically perform maintenance tasks for the bonding layer. * Periodically perform maintenance tasks for the bonding layer.
@ -451,9 +458,10 @@ class Bond {
* *
* @param policyAlias Policy in use * @param policyAlias Policy in use
* @param localSocket Local source socket * @param localSocket Local source socket
* @param createIfNeeded Whether a Link object is created if the name wasn't previously in the link map
* @return Physical link definition * @return Physical link definition
*/ */
static SharedPtr<Link> getLinkBySocket(const std::string& policyAlias, uint64_t localSocket); static SharedPtr<Link> getLinkBySocket(const std::string& policyAlias, uint64_t localSocket, bool createIfNeeded);
/** /**
* Gets a reference to a physical link definition given its human-readable system name. * Gets a reference to a physical link definition given its human-readable system name.
@ -630,6 +638,15 @@ class Bond {
*/ */
void receivedQoS(const SharedPtr<Path>& path, int64_t now, int count, uint64_t* rx_id, uint16_t* rx_ts); void receivedQoS(const SharedPtr<Path>& path, int64_t now, int count, uint64_t* rx_id, uint16_t* rx_ts);
/**
* Process the contents of an inbound VERB_ACK to gather path quality observations.
*
* @param pathIdx Path over which packet was received
* @param now Current time
* @param ackedBytes Number of bytes ACKed by this VERB_ACK
*/
void receivedAck(int pathIdx, int64_t now, int32_t ackedBytes);
/** /**
* Generate the contents of a VERB_QOS_MEASUREMENT packet. * Generate the contents of a VERB_QOS_MEASUREMENT packet.
* *
@ -871,6 +888,26 @@ class Bond {
*/ */
void processBackgroundBondTasks(void* tPtr, int64_t now); void processBackgroundBondTasks(void* tPtr, int64_t now);
/**
* Rate limit gate for VERB_ACK
*
* @param now Current time
* @return Whether the incoming packet should be rate-gated
*/
inline bool rateGateACK(const int64_t now)
{
_ackCutoffCount++;
int numToDrain = _lastAckRateCheck ? (now - _lastAckRateCheck) / ZT_ACK_DRAINAGE_DIVISOR : _ackCutoffCount;
_lastAckRateCheck = now;
if (_ackCutoffCount > numToDrain) {
_ackCutoffCount -= numToDrain;
}
else {
_ackCutoffCount = 0;
}
return (_ackCutoffCount < ZT_ACK_CUTOFF_LIMIT);
}
/** /**
* Rate limit gate for VERB_QOS_MEASUREMENT * Rate limit gate for VERB_QOS_MEASUREMENT
* *
@ -1020,14 +1057,6 @@ class Bond {
return _policy; return _policy;
} }
/**
* @return the health status of the bond
*/
inline bool isHealthy()
{
return _isHealthy;
}
/** /**
* @return the number of links comprising this bond which are considered alive * @return the number of links comprising this bond which are considered alive
*/ */
@ -1142,6 +1171,9 @@ class Bond {
* *
*/ */
void log(const char* fmt, ...) void log(const char* fmt, ...)
#ifdef __GNUC__
__attribute__((format(printf, 2, 3)))
#endif
{ {
#ifdef ZT_TRACE #ifdef ZT_TRACE
time_t rawtime; time_t rawtime;
@ -1171,6 +1203,9 @@ class Bond {
* *
*/ */
void debug(const char* fmt, ...) void debug(const char* fmt, ...)
#ifdef __GNUC__
__attribute__((format(printf, 2, 3)))
#endif
{ {
#ifdef ZT_DEBUG #ifdef ZT_DEBUG
time_t rawtime; time_t rawtime;
@ -1198,7 +1233,11 @@ class Bond {
private: private:
struct NominatedPath { struct NominatedPath {
NominatedPath() NominatedPath()
: lastQoSMeasurement(0) : lastAckSent(0)
, lastAckReceived(0)
, unackedBytes(0)
, packetsReceivedSinceLastAck(0)
, lastQoSMeasurement(0)
, lastThroughputEstimation(0) , lastThroughputEstimation(0)
, lastRefractoryUpdate(0) , lastRefractoryUpdate(0)
, lastAliveToggle(0) , lastAliveToggle(0)
@ -1289,6 +1328,15 @@ class Bond {
return ((packetsReceivedSinceLastQoS >= ZT_QOS_TABLE_SIZE) || ((now - lastQoSMeasurement) > qosSendInterval)) && packetsReceivedSinceLastQoS; return ((packetsReceivedSinceLastQoS >= ZT_QOS_TABLE_SIZE) || ((now - lastQoSMeasurement) > qosSendInterval)) && packetsReceivedSinceLastQoS;
} }
/**
* @param now Current time
* @return Whether an ACK (VERB_ACK) packet needs to be emitted at this time
*/
inline bool needsToSendAck(int64_t now, int ackSendInterval)
{
return ((now - lastAckSent) >= ackSendInterval || (packetsReceivedSinceLastAck == ZT_QOS_TABLE_SIZE)) && packetsReceivedSinceLastAck;
}
/** /**
* Reset packet counters * Reset packet counters
*/ */
@ -1300,6 +1348,7 @@ class Bond {
std::map<uint64_t, uint64_t> qosStatsOut; // id:egress_time std::map<uint64_t, uint64_t> qosStatsOut; // id:egress_time
std::map<uint64_t, uint64_t> qosStatsIn; // id:now std::map<uint64_t, uint64_t> qosStatsIn; // id:now
std::map<uint64_t, uint64_t> ackStatsIn; // id:now
RingBuffer<int, ZT_QOS_SHORTTERM_SAMPLE_WIN_SIZE> qosRecordSize; RingBuffer<int, ZT_QOS_SHORTTERM_SAMPLE_WIN_SIZE> qosRecordSize;
RingBuffer<float, ZT_QOS_SHORTTERM_SAMPLE_WIN_SIZE> qosRecordLossSamples; RingBuffer<float, ZT_QOS_SHORTTERM_SAMPLE_WIN_SIZE> qosRecordLossSamples;
@ -1308,6 +1357,11 @@ class Bond {
RingBuffer<float, ZT_QOS_SHORTTERM_SAMPLE_WIN_SIZE> throughputVarianceSamples; RingBuffer<float, ZT_QOS_SHORTTERM_SAMPLE_WIN_SIZE> throughputVarianceSamples;
RingBuffer<uint16_t, ZT_QOS_SHORTTERM_SAMPLE_WIN_SIZE> latencySamples; RingBuffer<uint16_t, ZT_QOS_SHORTTERM_SAMPLE_WIN_SIZE> latencySamples;
uint64_t lastAckSent;
uint64_t lastAckReceived;
uint64_t unackedBytes;
uint64_t packetsReceivedSinceLastAck;
uint64_t lastQoSMeasurement; // Last time that a VERB_QOS_MEASUREMENT was sent out on this path. uint64_t lastQoSMeasurement; // Last time that a VERB_QOS_MEASUREMENT was sent out on this path.
uint64_t lastThroughputEstimation; // Last time that the path's throughput was estimated. uint64_t lastThroughputEstimation; // Last time that the path's throughput was estimated.
uint64_t lastRefractoryUpdate; // The last time that the refractory period was updated. uint64_t lastRefractoryUpdate; // The last time that the refractory period was updated.
@ -1344,7 +1398,7 @@ class Bond {
int packetsIn; int packetsIn;
int packetsOut; int packetsOut;
AtomicCounter __refCount; // AtomicCounter __refCount;
SharedPtr<Path> p; SharedPtr<Path> p;
void set(uint64_t now, const SharedPtr<Path>& path) void set(uint64_t now, const SharedPtr<Path>& path)
@ -1490,7 +1544,6 @@ class Bond {
/** /**
* Link state reporting * Link state reporting
*/ */
bool _isHealthy;
uint8_t _numAliveLinks; uint8_t _numAliveLinks;
uint8_t _numTotalLinks; uint8_t _numTotalLinks;
@ -1508,7 +1561,9 @@ class Bond {
* Rate-limiting * Rate-limiting
*/ */
uint16_t _qosCutoffCount; uint16_t _qosCutoffCount;
uint16_t _ackCutoffCount;
uint64_t _lastQoSRateCheck; uint64_t _lastQoSRateCheck;
uint64_t _lastAckRateCheck;
uint16_t _pathNegotiationCutoffCount; uint16_t _pathNegotiationCutoffCount;
uint64_t _lastPathNegotiationReceived; uint64_t _lastPathNegotiationReceived;

View file

@ -50,16 +50,17 @@
#define __UNIX_LIKE__ #define __UNIX_LIKE__
#endif #endif
#include <endian.h> #include <endian.h>
#if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64) || defined(__aarch64__)) #if (defined(__amd64) || defined(__amd64__) || defined(__x86_64) || defined(__x86_64__) || defined(__AMD64) || defined(__AMD64__) || defined(_M_X64) || defined(__aarch64__))
#define OIDC_SUPPORTED 1 #ifdef ZT_SSO_SUPPORTED
#else #define ZT_SSO_ENABLED 1
#define OIDC_SUPPORTED 0 #endif
#endif #endif
#endif #endif
#ifdef __APPLE__ #ifdef __APPLE__
#define OIDC_SUPPORTED 1 #ifdef ZT_SSO_SUPPORTED
#define ZT_SSO_ENABLED 1
#endif
#define likely(x) __builtin_expect((x),1) #define likely(x) __builtin_expect((x),1)
#define unlikely(x) __builtin_expect((x),0) #define unlikely(x) __builtin_expect((x),0)
#include <TargetConditionals.h> #include <TargetConditionals.h>
@ -73,7 +74,9 @@
#endif #endif
#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) #if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
#define OIDC_SUPPORTED 0 #ifdef ZT_SSO_SUPPORTED
#define ZT_SSO_ENABLED 0
#endif
#ifndef __UNIX_LIKE__ #ifndef __UNIX_LIKE__
#define __UNIX_LIKE__ #define __UNIX_LIKE__
#endif #endif
@ -89,7 +92,9 @@
#endif #endif
#if defined(_WIN32) || defined(_WIN64) #if defined(_WIN32) || defined(_WIN64)
#define OIDC_SUPPORTED 1 #ifdef ZT_SSO_SUPPORTED
#define ZT_SSO_ENABLED 1
#endif
#ifndef __WINDOWS__ #ifndef __WINDOWS__
#define __WINDOWS__ #define __WINDOWS__
#endif #endif
@ -368,9 +373,14 @@
#define ZT_QOS_TABLE_SIZE ((ZT_QOS_MAX_PACKET_SIZE * 8) / (64 + 16)) #define ZT_QOS_TABLE_SIZE ((ZT_QOS_MAX_PACKET_SIZE * 8) / (64 + 16))
/** /**
* Maximum number of outgoing packets we monitor for QoS information * Maximum number of packets we monitor for ACK information at any given time
*/ */
#define ZT_QOS_MAX_OUTSTANDING_RECORDS (1024 * 16) #define ZT_ACK_MAX_PENDING_RECORDS (32 * 1024)
/**
* Maximum number of packets we monitor for QoS information at any given time
*/
#define ZT_QOS_MAX_PENDING_RECORDS (ZT_QOS_TABLE_SIZE * 3)
/** /**
* Interval used for rate-limiting the computation of path quality estimates. * Interval used for rate-limiting the computation of path quality estimates.
@ -525,14 +535,14 @@
#define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 8 #define ZT_PUSH_DIRECT_PATHS_MAX_PER_SCOPE_AND_FAMILY 8
/** /**
* Time horizon for VERB_NETWORK_CREDENTIALS cutoff * Rate limit for network credential pushes from peer.
*/ */
#define ZT_PEER_CREDENTIALS_CUTOFF_TIME 60000 #define ZT_PEER_CREDENTIALS_RATE_LIMIT 1000
/** /**
* Maximum number of VERB_NETWORK_CREDENTIALS within cutoff time * Rate limit for responding to peer credential requests
*/ */
#define ZT_PEER_CREDENTIALS_CUTOFF_LIMIT 15 #define ZT_PEER_CREDENTIALS_REQUEST_RATE_LIMIT 1000
/** /**
* WHOIS rate limit (we allow these to be pretty fast) * WHOIS rate limit (we allow these to be pretty fast)
@ -571,13 +581,13 @@
* Anything below this value gets into thrashing territory since we divide * Anything below this value gets into thrashing territory since we divide
* this value by ZT_BOND_ECHOS_PER_FAILOVER_INTERVAL to send ECHOs often. * this value by ZT_BOND_ECHOS_PER_FAILOVER_INTERVAL to send ECHOs often.
*/ */
#define ZT_BOND_FAILOVER_MIN_INTERVAL 250 #define ZT_BOND_FAILOVER_MIN_INTERVAL 500
/** /**
* How many times per failover interval that an ECHO is sent. This should be * How many times per failover interval that an ECHO is sent. This should be
* at least 2. Anything more then 4 starts to increase overhead significantly. * at least 2. Anything more then 4 starts to increase overhead significantly.
*/ */
#define ZT_BOND_ECHOS_PER_FAILOVER_INTERVAL 4 #define ZT_BOND_ECHOS_PER_FAILOVER_INTERVAL 3
/** /**
* A defensive timer to prevent path quality metrics from being * A defensive timer to prevent path quality metrics from being

View file

@ -47,14 +47,13 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr,int32_t f
try { try {
// Check for trusted paths or unencrypted HELLOs (HELLO is the only packet sent in the clear) // Check for trusted paths or unencrypted HELLOs (HELLO is the only packet sent in the clear)
const unsigned int c = cipher(); const unsigned int c = cipher();
bool trusted = false;
if (c == ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH) { if (c == ZT_PROTO_CIPHER_SUITE__NO_CRYPTO_TRUSTED_PATH) {
// If this is marked as a packet via a trusted path, check source address and path ID. // If this is marked as a packet via a trusted path, check source address and path ID.
// Obviously if no trusted paths are configured this always returns false and such // Obviously if no trusted paths are configured this always returns false and such
// packets are dropped on the floor. // packets are dropped on the floor.
const uint64_t tpid = trustedPathId(); const uint64_t tpid = trustedPathId();
if (RR->topology->shouldInboundPathBeTrusted(_path->address(),tpid)) { if (RR->topology->shouldInboundPathBeTrusted(_path->address(),tpid)) {
trusted = true; _authenticated = true;
} else { } else {
RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops(),"path not trusted"); RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops(),"path not trusted");
return true; return true;
@ -66,7 +65,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr,int32_t f
const SharedPtr<Peer> peer(RR->topology->getPeer(tPtr,sourceAddress)); const SharedPtr<Peer> peer(RR->topology->getPeer(tPtr,sourceAddress));
if (peer) { if (peer) {
if (!trusted) { if (!_authenticated) {
if (!dearmor(peer->key(), peer->aesKeys())) { if (!dearmor(peer->key(), peer->aesKeys())) {
RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops(),"invalid MAC"); RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,packetId(),sourceAddress,hops(),"invalid MAC");
peer->recordIncomingInvalidPacket(_path); peer->recordIncomingInvalidPacket(_path);
@ -79,6 +78,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr,int32_t f
return true; return true;
} }
_authenticated = true;
const Packet::Verb v = verb(); const Packet::Verb v = verb();
bool r = true; bool r = true;
@ -88,6 +88,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr,int32_t f
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),v,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW); peer->received(tPtr,_path,hops(),packetId(),payloadLength(),v,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW);
break; break;
case Packet::VERB_HELLO: r = _doHELLO(RR,tPtr,true); break; case Packet::VERB_HELLO: r = _doHELLO(RR,tPtr,true); break;
case Packet::VERB_ACK : r = _doACK(RR,tPtr,peer); break;
case Packet::VERB_QOS_MEASUREMENT: r = _doQOS_MEASUREMENT(RR,tPtr,peer); break; case Packet::VERB_QOS_MEASUREMENT: r = _doQOS_MEASUREMENT(RR,tPtr,peer); break;
case Packet::VERB_ERROR: r = _doERROR(RR,tPtr,peer); break; case Packet::VERB_ERROR: r = _doERROR(RR,tPtr,peer); break;
case Packet::VERB_OK: r = _doOK(RR,tPtr,peer); break; case Packet::VERB_OK: r = _doOK(RR,tPtr,peer); break;
@ -169,7 +170,7 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
const SharedPtr<Network> network(RR->node->network(networkId)); const SharedPtr<Network> network(RR->node->network(networkId));
const int64_t now = RR->node->now(); const int64_t now = RR->node->now();
if ((network)&&(network->config().com)) if ((network)&&(network->config().com))
network->pushCredentialsNow(tPtr,peer->address(),now); network->peerRequestedCredentials(tPtr,peer->address(),now);
} break; } break;
case Packet::ERROR_NETWORK_ACCESS_DENIED_: { case Packet::ERROR_NETWORK_ACCESS_DENIED_: {
@ -250,6 +251,25 @@ bool IncomingPacket::_doERROR(const RuntimeEnvironment *RR,void *tPtr,const Shar
return true; return true;
} }
bool IncomingPacket::_doACK(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer)
{
/*
SharedPtr<Bond> bond = peer->bond();
if (! bond || ! bond->rateGateACK(RR->node->now())) {
return true;
}
int32_t ackedBytes;
if (payloadLength() != sizeof(ackedBytes)) {
return true; // ignore
}
memcpy(&ackedBytes, payload(), sizeof(ackedBytes));
if (bond) {
bond->receivedAck(_path, RR->node->now(), Utils::ntoh(ackedBytes));
}
*/
return true;
}
bool IncomingPacket::_doQOS_MEASUREMENT(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer) bool IncomingPacket::_doQOS_MEASUREMENT(const RuntimeEnvironment* RR, void* tPtr, const SharedPtr<Peer>& peer)
{ {
SharedPtr<Bond> bond = peer->bond(); SharedPtr<Bond> bond = peer->bond();
@ -860,7 +880,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const
bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer) bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer)
{ {
uint64_t now = RR->node->now(); uint64_t now = RR->node->now();
if (!peer->rateGateEchoRequest(now)) { if (!_path->rateGateEchoRequest(now)) {
return true; return true;
} }
@ -1057,10 +1077,8 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,c
{ {
const SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PACKET_IDX_PAYLOAD))); const SharedPtr<Network> network(RR->node->network(at<uint64_t>(ZT_PACKET_IDX_PAYLOAD)));
if (network) { if (network) {
//fprintf(stderr, "IncomingPacket::_doNETWORK_CONFIG %.16llx\n", network->id());
const uint64_t configUpdateId = network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PACKET_IDX_PAYLOAD); const uint64_t configUpdateId = network->handleConfigChunk(tPtr,packetId(),source(),*this,ZT_PACKET_IDX_PAYLOAD);
if (configUpdateId) { if (configUpdateId) {
//fprintf(stderr, "Have config update ID: %llu\n", configUpdateId);
Packet outp(peer->address(), RR->identity.address(), Packet::VERB_OK); Packet outp(peer->address(), RR->identity.address(), Packet::VERB_OK);
outp.append((uint8_t)Packet::VERB_ECHO); outp.append((uint8_t)Packet::VERB_ECHO);
outp.append((uint64_t)packetId()); outp.append((uint64_t)packetId());
@ -1069,9 +1087,7 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,c
const int64_t now = RR->node->now(); const int64_t now = RR->node->now();
outp.armor(peer->key(),true,peer->aesKeysIfSupported()); outp.armor(peer->key(),true,peer->aesKeysIfSupported());
peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now);
if (!_path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now())) { _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now());
//fprintf(stderr, "Error sending VERB_OK after NETWORK_CONFIG packet for %.16llx\n", network->id());
}
} }
} }
@ -1098,16 +1114,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr
} catch ( ... ) {} // discard invalid COMs } catch ( ... ) {} // discard invalid COMs
} }
bool trustEstablished = false; const bool trustEstablished = (network) ? network->gate(tPtr,peer) : false;
if (network) {
if (network->gate(tPtr,peer)) {
trustEstablished = true;
} else {
_sendErrorNeedCredentials(RR,tPtr,peer,nwid);
return false;
}
}
const int64_t now = RR->node->now(); const int64_t now = RR->node->now();
if ((gatherLimit > 0)&&((trustEstablished)||(RR->topology->amUpstream())||(RR->node->localControllerHasAuthorized(now,nwid,peer->address())))) { if ((gatherLimit > 0)&&((trustEstablished)||(RR->topology->amUpstream())||(RR->node->localControllerHasAuthorized(now,nwid,peer->address())))) {
Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK); Packet outp(peer->address(),RR->identity.address(),Packet::VERB_OK);
@ -1224,9 +1231,6 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr,
} }
peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid,ZT_QOS_NO_FLOW); peer->received(tPtr,_path,hops(),packetId(),payloadLength(),Packet::VERB_MULTICAST_FRAME,0,Packet::VERB_NOP,true,nwid,ZT_QOS_NO_FLOW);
} else {
_sendErrorNeedCredentials(RR,tPtr,peer,nwid);
return false;
} }
return true; return true;

View file

@ -51,7 +51,9 @@ class IncomingPacket : public Packet
public: public:
IncomingPacket() : IncomingPacket() :
Packet(), Packet(),
_receiveTime(0) _receiveTime(0),
_path(),
_authenticated(false)
{ {
} }
@ -67,7 +69,8 @@ public:
IncomingPacket(const void *data,unsigned int len,const SharedPtr<Path> &path,int64_t now) : IncomingPacket(const void *data,unsigned int len,const SharedPtr<Path> &path,int64_t now) :
Packet(data,len), Packet(data,len),
_receiveTime(now), _receiveTime(now),
_path(path) _path(path),
_authenticated(false)
{ {
} }
@ -85,6 +88,7 @@ public:
copyFrom(data,len); copyFrom(data,len);
_receiveTime = now; _receiveTime = now;
_path = path; _path = path;
_authenticated = false;
} }
/** /**
@ -112,6 +116,7 @@ private:
// been authenticated, decrypted, decompressed, and classified. // been authenticated, decrypted, decompressed, and classified.
bool _doERROR(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doERROR(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated); bool _doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool alreadyAuthenticated);
bool _doACK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doQOS_MEASUREMENT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doQOS_MEASUREMENT(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
bool _doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer); bool _doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const SharedPtr<Peer> &peer);
@ -134,6 +139,7 @@ private:
uint64_t _receiveTime; uint64_t _receiveTime;
SharedPtr<Path> _path; SharedPtr<Path> _path;
bool _authenticated;
}; };
} // namespace ZeroTier } // namespace ZeroTier

View file

@ -115,7 +115,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
RR->t->credentialRejected(tPtr,com,"old"); RR->t->credentialRejected(tPtr,com,"old");
return ADD_REJECTED; return ADD_REJECTED;
} }
if ((newts == oldts)&&(_com == com)) if (_com == com)
return ADD_ACCEPTED_REDUNDANT; return ADD_ACCEPTED_REDUNDANT;
switch(com.verify(RR,tPtr)) { switch(com.verify(RR,tPtr)) {
@ -123,6 +123,7 @@ Membership::AddCredentialResult Membership::addCredential(const RuntimeEnvironme
RR->t->credentialRejected(tPtr,com,"invalid"); RR->t->credentialRejected(tPtr,com,"invalid");
return ADD_REJECTED; return ADD_REJECTED;
case 0: case 0:
//printf("%.16llx %.10llx replacing COM %lld with %lld\n", com.networkId(), com.issuedTo().toInt(), _com.timestamp(), com.timestamp()); fflush(stdout);
_com = com; _com = com;
return ADD_ACCEPTED_NEW; return ADD_ACCEPTED_NEW;
case 1: case 1:

View file

@ -64,13 +64,9 @@ public:
*/ */
void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf); void pushCredentials(const RuntimeEnvironment *RR,void *tPtr,const int64_t now,const Address &peerAddress,const NetworkConfig &nconf);
/** inline int64_t lastPushedCredentials() { return _lastPushedCredentials; }
* @return True if we haven't pushed credentials in a long time (to cause proactive credential push) inline int64_t comTimestamp() { return _com.timestamp(); }
*/ inline int64_t comRevocationThreshold() { return _comRevocationThreshold; }
inline bool shouldPushCredentials(const int64_t now) const
{
return ((now - _lastPushedCredentials) > ZT_PEER_ACTIVITY_TIMEOUT);
}
/** /**
* Check whether we should push MULTICAST_LIKEs to this peer, and update last sent time if true * Check whether we should push MULTICAST_LIKEs to this peer, and update last sent time if true
@ -96,9 +92,7 @@ public:
*/ */
inline bool isAllowedOnNetwork(const NetworkConfig &thisNodeNetworkConfig, const Identity &otherNodeIdentity) const inline bool isAllowedOnNetwork(const NetworkConfig &thisNodeNetworkConfig, const Identity &otherNodeIdentity) const
{ {
if (thisNodeNetworkConfig.isPublic()) return true; return thisNodeNetworkConfig.isPublic() || (((_com.timestamp() > _comRevocationThreshold) && (thisNodeNetworkConfig.com.agreesWith(_com, otherNodeIdentity))));
if (_com.timestamp() <= _comRevocationThreshold) return false;
return thisNodeNetworkConfig.com.agreesWith(_com, otherNodeIdentity);
} }
inline bool recentlyAssociated(const int64_t now) const inline bool recentlyAssociated(const int64_t now) const

View file

@ -1223,10 +1223,16 @@ void Network::requestConfiguration(void *tPtr)
bool Network::gate(void *tPtr,const SharedPtr<Peer> &peer) bool Network::gate(void *tPtr,const SharedPtr<Peer> &peer)
{ {
const int64_t now = RR->node->now(); const int64_t now = RR->node->now();
//int64_t comTimestamp = 0;
//int64_t comRevocationThreshold = 0;
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
try { try {
if (_config) { if (_config) {
Membership *m = _memberships.get(peer->address()); Membership *m = _memberships.get(peer->address());
//if (m) {
// comTimestamp = m->comTimestamp();
// comRevocationThreshold = m->comRevocationThreshold();
//}
if ( (_config.isPublic()) || ((m)&&(m->isAllowedOnNetwork(_config, peer->identity()))) ) { if ( (_config.isPublic()) || ((m)&&(m->isAllowedOnNetwork(_config, peer->identity()))) ) {
if (!m) if (!m)
m = &(_membership(peer->address())); m = &(_membership(peer->address()));
@ -1237,6 +1243,8 @@ bool Network::gate(void *tPtr,const SharedPtr<Peer> &peer)
} }
} }
} catch ( ... ) {} } catch ( ... ) {}
//printf("%.16llx %.10llx not allowed, COM ts %lld revocation %lld\n", _id, peer->address().toInt(), comTimestamp, comRevocationThreshold); fflush(stdout);
return false; return false;
} }

View file

@ -372,10 +372,13 @@ public:
* @param to Destination peer address * @param to Destination peer address
* @param now Current time * @param now Current time
*/ */
inline void pushCredentialsNow(void *tPtr,const Address &to,const int64_t now) inline void peerRequestedCredentials(void *tPtr,const Address &to,const int64_t now)
{ {
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
_membership(to).pushCredentials(RR,tPtr,now,to,_config); Membership &m = _membership(to);
const int64_t lastPushed = m.lastPushedCredentials();
if ((lastPushed < _lastConfigUpdate)||((now - lastPushed) > ZT_PEER_CREDENTIALS_REQUEST_RATE_LIMIT))
m.pushCredentials(RR,tPtr,now,to,_config);
} }
/** /**
@ -389,7 +392,8 @@ public:
{ {
Mutex::Lock _l(_lock); Mutex::Lock _l(_lock);
Membership &m = _membership(to); Membership &m = _membership(to);
if (m.shouldPushCredentials(now)) const int64_t lastPushed = m.lastPushedCredentials();
if ((lastPushed < _lastConfigUpdate)||((now - lastPushed) > ZT_PEER_ACTIVITY_TIMEOUT))
m.pushCredentials(RR,tPtr,now,to,_config); m.pushCredentials(RR,tPtr,now,to,_config);
} }
@ -439,7 +443,7 @@ private:
Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges) Hashtable< MAC,Address > _remoteBridgeRoutes; // remote addresses where given MACs are reachable (for tracking devices behind remote bridges)
NetworkConfig _config; NetworkConfig _config;
uint64_t _lastConfigUpdate; int64_t _lastConfigUpdate;
struct _IncomingConfigChunk struct _IncomingConfigChunk
{ {

View file

@ -41,20 +41,19 @@
#include "Trace.hpp" #include "Trace.hpp"
/** /**
* Default maximum time delta for COMs, tags, and capabilities * Default time delta for COMs, tags, and capabilities
*
* The current value is two hours, providing ample time for a controller to
* experience fail-over, etc.
*/ */
#define ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA 7200000ULL #define ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_DFL_MAX_DELTA ((int64_t)(1000 * 60 * 30))
/** /**
* Default minimum credential TTL and maxDelta for COM timestamps * Maximum time delta for COMs, tags, and capabilities
*
* This is just slightly over three minutes and provides three retries for
* all currently online members to refresh.
*/ */
#define ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA 185000ULL #define ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MAX_MAX_DELTA ((int64_t)(1000 * 60 * 60 * 2))
/**
* Minimum credential TTL and maxDelta for COM timestamps
*/
#define ZT_NETWORKCONFIG_DEFAULT_CREDENTIAL_TIME_MIN_MAX_DELTA ((int64_t)(1000 * 60 * 5))
/** /**
* Flag: enable broadcast * Flag: enable broadcast

View file

@ -509,7 +509,6 @@ ZT_PeerList *Node::peers() const
if (pi->second->bond()) { if (pi->second->bond()) {
p->isBonded = pi->second->bond(); p->isBonded = pi->second->bond();
p->bondingPolicy = pi->second->bond()->policy(); p->bondingPolicy = pi->second->bond()->policy();
p->isHealthy = pi->second->bond()->isHealthy();
p->numAliveLinks = pi->second->bond()->getNumAliveLinks(); p->numAliveLinks = pi->second->bond()->getNumAliveLinks();
p->numTotalLinks = pi->second->bond()->getNumTotalLinks(); p->numTotalLinks = pi->second->bond()->getNumTotalLinks();
} }
@ -741,7 +740,7 @@ void Node::ncSendError(uint64_t nwid,uint64_t requestPacketId,const Address &des
n->setAccessDenied(nullptr); n->setAccessDenied(nullptr);
break; break;
case NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED: { case NetworkController::NC_ERROR_AUTHENTICATION_REQUIRED: {
fprintf(stderr, "\n\nGot auth required\n\n"); //fprintf(stderr, "\n\nGot auth required\n\n");
break; break;
} }

View file

@ -83,6 +83,7 @@ public:
_lastOut(0), _lastOut(0),
_lastIn(0), _lastIn(0),
_lastTrustEstablishedPacketReceived(0), _lastTrustEstablishedPacketReceived(0),
_lastEchoRequestReceived(0),
_localSocket(-1), _localSocket(-1),
_latency(0xffff), _latency(0xffff),
_addr(), _addr(),
@ -93,6 +94,7 @@ public:
_lastOut(0), _lastOut(0),
_lastIn(0), _lastIn(0),
_lastTrustEstablishedPacketReceived(0), _lastTrustEstablishedPacketReceived(0),
_lastEchoRequestReceived(0),
_localSocket(localSocket), _localSocket(localSocket),
_latency(0xffff), _latency(0xffff),
_addr(addr), _addr(addr),
@ -266,6 +268,18 @@ public:
*/ */
inline int64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; } inline int64_t lastTrustEstablishedPacketReceived() const { return _lastTrustEstablishedPacketReceived; }
/**
* Rate limit gate for inbound ECHO requests
*/
inline bool rateGateEchoRequest(const int64_t now)
{
if ((now - _lastEchoRequestReceived) >= (ZT_PEER_GENERAL_RATE_LIMIT / 6)) {
_lastEchoRequestReceived = now;
return true;
}
return false;
}
void *_bondingMetricPtr; void *_bondingMetricPtr;
private: private:
@ -273,6 +287,9 @@ private:
volatile int64_t _lastOut; volatile int64_t _lastOut;
volatile int64_t _lastIn; volatile int64_t _lastIn;
volatile int64_t _lastTrustEstablishedPacketReceived; volatile int64_t _lastTrustEstablishedPacketReceived;
int64_t _lastEchoRequestReceived;
int64_t _localSocket; int64_t _localSocket;
volatile unsigned int _latency; volatile unsigned int _latency;
InetAddress _addr; InetAddress _addr;

View file

@ -34,7 +34,6 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
_lastTriedMemorizedPath(0), _lastTriedMemorizedPath(0),
_lastDirectPathPushSent(0), _lastDirectPathPushSent(0),
_lastDirectPathPushReceive(0), _lastDirectPathPushReceive(0),
_lastEchoRequestReceived(0),
_lastCredentialRequestSent(0), _lastCredentialRequestSent(0),
_lastWhoisRequestReceived(0), _lastWhoisRequestReceived(0),
_lastCredentialsReceived(0), _lastCredentialsReceived(0),
@ -48,7 +47,6 @@ Peer::Peer(const RuntimeEnvironment *renv,const Identity &myIdentity,const Ident
_vRevision(0), _vRevision(0),
_id(peerIdentity), _id(peerIdentity),
_directPathPushCutoffCount(0), _directPathPushCutoffCount(0),
_credentialsCutoffCount(0),
_echoRequestCutoffCount(0), _echoRequestCutoffCount(0),
_localMultipathSupported(false), _localMultipathSupported(false),
_lastComputedAggregateMeanLatency(0) _lastComputedAggregateMeanLatency(0)
@ -224,6 +222,8 @@ void Peer::received(
if (sinceLastPush >= ((hops == 0) ? ZT_DIRECT_PATH_PUSH_INTERVAL_HAVEPATH : ZT_DIRECT_PATH_PUSH_INTERVAL)) { if (sinceLastPush >= ((hops == 0) ? ZT_DIRECT_PATH_PUSH_INTERVAL_HAVEPATH : ZT_DIRECT_PATH_PUSH_INTERVAL)) {
_lastDirectPathPushSent = now; _lastDirectPathPushSent = now;
std::vector<InetAddress> pathsToPush(RR->node->directPaths()); std::vector<InetAddress> pathsToPush(RR->node->directPaths());
std::vector<InetAddress> ma = RR->sa->whoami();
pathsToPush.insert(pathsToPush.end(), ma.begin(), ma.end());
if (!pathsToPush.empty()) { if (!pathsToPush.empty()) {
std::vector<InetAddress>::const_iterator p(pathsToPush.begin()); std::vector<InetAddress>::const_iterator p(pathsToPush.begin());
while (p != pathsToPush.end()) { while (p != pathsToPush.end()) {
@ -453,7 +453,7 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA
if (atAddress) { if (atAddress) {
outp.armor(_key,false,nullptr); // false == don't encrypt full payload, but add MAC outp.armor(_key,false,nullptr); // false == don't encrypt full payload, but add MAC
RR->node->expectReplyTo(outp.packetId()); RR->node->expectReplyTo(outp.packetId());
RR->node->putPacket(tPtr,localSocket,atAddress,outp.data(),outp.size()); RR->node->putPacket(tPtr,-1,atAddress,outp.data(),outp.size());
} else { } else {
RR->node->expectReplyTo(outp.packetId()); RR->node->expectReplyTo(outp.packetId());
RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC
@ -502,7 +502,7 @@ void Peer::performMultipathStateCheck(void *tPtr, int64_t now)
_localMultipathSupported = ((numAlivePaths >= 1) && (RR->bc->inUse()) && (ZT_PROTO_VERSION > 9)); _localMultipathSupported = ((numAlivePaths >= 1) && (RR->bc->inUse()) && (ZT_PROTO_VERSION > 9));
if (_localMultipathSupported && !_bond) { if (_localMultipathSupported && !_bond) {
if (RR->bc) { if (RR->bc) {
_bond = RR->bc->createTransportTriggeredBond(RR, this); _bond = RR->bc->createBond(RR, this);
/** /**
* Allow new bond to retroactively learn all paths known to this peer * Allow new bond to retroactively learn all paths known to this peer
*/ */

View file

@ -53,7 +53,10 @@ private:
Peer() {} // disabled to prevent bugs -- should not be constructed uninitialized Peer() {} // disabled to prevent bugs -- should not be constructed uninitialized
public: public:
~Peer() { Utils::burn(_key,sizeof(_key)); } ~Peer() {
Utils::burn(_key,sizeof(_key));
RR->bc->destroyBond(_id.address().toInt());
}
/** /**
* Construct a new peer * Construct a new peer
@ -387,11 +390,11 @@ public:
*/ */
inline bool rateGateCredentialsReceived(const int64_t now) inline bool rateGateCredentialsReceived(const int64_t now)
{ {
if ((now - _lastCredentialsReceived) <= ZT_PEER_CREDENTIALS_CUTOFF_TIME) if ((now - _lastCredentialsReceived) >= ZT_PEER_CREDENTIALS_RATE_LIMIT) {
++_credentialsCutoffCount;
else _credentialsCutoffCount = 0;
_lastCredentialsReceived = now; _lastCredentialsReceived = now;
return (_credentialsCutoffCount < ZT_PEER_CREDENTIALS_CUTOFF_LIMIT); return true;
}
return false;
} }
/** /**
@ -418,18 +421,6 @@ public:
return false; return false;
} }
/**
* Rate limit gate for inbound ECHO requests
*/
inline bool rateGateEchoRequest(const int64_t now)
{
if ((now - _lastEchoRequestReceived) >= ZT_PEER_GENERAL_RATE_LIMIT) {
_lastEchoRequestReceived = now;
return true;
}
return false;
}
/** /**
* Serialize a peer for storage in local cache * Serialize a peer for storage in local cache
* *
@ -546,7 +537,6 @@ private:
int64_t _lastTriedMemorizedPath; int64_t _lastTriedMemorizedPath;
int64_t _lastDirectPathPushSent; int64_t _lastDirectPathPushSent;
int64_t _lastDirectPathPushReceive; int64_t _lastDirectPathPushReceive;
int64_t _lastEchoRequestReceived;
int64_t _lastCredentialRequestSent; int64_t _lastCredentialRequestSent;
int64_t _lastWhoisRequestReceived; int64_t _lastWhoisRequestReceived;
int64_t _lastCredentialsReceived; int64_t _lastCredentialsReceived;
@ -573,7 +563,6 @@ private:
Identity _id; Identity _id;
unsigned int _directPathPushCutoffCount; unsigned int _directPathPushCutoffCount;
unsigned int _credentialsCutoffCount;
unsigned int _echoRequestCutoffCount; unsigned int _echoRequestCutoffCount;
AtomicCounter __refCount; AtomicCounter __refCount;

View file

@ -67,7 +67,7 @@ public:
* @param tgt Target node whose credential(s) are being revoked * @param tgt Target node whose credential(s) are being revoked
* @param ct Credential type being revoked * @param ct Credential type being revoked
*/ */
Revocation(const uint32_t i,const uint64_t nwid,const uint32_t cid,const uint64_t thr,const uint64_t fl,const Address &tgt,const Credential::Type ct) : Revocation(const uint32_t i,const uint64_t nwid,const uint32_t cid,const int64_t thr,const uint64_t fl,const Address &tgt,const Credential::Type ct) :
_id(i), _id(i),
_credentialId(cid), _credentialId(cid),
_networkId(nwid), _networkId(nwid),
@ -155,7 +155,7 @@ public:
_networkId = b.template at<uint64_t>(p); p += 8; _networkId = b.template at<uint64_t>(p); p += 8;
p += 4; // 4 bytes, currently unused p += 4; // 4 bytes, currently unused
_credentialId = b.template at<uint32_t>(p); p += 4; _credentialId = b.template at<uint32_t>(p); p += 4;
_threshold = b.template at<uint64_t>(p); p += 8; _threshold = (int64_t)b.template at<uint64_t>(p); p += 8;
_flags = b.template at<uint64_t>(p); p += 8; _flags = b.template at<uint64_t>(p); p += 8;
_target.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; _target.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;
_signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH; _signedBy.setTo(b.field(p,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); p += ZT_ADDRESS_LENGTH;

View file

@ -15,7 +15,7 @@
#include "Constants.hpp" #include "Constants.hpp"
#include "Utils.hpp" #include "Utils.hpp"
#if (!defined(ZT_SALSA20_SSE)) && (defined(__SSE2__) || (defined(__WINDOWS__) && !defined(__MINGW32__))) #if (!defined(ZT_SALSA20_SSE)) && (defined(__SSE2__) || (defined(__WINDOWS__) && !defined(__MINGW32__) && !defined(_M_ARM64)))
#define ZT_SALSA20_SSE 1 #define ZT_SALSA20_SSE 1
#endif #endif

View file

@ -99,6 +99,21 @@ void SelfAwareness::iam(void *tPtr,const Address &reporter,const int64_t receive
} }
} }
std::vector<InetAddress> SelfAwareness::whoami()
{
std::vector<InetAddress> surfaceAddresses;
Mutex::Lock _l(_phy_m);
Hashtable< PhySurfaceKey,PhySurfaceEntry >::Iterator i(_phy);
PhySurfaceKey *k = (PhySurfaceKey *)0;
PhySurfaceEntry *e = (PhySurfaceEntry *)0;
while (i.next(k,e)) {
if (std::find(surfaceAddresses.begin(), surfaceAddresses.end(), e->mySurface) == surfaceAddresses.end()) {
surfaceAddresses.push_back(e->mySurface);
}
}
return surfaceAddresses;
}
void SelfAwareness::clean(int64_t now) void SelfAwareness::clean(int64_t now)
{ {
Mutex::Lock _l(_phy_m); Mutex::Lock _l(_phy_m);

View file

@ -44,6 +44,13 @@ public:
*/ */
void iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now); void iam(void *tPtr,const Address &reporter,const int64_t receivedOnLocalSocket,const InetAddress &reporterPhysicalAddress,const InetAddress &myPhysicalAddress,bool trusted,int64_t now);
/**
* Return all known external surface addresses reported by peers
*
* @return A vector of InetAddress(es)
*/
std::vector<InetAddress> whoami();
/** /**
* Clean up database periodically * Clean up database periodically
* *

40
one.cpp
View file

@ -88,7 +88,7 @@
#include "service/OneService.hpp" #include "service/OneService.hpp"
#include "ext/json/json.hpp" #include <nlohmann/json.hpp>
#ifdef __APPLE__ #ifdef __APPLE__
#include <SystemConfiguration/SystemConfiguration.h> #include <SystemConfiguration/SystemConfiguration.h>
@ -523,31 +523,23 @@ static int cli(int argc,char **argv)
printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str()); printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str());
} else { } else {
bool bFoundBond = false; bool bFoundBond = false;
printf(" <peer> <bondtype> <status> <links>" ZT_EOL_S); printf(" <peer> <bondtype> <links>" ZT_EOL_S);
if (j.is_array()) { if (j.is_array()) {
for(unsigned long k=0;k<j.size();++k) { for(unsigned long k=0;k<j.size();++k) {
nlohmann::json &p = j[k]; nlohmann::json &p = j[k];
bool isBonded = p["isBonded"]; bool isBonded = p["isBonded"];
if (isBonded) { if (isBonded) {
int8_t bondingPolicy = p["bondingPolicy"]; int8_t bondingPolicy = p["bondingPolicy"];
bool isHealthy = p["isHealthy"];
int8_t numAliveLinks = p["numAliveLinks"]; int8_t numAliveLinks = p["numAliveLinks"];
int8_t numTotalLinks = p["numTotalLinks"]; int8_t numTotalLinks = p["numTotalLinks"];
bFoundBond = true; bFoundBond = true;
std::string healthStr;
if (isHealthy) {
healthStr = "HEALTHY";
} else {
healthStr = "DEGRADED";
}
std::string policyStr = "none"; std::string policyStr = "none";
if (bondingPolicy >= ZT_BOND_POLICY_NONE && bondingPolicy <= ZT_BOND_POLICY_BALANCE_AWARE) { if (bondingPolicy >= ZT_BOND_POLICY_NONE && bondingPolicy <= ZT_BOND_POLICY_BALANCE_AWARE) {
policyStr = Bond::getPolicyStrByCode(bondingPolicy); policyStr = Bond::getPolicyStrByCode(bondingPolicy);
} }
printf("%10s %32s %8s %d/%d" ZT_EOL_S, printf("%10s %32s %d/%d" ZT_EOL_S,
OSUtils::jsonString(p ["address"],"-").c_str(), OSUtils::jsonString(p ["address"],"-").c_str(),
policyStr.c_str(), policyStr.c_str(),
healthStr.c_str(),
numAliveLinks, numAliveLinks,
numTotalLinks); numTotalLinks);
} }
@ -617,12 +609,6 @@ static int cli(int argc,char **argv)
if (json) { if (json) {
printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str()); printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str());
} else { } else {
std::string healthStr;
if (OSUtils::jsonInt(j["isHealthy"],0)) {
healthStr = "Healthy";
} else {
healthStr = "Degraded";
}
int numAliveLinks = OSUtils::jsonInt(j["numAliveLinks"],0); int numAliveLinks = OSUtils::jsonInt(j["numAliveLinks"],0);
int numTotalLinks = OSUtils::jsonInt(j["numTotalLinks"],0); int numTotalLinks = OSUtils::jsonInt(j["numTotalLinks"],0);
printf("Peer : %s\n", arg1.c_str()); printf("Peer : %s\n", arg1.c_str());
@ -630,7 +616,6 @@ static int cli(int argc,char **argv)
//if (bondingPolicy == ZT_BOND_POLICY_ACTIVE_BACKUP) { //if (bondingPolicy == ZT_BOND_POLICY_ACTIVE_BACKUP) {
printf("Link Select Method : %d\n", (int)OSUtils::jsonInt(j["linkSelectMethod"],0)); printf("Link Select Method : %d\n", (int)OSUtils::jsonInt(j["linkSelectMethod"],0));
//} //}
printf("Status : %s\n", healthStr.c_str());
printf("Links : %d/%d\n", numAliveLinks, numTotalLinks); printf("Links : %d/%d\n", numAliveLinks, numTotalLinks);
printf("Failover Interval : %d (ms)\n", (int)OSUtils::jsonInt(j["failoverInterval"],0)); printf("Failover Interval : %d (ms)\n", (int)OSUtils::jsonInt(j["failoverInterval"],0));
printf("Up Delay : %d (ms)\n", (int)OSUtils::jsonInt(j["upDelay"],0)); printf("Up Delay : %d (ms)\n", (int)OSUtils::jsonInt(j["upDelay"],0));
@ -705,33 +690,23 @@ static int cli(int argc,char **argv)
printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str()); printf("%s" ZT_EOL_S,OSUtils::jsonDump(j).c_str());
} else { } else {
bool bFoundBond = false; bool bFoundBond = false;
printf(" <peer> <bondtype> <status> <links>" ZT_EOL_S); printf(" <peer> <bondtype> <links>" ZT_EOL_S);
if (j.is_array()) { if (j.is_array()) {
for(unsigned long k=0;k<j.size();++k) { for(unsigned long k=0;k<j.size();++k) {
nlohmann::json &p = j[k]; nlohmann::json &p = j[k];
bool isBonded = p["isBonded"]; bool isBonded = p["isBonded"];
if (isBonded) { if (isBonded) {
int8_t bondingPolicy = p["bondingPolicy"]; int8_t bondingPolicy = p["bondingPolicy"];
bool isHealthy = p["isHealthy"];
int8_t numAliveLinks = p["numAliveLinks"]; int8_t numAliveLinks = p["numAliveLinks"];
int8_t numTotalLinks = p["numTotalLinks"]; int8_t numTotalLinks = p["numTotalLinks"];
bFoundBond = true; bFoundBond = true;
std::string healthStr;
if (isHealthy) {
healthStr = "Healthy";
} else {
healthStr = "Degraded";
}
std::string policyStr = "none"; std::string policyStr = "none";
if (bondingPolicy >= ZT_BOND_POLICY_NONE && bondingPolicy <= ZT_BOND_POLICY_BALANCE_AWARE) { if (bondingPolicy >= ZT_BOND_POLICY_NONE && bondingPolicy <= ZT_BOND_POLICY_BALANCE_AWARE) {
policyStr = Bond::getPolicyStrByCode(bondingPolicy); policyStr = Bond::getPolicyStrByCode(bondingPolicy);
} }
printf("%10s %32s %d/%d" ZT_EOL_S,
printf("%10s %32s %8s %d/%d" ZT_EOL_S,
OSUtils::jsonString(p["address"],"-").c_str(), OSUtils::jsonString(p["address"],"-").c_str(),
policyStr.c_str(), policyStr.c_str(),
healthStr.c_str(),
numAliveLinks, numAliveLinks,
numTotalLinks); numTotalLinks);
} }
@ -800,7 +775,10 @@ static int cli(int argc,char **argv)
if (status == "AUTHENTICATION_REQUIRED") { if (status == "AUTHENTICATION_REQUIRED") {
printf(" AUTH EXPIRED, URL: %s" ZT_EOL_S, OSUtils::jsonString(n["authenticationURL"], "(null)").c_str()); printf(" AUTH EXPIRED, URL: %s" ZT_EOL_S, OSUtils::jsonString(n["authenticationURL"], "(null)").c_str());
} else if (status == "OK") { } else if (status == "OK") {
printf(" AUTH OK, expires in: %lld seconds" ZT_EOL_S, ((int64_t)authenticationExpiryTime - OSUtils::now()) / 1000LL); int64_t expiresIn = ((int64_t)authenticationExpiryTime - OSUtils::now()) / 1000LL;
if (expiresIn >= 0) {
printf(" AUTH OK, expires in: %lld seconds" ZT_EOL_S, expiresIn);
}
} }
} }
} }

View file

@ -40,7 +40,7 @@
#endif #endif
#endif #endif
#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) #if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK)
#include <net/if.h> #include <net/if.h>
#include <netinet6/in6_var.h> #include <netinet6/in6_var.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
@ -311,7 +311,7 @@ class Binder {
if (! gotViaProc) { if (! gotViaProc) {
struct ifaddrs* ifatbl = (struct ifaddrs*)0; struct ifaddrs* ifatbl = (struct ifaddrs*)0;
struct ifaddrs* ifa; struct ifaddrs* ifa;
#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) #if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK)
// set up an IPv6 socket so we can check the state of interfaces via SIOCGIFAFLAG_IN6 // set up an IPv6 socket so we can check the state of interfaces via SIOCGIFAFLAG_IN6
int infoSock = socket(AF_INET6, SOCK_DGRAM, 0); int infoSock = socket(AF_INET6, SOCK_DGRAM, 0);
#endif #endif
@ -320,7 +320,7 @@ class Binder {
while (ifa) { while (ifa) {
if ((ifa->ifa_name) && (ifa->ifa_addr)) { if ((ifa->ifa_name) && (ifa->ifa_addr)) {
InetAddress ip = *(ifa->ifa_addr); InetAddress ip = *(ifa->ifa_addr);
#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) #if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK)
// Check if the address is an IPv6 Temporary Address, macOS/BSD version // Check if the address is an IPv6 Temporary Address, macOS/BSD version
if (ifa->ifa_addr->sa_family == AF_INET6) { if (ifa->ifa_addr->sa_family == AF_INET6) {
struct sockaddr_in6* sa6 = (struct sockaddr_in6*)ifa->ifa_addr; struct sockaddr_in6* sa6 = (struct sockaddr_in6*)ifa->ifa_addr;
@ -368,7 +368,7 @@ class Binder {
else { else {
interfacesEnumerated = false; interfacesEnumerated = false;
} }
#if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) #if (defined(__unix__) || defined(__APPLE__)) && !defined(__LINUX__) && !defined(ZT_SDK)
close(infoSock); close(infoSock);
#endif #endif
} }

View file

@ -43,7 +43,7 @@
#endif #endif
#ifndef OMIT_JSON_SUPPORT #ifndef OMIT_JSON_SUPPORT
#include "../ext/json/json.hpp" #include <nlohmann/json.hpp>
#endif #endif
namespace ZeroTier { namespace ZeroTier {

View file

@ -229,13 +229,19 @@ public:
* @param s Socket object * @param s Socket object
* @return Underlying OS-type (usually int or long) file descriptor associated with object * @return Underlying OS-type (usually int or long) file descriptor associated with object
*/ */
static inline ZT_PHY_SOCKFD_TYPE getDescriptor(PhySocket *s) throw() { return reinterpret_cast<PhySocketImpl *>(s)->sock; } static inline ZT_PHY_SOCKFD_TYPE getDescriptor(PhySocket* s) throw()
{
return reinterpret_cast<PhySocketImpl*>(s)->sock;
}
/** /**
* @param s Socket object * @param s Socket object
* @return Pointer to user object * @return Pointer to user object
*/ */
static inline void** getuptr(PhySocket *s) throw() { return &(reinterpret_cast<PhySocketImpl *>(s)->uptr); } static inline void** getuptr(PhySocket* s) throw()
{
return &(reinterpret_cast<PhySocketImpl*>(s)->uptr);
}
/** /**
* @param s Socket object * @param s Socket object
@ -244,6 +250,10 @@ public:
*/ */
static inline void getIfName(PhySocket* s, char* nameBuf, int buflen) static inline void getIfName(PhySocket* s, char* nameBuf, int buflen)
{ {
PhySocketImpl& sws = *(reinterpret_cast<PhySocketImpl*>(s));
if (sws.type == ZT_PHY_SOCKET_CLOSED) {
return;
}
if (s) { if (s) {
memcpy(nameBuf, reinterpret_cast<PhySocketImpl*>(s)->ifname, buflen); memcpy(nameBuf, reinterpret_cast<PhySocketImpl*>(s)->ifname, buflen);
} }
@ -256,6 +266,10 @@ public:
*/ */
static inline void setIfName(PhySocket* s, char* ifname, int len) static inline void setIfName(PhySocket* s, char* ifname, int len)
{ {
PhySocketImpl& sws = *(reinterpret_cast<PhySocketImpl*>(s));
if (sws.type == ZT_PHY_SOCKET_CLOSED) {
return;
}
if (s) { if (s) {
memcpy(&(reinterpret_cast<PhySocketImpl*>(s)->ifname), ifname, len); memcpy(&(reinterpret_cast<PhySocketImpl*>(s)->ifname), ifname, len);
} }
@ -279,12 +293,18 @@ public:
/** /**
* @return Number of open sockets * @return Number of open sockets
*/ */
inline unsigned long count() const throw() { return _socks.size(); } inline unsigned long count() const throw()
{
return _socks.size();
}
/** /**
* @return Maximum number of sockets allowed * @return Maximum number of sockets allowed
*/ */
inline unsigned long maxCount() const throw() { return ZT_PHY_MAX_SOCKETS; } inline unsigned long maxCount() const throw()
{
return ZT_PHY_MAX_SOCKETS;
}
/** /**
* Wrap a raw file descriptor in a PhySocket structure * Wrap a raw file descriptor in a PhySocket structure

4
pkg/README.md Normal file
View file

@ -0,0 +1,4 @@
Third-party packaging
=====
Builds packages for various embedded devices and appliances and platforms

10
pkg/asustor/Dockerfile Normal file
View file

@ -0,0 +1,10 @@
# vim: ft=dockerfile
FROM ubuntu:20.04
RUN apt-get update -qq && apt-get install python2.7 -y
COPY apkg-tools.py /apkg-tools.py
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

13
pkg/asustor/build.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
build_packages()
{
sudo docker run -v $(pwd):/zto ztasustor
}
build_container()
{
sudo docker build -t ztasustor . --load
}
"$@"

29
pkg/asustor/entrypoint.sh Executable file
View file

@ -0,0 +1,29 @@
#!/bin/bash
ZTO_VER=$(git describe --abbrev=0 --tags)
ZTO_COMMIT=$(git rev-parse HEAD)
ZTO_DESC=$(jq -r '.desc' ../config.json)
# Clean up any pre-existing packages
find pkg/asustor -type f -name "*.apk" -exec rm -rvf {} \;
# Copy current license
cp ../../LICENSE.txt zerotier/control/license.txt
# Configure package data
tmp="config-tmp.json"
jq --arg a "$ZTO_VER" '.general.version = $a' pkg/asustor/zerotier/CONTROL/config.json > $tmp && mv $tmp pkg/asustor/zerotier/CONTROL/config.json
echo $ZTO_DESC > pkg/asustor/zerotier/CONTROL/description.txt
# Copy binaries into pkg directory
cp -vf output/static/zerotier-one.${ZTO_VER}.alpine-aarch64 pkg/asustor/zerotier/bin/zerotier-one.aarch64
cp -vf output/static/zerotier-one.${ZTO_VER}.alpine-i386 pkg/asustor/zerotier/bin/zerotier-one.i386
cp -vf output/static/zerotier-one.${ZTO_VER}.alpine-x86_64 pkg/asustor/zerotier/bin/zerotier-one.x86-64
# Package
python pkg/asustor/apkg-tools.py create pkg/asustor/zerotier
rm -rf output/asustor
mkdir -p output/asustor
mv ./*.apk output/asustor
# Show output product
cat pkg/asustor/zerotier/CONTROL/config.json
tree output/asustor

View file

@ -0,0 +1,15 @@
{
"general": {
"package": "zerotier",
"name": "ZeroTier",
"version": "1.8.6",
"depends": [],
"conflicts": [],
"developer": "ZeroTier, Inc.",
"maintainer": "ZeroTier, Inc.",
"email": "support@zerotier.com",
"website": "http://www.zerotier.com/",
"architecture": "any",
"firmware": "2.1.0"
}
}

View file

@ -0,0 +1 @@
Securely connect any device, anywhere.

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

View file

@ -0,0 +1,149 @@
-----------------------------------------------------------------------------
Business Source License 1.1
License text copyright (c) 2017 MariaDB Corporation Ab, All Rights Reserved.
"Business Source License" is a trademark of MariaDB Corporation Ab.
-----------------------------------------------------------------------------
Parameters
Licensor: ZeroTier, Inc.
Licensed Work: ZeroTier Network Virtualization Engine 1.4.4
The Licensed Work is (c)2019 ZeroTier, Inc.
Additional Use Grant: You may make use of the Licensed Work, provided you
do not use it in any of the following ways:
* Sell hosted ZeroTier services as a "SaaS" Product
(1) Operate or sell access to ZeroTier root servers,
network controllers, or authorization key or certificate
generation components of the Licensed Work as a
for-profit service, regardless of whether the use of
these components is sold alone or is bundled with other
services. Note that this does not apply to the use of
ZeroTier behind the scenes to operate a service not
related to ZeroTier network administration.
* Create Non-Open-Source Commercial Derviative Works
(2) Link or directly include the Licensed Work in a
commercial or for-profit application or other product
not distributed under an Open Source Initiative (OSI)
compliant license. See: https://opensource.org/licenses
(3) Remove the name, logo, copyright, or other branding
material from the Licensed Work to create a "rebranded"
or "white labeled" version to distribute as part of
any commercial or for-profit product or service.
* Certain Government Uses
(4) Use or deploy the Licensed Work in a government
setting in support of any active government function
or operation with the exception of the following:
physical or mental health care, family and social
services, social welfare, senior care, child care, and
the care of persons with disabilities.
Change Date: 2025-01-01
Change License: Apache License version 2.0 as published by the Apache
Software Foundation
https://www.apache.org/licenses/
Alternative Licensing
If you would like to use the Licensed Work in any way that conflicts with
the stipulations of the Additional Use Grant, contact ZeroTier, Inc. to
obtain an alternative commercial license.
Visit us on the web at: https://www.zerotier.com/
Notice
The Business Source License (this document, or the "License") is not an Open
Source license. However, the Licensed Work will eventually be made available
under an Open Source License, as stated in this License.
For more information on the use of the Business Source License for ZeroTier
products, please visit our pricing page which contains license details and
and license FAQ: https://zerotier.com/pricing
For more information on the use of the Business Source License generally,
please visit the Adopting and Developing Business Source License FAQ at
https://mariadb.com/bsl-faq-adopting.
-----------------------------------------------------------------------------
Business Source License 1.1
Terms
The Licensor hereby grants you the right to copy, modify, create derivative
works, redistribute, and make non-production use of the Licensed Work. The
Licensor may make an Additional Use Grant, above, permitting limited
production use.
Effective on the Change Date, or the fourth anniversary of the first publicly
available distribution of a specific version of the Licensed Work under this
License, whichever comes first, the Licensor hereby grants you rights under
the terms of the Change License, and the rights granted in the paragraph
above terminate.
If your use of the Licensed Work does not comply with the requirements
currently in effect as described in this License, you must purchase a
commercial license from the Licensor, its affiliated entities, or authorized
resellers, or you must refrain from using the Licensed Work.
All copies of the original and modified Licensed Work, and derivative works
of the Licensed Work, are subject to this License. This License applies
separately for each version of the Licensed Work and the Change Date may vary
for each version of the Licensed Work released by Licensor.
You must conspicuously display this License on each original or modified copy
of the Licensed Work. If you receive the Licensed Work in original or
modified form from a third party, the terms and conditions set forth in this
License apply to your use of that work.
Any use of the Licensed Work in violation of this License will automatically
terminate your rights under this License for the current and all other
versions of the Licensed Work.
This License does not grant you any right in any trademark or logo of
Licensor or its affiliates (provided that you may use a trademark or logo of
Licensor as expressly required by this License).
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON
AN "AS IS" BASIS. LICENSOR HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS,
EXPRESS OR IMPLIED, INCLUDING (WITHOUT LIMITATION) WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT, AND
TITLE.
-----------------------------------------------------------------------------
MariaDB hereby grants you permission to use this Licenses text to license
your works, and to refer to it using the trademark "Business Source License",
as long as you comply with the Covenants of Licensor below.
Covenants of Licensor
In consideration of the right to use this Licenses text and the "Business
Source License" name and trademark, Licensor covenants to MariaDB, and to all
other recipients of the licensed work to be provided by Licensor:
1. To specify as the Change License the GPL Version 2.0 or any later version,
or a license that is compatible with GPL Version 2.0 or a later version,
where "compatible" means that software provided under the Change License can
be included in a program with software provided under GPL Version 2.0 or a
later version. Licensor may specify additional Change Licenses without
limitation.
2. To either: (a) specify an additional grant of rights to use that does not
impose any additional restriction on the right granted in this License, as
the Additional Use Grant; or (b) insert the text "None".
3. To specify a Change Date.
4. Not to modify this License in any other way.

View file

@ -0,0 +1,24 @@
#!/bin/sh
APKG_PKG_DIR=/usr/local/AppCentral/zerotier
case "$APKG_PKG_STATUS" in
install)
modprobe tun
mkdir -p /usr/local/bin
mv ${APKG_PKG_DIR}/bin/zerotier-one.${AS_NAS_ARCH} ${APKG_PKG_DIR}/bin/zerotier-one
ln -s ${APKG_PKG_DIR}/bin/zerotier-one /usr/local/bin/zerotier-cli
ln -s ${APKG_PKG_DIR}/bin/zerotier-one /usr/local/bin/zerotier-idtool
ln -s $APKG_PKG_DIR/data /var/lib/zerotier-one
;;
upgrade)
# post upgrade script here (restore data)
# cp -af $APKG_TEMP_DIR/* $APKG_PKG_DIR/etc/.
;;
*)
;;
esac
exit 0

View file

@ -0,0 +1,3 @@
#!/bin/sh
rm -rf /var/lib/zerotier-one/

View file

View file

View file

@ -0,0 +1,26 @@
#!/bin/sh
. /etc/script/lib/command.sh
APKG_PKG_DIR=/usr/local/AppCentral/zerotier
case $1 in
start)
modprobe tun
# start script here
$APKG_PKG_DIR/bin/zerotier-one $APKG_PKG_DIR/data -d
;;
stop)
# stop script here
pkill zerotier
;;
*)
echo "usage: $0 {start|stop}"
exit 1
;;
esac
exit 0

View file

@ -0,0 +1 @@
2.0

View file

@ -0,0 +1,58 @@
<div class="header">
<h2 id="zerotier">ZeroTier</h2>
</div>
<p>Welcome! ZeroTier is a peer-to-peer encrypted virtual networking solution that enables you to create Local Area Networks with static IP assignments for all of your devices. Access your NAS from anywhere in the world with a single IP and without the need of cloud services backhauling your traffic. To use the CLI:</p>
<h2 id="using-the-cli-via-ssh-">Using the CLI via SSH:</h2>
<ol>
<li><p>Using your (admin) account, enable SSH:</p>
<ul>
<li><strong><code>Services</code></strong> -&gt; <strong><code>Terminal</code></strong> -&gt; <strong><code>Enable SSH</code></strong> (set to port <code>22</code>)</li>
</ul>
</li>
<li><p>From a computer, open a terminal and SSH into your NAS device:</p>
<ul>
<li><strong><code>ssh admin@your_nas_device_lan_ip</code></strong></li>
</ul>
</li>
<li><p>Create account and network ID at <a href="https://my.zerotier.com">my.zerotier.com</a></p>
<ul>
<li><em>Note: This account is merely to administer your network. Your traffic is not handled by ZeroTier except in the case where a direct connection cannot be established. This is a courtesy service we offer for free that you can disable if you&#39;d like. In any case, your traffic is <a href="https://www.zerotier.com/manual/#2_1_3">fully encrypted</a> end-to-end.</em></li>
</ul>
</li>
<li><p>Join your device to the network:</p>
<ul>
<li><strong><code>zerotier-cli join your_network_id</code></strong></li>
</ul>
</li>
<li><p>Use <a href="https://my.zerotier.com">my.zerotier.com</a> to authorize your NAS device to join your network.</p>
</li>
</ol>
<h2 id="help-and-support-in-order-of-relevance-">Help and support (in order of relevance)</h2>
<ul>
<li>Github Repository: <a href="https://github.com/zerotier/ZeroTierNAS/issues">https://github.com/zerotier/ZeroTierNAS</a></li>
<li>Forums: <a href="https://discuss.zerotier.com">https://discuss.zerotier.com</a></li>
<li>Contact: <a href="mailto:support@zerotier.com">support@zerotier.com</a></li>
</ul>
<div class="footer">
<h2 id="zerotier"><h2>
</div>
<style>
.header {
padding: 1px;
text-align: center;
background: #F2B464;
color: black;
font-size: 30px;
}
.footer {
padding: 1px;
text-align: center;
background: #F2B464;
color: black;
font-size: 30px;
}
</style>

6
pkg/config.json Normal file
View file

@ -0,0 +1,6 @@
{
"version": "1.8.7",
"rev": "1",
"desc": "Securely connect any device, anywhere.",
"email": "support@zerotier.com"
}

8
pkg/qnap/Dockerfile Normal file
View file

@ -0,0 +1,8 @@
# vim: ft=dockerfile
FROM ubuntu:20.04
# COPY zerotier/qbuild /qbuild
COPY entrypoint.sh /entrypoint.sh
ENTRYPOINT ["/entrypoint.sh"]

13
pkg/qnap/build.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/bash
build_packages()
{
sudo docker run -v $(pwd):/zto ztqnap
}
build_container()
{
sudo docker build -t ztqnap . --load
}
"$@"

76
pkg/qnap/entrypoint.sh Executable file
View file

@ -0,0 +1,76 @@
#!/bin/bash
ZTO_VER=$(git describe --abbrev=0 --tags)
ZTO_COMMIT=$(git rev-parse HEAD)
ZTO_DESC=$(jq -r '.desc' ../config.json)
mkdir -p pkg/qnap/zerotier/arm_64
mkdir -p pkg/qnap/zerotier/arm_x09
mkdir -p pkg/qnap/zerotier/arm_x10
mkdir -p pkg/qnap/zerotier/arm_x12
mkdir -p pkg/qnap/zerotier/arm_x19
mkdir -p pkg/qnap/zerotier/arm_x31
mkdir -p pkg/qnap/zerotier/arm_x41
mkdir -p pkg/qnap/zerotier/x86_64
mkdir -p pkg/qnap/zerotier/x86
mkdir -p pkg/qnap/zerotier/x86_ce53xx
cat > pkg/qnap/zerotier/qpkg.cfg <<- EOM
# Update package config
# Name of the packaged application.
QPKG_NAME="zerotier"
# Name of the display application.
QPKG_DISPLAY_NAME="ZeroTier"
# Version of the packaged application.
QPKG_VER="$ZTO_VER"
# Author or maintainer of the package
QPKG_AUTHOR="ZeroTier, Inc."
# License for the packaged application
QPKG_LICENSE="BUSL-1.1"
# One-line description of the packaged application
QPKG_SUMMARY="$ZTO_DESC"
# Preferred number in start/stop sequence.
QPKG_RC_NUM="101"
# Init-script used to control the start and stop of the installed application.
QPKG_SERVICE_PROGRAM="zerotier.sh"
# Specifies any packages required for the current package to operate.
QPKG_REQUIRE="QVPN Service"
# Specifies what packages cannot be installed if the current package
# is to operate properly.
#QPKG_CONFLICT="Python, OPT/sed"
# Name of configuration file (multiple definitions are allowed).
#QPKG_CONFIG="myApp.conf"
#QPKG_CONFIG="/etc/config/myApp.conf"
# Port number used by service program.
QPKG_SERVICE_PORT="9993"
# Minimum QTS version requirement
QTS_MINI_VERSION="4.1.0"
# Maximum QTS version requirement
QTS_MAX_VERSION="5.0.0"
# Location of icons for the packaged application.
QDK_DATA_DIR_ICONS="icons"
EOM
# Copy binaries into pkg directory
# See: https://github.com/qnap-dev/QDK
cp -vf output/static/zerotier-one.${ZTO_VER}.alpine-aarch64 pkg/qnap/zerotier/arm_64/zerotier-one
#cp -vf output/static/zerotier-one.${ZTO_VER}.alpine-armv5tejl pkg/qnap/zerotier/arm-x09/zerotier-one
#cp -vf output/static/zerotier-one.${ZTO_VER}.alpine-armv5tel pkg/qnap/zerotier/arm-x19/zerotier-one
cp -vf output/static/zerotier-one.${ZTO_VER}.alpine-armhf pkg/qnap/zerotier/arm-x31/zerotier-one
cp -vf output/static/zerotier-one.${ZTO_VER}.alpine-armhf pkg/qnap/zerotier/arm-x41/zerotier-one
cp -vf output/static/zerotier-one.${ZTO_VER}.alpine-i386 pkg/qnap/zerotier/x86/zerotier-one
cp -vf output/static/zerotier-one.${ZTO_VER}.alpine-x86_64 pkg/qnap/zerotier/x86_64/zerotier-one
cp -vf output/static/zerotier-one.${ZTO_VER}.alpine-i386 pkg/qnap/zerotier/x86_ce53xx/zerotier-one
rm -rf output/qnap/*
pushd pkg/qnap/zerotier
./qbuild #--build-arch arm-x31
cp -f build/* ../../../output/qnap
# Show output product
cd popd

3
pkg/qnap/qdk.conf Normal file
View file

@ -0,0 +1,3 @@
QDK_VERSION=2.3.11
QDK_PATH_P=`pwd | awk 'BEGIN { FS = "QDK" } ; { print $1 }'`
QDK_PATH="${QDK_PATH_P}/QDK"

View file

@ -0,0 +1,7 @@
.PHONY: all
all:
@$(CC) -o qpkg_encrypt qpkg_encrypt.c
clean:
rm -rf /bin/qpkg_encrypt

View file

View file

View file

View file

View file

View file

View file

View file

View file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

View file

@ -0,0 +1,158 @@
######################################################################
# List of available definitions (it's not necessary to uncomment them)
######################################################################
###### Command definitions #####
#CMD_AWK="/bin/awk"
#CMD_CAT="/bin/cat"
#CMD_CHMOD="/bin/chmod"
#CMD_CHOWN="/bin/chown"
#CMD_CP="/bin/cp"
#CMD_CUT="/bin/cut"
#CMD_DATE="/bin/date"
#CMD_ECHO="/bin/echo"
#CMD_EXPR="/usr/bin/expr"
#CMD_FIND="/usr/bin/find"
#CMD_GETCFG="/sbin/getcfg"
#CMD_GREP="/bin/grep"
#CMD_GZIP="/bin/gzip"
#CMD_HOSTNAME="/bin/hostname"
#CMD_LN="/bin/ln"
#CMD_LOG_TOOL="/sbin/log_tool"
#CMD_MD5SUM="/bin/md5sum"
#CMD_MKDIR="/bin/mkdir"
#CMD_MV="/bin/mv"
#CMD_RM="/bin/rm"
#CMD_RMDIR="/bin/rmdir"
#CMD_SED="/bin/sed"
#CMD_SETCFG="/sbin/setcfg"
#CMD_SLEEP="/bin/sleep"
#CMD_SORT="/usr/bin/sort"
#CMD_SYNC="/bin/sync"
#CMD_TAR="/bin/tar"
#CMD_TOUCH="/bin/touch"
#CMD_WGET="/usr/bin/wget"
#CMD_WLOG="/sbin/write_log"
#CMD_XARGS="/usr/bin/xargs"
#CMD_7Z="/usr/local/sbin/7z"
#
###### System definitions #####
#SYS_EXTRACT_DIR="$(pwd)"
#SYS_CONFIG_DIR="/etc/config"
#SYS_INIT_DIR="/etc/init.d"
#SYS_STARTUP_DIR="/etc/rcS.d"
#SYS_SHUTDOWN_DIR="/etc/rcK.d"
#SYS_RSS_IMG_DIR="/home/httpd/RSS/images"
#SYS_QPKG_DATA_FILE_GZIP="./data.tar.gz"
#SYS_QPKG_DATA_FILE_BZIP2="./data.tar.bz2"
#SYS_QPKG_DATA_FILE_7ZIP="./data.tar.7z"
#SYS_QPKG_DATA_CONFIG_FILE="./conf.tar.gz"
#SYS_QPKG_DATA_MD5SUM_FILE="./md5sum"
#SYS_QPKG_DATA_PACKAGES_FILE="./Packages.gz"
#SYS_QPKG_CONFIG_FILE="$SYS_CONFIG_DIR/qpkg.conf"
#SYS_QPKG_CONF_FIELD_QPKGFILE="QPKG_File"
#SYS_QPKG_CONF_FIELD_NAME="Name"
#SYS_QPKG_CONF_FIELD_VERSION="Version"
#SYS_QPKG_CONF_FIELD_ENABLE="Enable"
#SYS_QPKG_CONF_FIELD_DATE="Date"
#SYS_QPKG_CONF_FIELD_SHELL="Shell"
#SYS_QPKG_CONF_FIELD_INSTALL_PATH="Install_Path"
#SYS_QPKG_CONF_FIELD_CONFIG_PATH="Config_Path"
#SYS_QPKG_CONF_FIELD_WEBUI="WebUI"
#SYS_QPKG_CONF_FIELD_WEBPORT="Web_Port"
#SYS_QPKG_CONF_FIELD_SERVICEPORT="Service_Port"
#SYS_QPKG_CONF_FIELD_SERVICE_PIDFILE="Pid_File"
#SYS_QPKG_CONF_FIELD_AUTHOR="Author"
#SYS_QPKG_CONF_FIELD_RC_NUMBER="RC_Number"
## The following variables are assigned values at run-time.
#SYS_HOSTNAME=$($CMD_HOSTNAME)
## Data file name (one of SYS_QPKG_DATA_FILE_GZIP, SYS_QPKG_DATA_FILE_BZIP2,
## or SYS_QPKG_DATA_FILE_7ZIP)
#SYS_QPKG_DATA_FILE=
## Base location.
#SYS_QPKG_BASE=""
## Base location of QPKG installed packages.
#SYS_QPKG_INSTALL_PATH=""
## Location of installed software.
#SYS_QPKG_DIR=""
## If the QPKG should be enabled or disabled after the installation/upgrade.
#SYS_QPKG_SERVICE_ENABLED=""
## Architecture of the device the QPKG is installed on.
#SYS_CPU_ARCH=""
## Name and location of system shares
#SYS_PUBLIC_SHARE=""
#SYS_PUBLIC_PATH=""
#SYS_DOWNLOAD_SHARE=""
#SYS_DOWNLOAD_PATH=""
#SYS_MULTIMEDIA_SHARE=""
#SYS_MULTIMEDIA_PATH=""
#SYS_RECORDINGS_SHARE=""
#SYS_RECORDINGS_PATH=""
#SYS_USB_SHARE=""
#SYS_USB_PATH=""
#SYS_WEB_SHARE=""
#SYS_WEB_PATH=""
## Path to ipkg or opkg package tool if installed.
#CMD_PKG_TOOL=
#
######################################################################
# All package specific functions shall call 'err_log MSG' if an error
# is detected that shall terminate the installation.
######################################################################
######################################################################
# Define any package specific operations that shall be performed when
# the package is removed.
######################################################################
#PKG_PRE_REMOVE="{
#}"
PKG_MAIN_REMOVE="{
rm -rf /usr/sbin/zerotier-cli
# all identity files are stored in the Install_Path and will be removed automatically
}"
#PKG_POST_REMOVE="{
#}"
######################################################################
# Define any package specific initialization that shall be performed
# before the package is installed.
######################################################################
pkg_init()
{
modprobe tun
}
######################################################################
# Define any package specific requirement checks that shall be
# performed before the package is installed.
######################################################################
#pkg_check_requirement()
#{
#}
######################################################################
# Define any package specific operations that shall be performed when
# the package is installed.
######################################################################
#pkg_pre_install()
#{
# log "pkg_pre_install"
#}
#pkg_install()
#{
# log "pkg_install"
#}
pkg_post_install()
{
log $SYS_QPKG_INSTALL_PATH
modprobe tun
}

View file

@ -0,0 +1,99 @@
# Update package config
# Name of the packaged application.
QPKG_NAME="zerotier"
# Name of the display application.
QPKG_DISPLAY_NAME="ZeroTier"
# Version of the packaged application.
QPKG_VER="1.8.4"
# Author or maintainer of the package
QPKG_AUTHOR="ZeroTier, Inc."
# License for the packaged application
QPKG_LICENSE="BUSL-1.1"
# One-line description of the packaged application
QPKG_SUMMARY="Securely connect any device, anywhere."
# Preferred number in start/stop sequence.
QPKG_RC_NUM="101"
# Init-script used to control the start and stop of the installed application.
QPKG_SERVICE_PROGRAM="zerotier.sh"
# Specifies any packages required for the current package to operate.
QPKG_REQUIRE="QVPN Service"
# Specifies what packages cannot be installed if the current package
# is to operate properly.
#QPKG_CONFLICT="Python, OPT/sed"
# Name of configuration file (multiple definitions are allowed).
#QPKG_CONFIG="myApp.conf"
#QPKG_CONFIG="/etc/config/myApp.conf"
# Port number used by service program.
QPKG_SERVICE_PORT="9993"
# Location of file with running service's PID
#QPKG_SERVICE_PIDFILE="/var/lib/zerotier-one/zerotier-one.pid"
# Relative path to web interface
#QPKG_WEBUI=""
# Port number for the web interface.
#QPKG_WEB_PORT=""
# Port number for the SSL web interface.
#QPKG_WEB_SSL_PORT=""
# Use QTS HTTP Proxy and set Proxy_Path in the qpkg.conf.
# When the QPKG has its own HTTP service port, and want clients to connect via QTS HTTP port (default 8080).
# Usually use this option when the QPKG need to connect via myQNAPcloud service.
#QPKG_USE_PROXY="1"
#QPKG_PROXY_PATH="/qpkg_name"
#Desktop Application (since 4.1)
# Set value to 1 means to open the QPKG's Web UI inside QTS desktop instead of new window.
#QPKG_DESKTOP_APP="1"
# Desktop Application Window default inner width (since 4.1) (not over 1178)
#QPKG_DESKTOP_APP_WIN_WIDTH=""
# Desktop Application Window default inner width (since 4.1) (not over 600)
#QPKG_DESKTOP_APP_WIN_HEIGHT=""
# Minimum QTS version requirement
QTS_MINI_VERSION="4.1.0"
# Maximum QTS version requirement
QTS_MAX_VERSION="5.0.0"
# Select volume
# 1: support installation
# 2: support migration
# 3 (1+2): support both installation and migration
#QPKG_VOLUME_SELECT="0"
# Set timeout for QPKG enable and QPKG disable (since 4.1.0)
# Format in seconds (enable, disable)
#QPKG_TIMEOUT="10,30"
# Visible setting for the QPKG that has web UI, show this QPKG on the Main menu of
# 1(default): administrators, 2: all NAS users.
#QPKG_VISIBLE="2"
# Location of the chroot environment (only TS-x09)
#QPKG_ROOTFS=""
# Init-script used to controls the start and stop of the
# installed application (only TS-x09)
#QPKG_SERVICE_PROGRAM_CHROOT=""
# Location of icons for the packaged application.
QDK_DATA_DIR_ICONS="icons"
# Location of files specific to arm-x09 packages.
#QDK_DATA_DIR_X09="arm-x09"
# Location of files specific to arm-x19 packages.
#QDK_DATA_DIR_X19="arm-x19"
# Location of files specific to arm-x31 packages.
#QDK_DATA_DIR_X31="arm-x31"
# Location of files specific to arm-x41 packages.
#QDK_DATA_DIR_X41="arm_al"
# Location of files specific to x86 packages.
#QDK_DATA_DIR_X86="x86"
# Location of files specific to x86 (64-bit) packages.
#QDK_DATA_DIR_X86_64="x86_64"
# Location of files common to all architectures.
#QDK_DATA_DIR_SHARED="shared"
# Location of configuration files.
#QDK_DATA_DIR_CONFIG="config"
# Name of local data package.
#QDK_DATA_FILE=""
# Name of extra package (multiple definitions are allowed).
#QDK_EXTRA_FILE=""

View file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View file

@ -0,0 +1,34 @@
#!/bin/sh
CONF=/etc/config/qpkg.conf
QPKG_NAME="zerotier"
QPKG_ROOT=`/sbin/getcfg $QPKG_NAME Install_Path -f ${CONF}`
APACHE_ROOT=/share/`/sbin/getcfg SHARE_DEF defWeb -d Qweb -f /etc/config/def_share.info`
case "$1" in
start)
modprobe tun
ln -s $QPKG_ROOT/zerotier-one /usr/sbin/zerotier-cli
ln -s $QPKG_ROOT/zerotier-one /usr/bin/zerotier-cli
ln -s $QPKG_ROOT /var/lib/zerotier-one
ENABLED=$(/sbin/getcfg $QPKG_NAME Enable -u -d FALSE -f $CONF)
if [ "$ENABLED" != "TRUE" ]; then
echo "$QPKG_NAME is disabled."
exit 1
fi
$QPKG_ROOT/zerotier-one $QPKG_ROOT -d
;;
stop)
killall zerotier-one
;;
restart)
$0 stop
$0 start
;;
*)
echo "Usage: $0 {start|stop|restart}"
exit 1
esac
exit 0

Some files were not shown because too many files have changed in this diff Show more