Просмотр исходного кода

1.12.0 merge to main (#2104)

* add note about forceTcpRelay

* Create a sample systemd unit for tcp proxy

* set gitattributes for rust & cargo so hashes dont conflict on Windows

* Revert "set gitattributes for rust & cargo so hashes dont conflict on Windows"

This reverts commit 032dc5c108195f6bbc2e224f00da5b785df4b7f9.

* Turn off autocrlf for rust source

Doesn't appear to play nice well when it comes to git and vendored cargo package hashes

* Fix #1883 (#1886)

Still unknown as to why, but the call to `nc->GetProperties()` can fail
when setting a friendly name on the Windows virtual ethernet adapter.
Ensure that `ncp` is not null before continuing and accessing the device
GUID.

* Don't vendor packages for zeroidc (#1885)

* Added docker environment way to join networks (#1871)

* add StringUtils

* fix headers
use recommended headers and remove unused headers

* move extern "C"
only JNI functions need to be exported

* cleanup

* fix ANDROID-50: RESULT_ERROR_BAD_PARAMETER typo

* fix typo in log message

* fix typos in JNI method signatures

* fix typo

* fix ANDROID-51: fieldName is uninitialized

* fix ANDROID-35: memory leak

* fix missing DeleteLocalRef in loops

* update to use unique error codes

* add GETENV macro

* add LOG_TAG defines

* ANDROID-48: add ZT_jnicache.cpp

* ANDROID-48: use ZT_jnicache.cpp and remove ZT_jnilookup.cpp and ZT_jniarray.cpp

* add Event.fromInt

* add PeerRole.fromInt

* add ResultCode.fromInt

* fix ANDROID-36: issues with ResultCode

* add VirtualNetworkConfigOperation.fromInt

* fix ANDROID-40: VirtualNetworkConfigOperation out-of-sync with ZT_VirtualNetworkConfigOperation enum

* add VirtualNetworkStatus.fromInt

* fix ANDROID-37: VirtualNetworkStatus out-of-sync with ZT_VirtualNetworkStatus enum

* add VirtualNetworkType.fromInt

* make NodeStatus a plain data class

* fix ANDROID-52: synchronization bug with nodeMap

* Node init work: separate Node construction and init

* add Node.toString

* make PeerPhysicalPath a plain data class

* remove unused PeerPhysicalPath.fixed

* add array functions

* make Peer a plain data class

* make Version a plain data class

* fix ANDROID-42: copy/paste error

* fix ANDROID-49: VirtualNetworkConfig.equals is wrong

* reimplement VirtualNetworkConfig.equals

* reimplement VirtualNetworkConfig.compareTo

* add VirtualNetworkConfig.hashCode

* make VirtualNetworkConfig a plain data class

* remove unused VirtualNetworkConfig.enabled

* reimplement VirtualNetworkDNS.equals

* add VirtualNetworkDNS.hashCode

* make VirtualNetworkDNS a plain data class

* reimplement VirtualNetworkRoute.equals

* reimplement VirtualNetworkRoute.compareTo

* reimplement VirtualNetworkRoute.toString

* add VirtualNetworkRoute.hashCode

* make VirtualNetworkRoute a plain data class

* add isSocketAddressEmpty

* add addressPort

* add fromSocketAddressObject

* invert logic in a couple of places and return early

* newInetAddress and newInetSocketAddress work
allow newInetSocketAddress to return NULL if given empty address

* fix ANDROID-38: stack corruption in onSendPacketRequested

* use GETENV macro

* JniRef work
JniRef does not use callbacks struct, so remove
fix NewGlobalRef / DeleteGlobalRef mismatch

* use PRId64 macros

* switch statement work

* comments and logging

* Modifier 'public' is redundant for interface members

* NodeException can be made a checked Exception

* 'NodeException' does not define a 'serialVersionUID' field

* 'finalize()' should not be overridden
this is fine to do because ZeroTierOneService calls close() when it is done

* error handling, error reporting, asserts, logging

* simplify loadLibrary

* rename Node.networks -> Node.networkConfigs

* Windows file permissions fix (#1887)

* Allow macOS interfaces to use multiple IP addresses (#1879)

Co-authored-by: Sean OMeara <[email protected]>
Co-authored-by: Grant Limberg <[email protected]>

* Fix condition where full HELLOs might not be sent when necessary (#1877)

Co-authored-by: Grant Limberg <[email protected]>

* 1.10.4 version bumps

* Add security policy to repo (#1889)

* [+] add e2k64 arch (#1890)

* temp fix for ANDROID-56: crash inside newNetworkConfig from too many args

* 1.10.4 release notes

* Windows 1.10.4 Advanced Installer bump

* Revert "temp fix for ANDROID-56: crash inside newNetworkConfig from too many args"

This reverts commit dd627cd7f44ad623a110bb14f72d0bea72a09e30.

* actual fix for ANDROID-56: crash inside newNetworkConfig
cast all arguments to varargs functions as good style

* Fix addIp being called with applied ips (#1897)

This was getting called outside of the check for existing ips
Because of the added ifdef and a brace getting moved to the
wrong place.

```
if (! n.tap()->addIp(*ip)) {
	fprintf(stderr, "ERROR: unable to add ip address %s" ZT_EOL_S, ip->toString(ipbuf));
}
WinFWHelper::newICMPRule(*ip, n.config().nwid);

```

* 1.10.5 (#1905)

* 1.10.5 bump

* 1.10.5 for Windows

* 1.10.5

* Prevent path-learning loops (#1914)

* Prevent path-learning loops

* Only allow new overwrite if not bonded

* fix binding temporary ipv6 addresses on macos (#1910)

The check code wasn't running.

I don't know why !defined(TARGET_OS_IOS) would exclude code on
desktop macOS. I did a quick search and changed it to defined(TARGET_OS_MAC).
Not 100% sure what the most correct solution there is.

You can verify the old and new versions with

`ifconfig | grep temporary`

plus

`zerotier-cli info -j` -> listeningOn

* 1.10.6 (#1929)

* 1.10.5 bump

* 1.10.6

* 1.10.6 AIP for Windows.

* Release notes for 1.10.6 (#1931)

* Minor tweak to Synology Docker image script (#1936)

* Change if_def again so ios can build (#1937)

All apple's variables are "defined"
but sometimes they are defined as "0"

* move begin/commit into try/catch block (#1932)

Thread was exiting in some cases

* Bump openssl from 0.10.45 to 0.10.48 in /zeroidc (#1938)

Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.45 to 0.10.48.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.45...openssl-v0.10.48)

---
updated-dependencies:
- dependency-name: openssl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

* new drone bits

* Fix multiple network join from environment entrypoint.sh.release (#1961)

* _bond_m guards _bond, not _paths_m (#1965)

* Fix: warning: mutex '_aqm_m' is not held on every path through here [-Wthread-safety-analysis] (#1964)

* Bump h2 from 0.3.16 to 0.3.17 in /zeroidc (#1963)

Bumps [h2](https://github.com/hyperium/h2) from 0.3.16 to 0.3.17.
- [Release notes](https://github.com/hyperium/h2/releases)
- [Changelog](https://github.com/hyperium/h2/blob/master/CHANGELOG.md)
- [Commits](https://github.com/hyperium/h2/compare/v0.3.16...v0.3.17)

---
updated-dependencies:
- dependency-name: h2
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Grant Limberg <[email protected]>

* Add note that binutils is required on FreeBSD (#1968)

* Add prometheus metrics for Central controllers (#1969)

* add header-only prometheus lib to ext

* rename folder

* Undo rename directory

* prometheus simpleapi included on mac & linux

* wip

* wire up some controller stats

* Get windows building with prometheus

* bsd build flags for prometheus

* Fix multiple network join from environment entrypoint.sh.release (#1961)

* _bond_m guards _bond, not _paths_m (#1965)

* Fix: warning: mutex '_aqm_m' is not held on every path through here [-Wthread-safety-analysis] (#1964)

* Serve prom metrics from /metrics endpoint

* Add prom metrics for Central controller specific things

* reorganize metric initialization

* testing out a labled gauge on Networks

* increment error counter on throw

* Consolidate metrics definitions

Put all metric definitions into node/Metrics.hpp.  Accessed as needed
from there.

* Revert "testing out a labled gauge on Networks"

This reverts commit 499ed6d95e11452019cdf48e32ed4cd878c2705b.

* still blows up but adding to the record for completeness right now

* Fix runtime issues with metrics

* Add metrics files to visual studio project

* Missed an "extern"

* add copyright headers to new files

* Add metrics for sent/received bytes (total)

* put /metrics endpoint behind auth

* sendto returns int on Win32

---------

Co-authored-by: Leonardo Amaral <[email protected]>
Co-authored-by: Brenton Bostick <[email protected]>

* Central startup update (#1973)

* allow specifying authtoken in central startup

* set allowManagedFrom

* move redis_mem_notification to the correct place

* add node checkins metric

* wire up min/max connection pool size metrics

* x86_64-unknown-linux-gnu on ubuntu runner (#1975)

* adding incoming zt packet type metrics (#1976)

* use cpp-httplib for HTTP control plane (#1979)

refactored the old control plane code to use [cpp-httplib](https://github.com/yhirose/cpp-httplib) instead of a hand rolled HTTP server.  Makes the control plane code much more legible.  Also no longer randomly stops responding.

* Outgoing Packet Metrics (#1980)

add tx/rx labels to packet counters and add metrics for outgoing packets

* Add short-term validation test workflow (#1974)

Add short-term validation test workflow

* Brenton/curly braces (#1971)

* fix formatting

* properly adjust various lines
breakup multiple statements onto multiple lines

* insert {} around if, for, etc.

* Fix rust dependency caching (#1983)

* fun with rust caching

* kick

* comment out invalid yaml keys for now

* Caching should now work

* re-add/rename key directives

* bump

* bump

* bump

* Don't force rebuild on Windows build GH Action (#1985)

Switching `/t:ZeroTierOne:Rebuild` to just `/t:ZeroTierOne` allows the Windows build to use the rust cache.  `/t:ZeroTierOne:Rebuild` cleared the cache before building.

* More packet metrics (#1982)

* found path negotation sends that weren't accounted for

* Fix histogram so it will actually compile

* Found more places for packet metrics

* separate the bind & listen calls on the http backplane (#1988)

* fix memory leak (#1992)

* fix a couple of metrics (#1989)

* More aggressive CLI spamming (#1993)

* fix type signatures (#1991)

* Network-metrics (#1994)

* Add a couple quick functions for converting a uint64_t network ID/node ID into std::string

* Network metrics

* Peer metrics (#1995)

* Adding peer metrics

still need to be wired up for use

* per peer packet metrics

* Fix crash from bad instantiation of histogram

* separate alive & dead path counts

* Add peer metric update block

* add peer latency values in doPingAndKeepalive

* prevent deadlock

* peer latency histogram actually works now

* cleanup

* capture counts of packets to specific peers

---------

Co-authored-by: Joseph Henry <[email protected]>

* Metrics consolidation (#1997)

* Rename zt_packet_incoming -> zt_packet

Also consolidate zt_peer_packets into a single metric with tx and rx labels.  Same for ztc_tcp_data and ztc_udp_data

* Further collapse tcp & udp into metric labels for zt_data

* Fix zt_data metric description

* zt_peer_packets description fix

* Consolidate incoming/outgoing network packets to a single metric

* zt_incoming_packet_error -> zt_packet_error

* Disable peer metrics for central controllers

Can change in the future if needed, but given the traffic our controllers serve, that's going to be a *lot* of data

* Disable peer metrics for controllers pt 2

* Update readme files for metrics (#2000)

* Controller Metrics & Network Config Request Fix (#2003)

* add new metrics for network config request queue size and sso expirations
* move sso expiration to its own thread in the controller
* fix potential undefined behavior when modifying a set

* Enable RTTI in Windows build

The new prometheus histogram stuff needs it.

Access violation - no RTTI data!INVALID packet 636ebd9ee8cac6c0 from cafe9efeb9(2605:9880:200:1200:30:571:e34:51/9993) (unexpected exception in tryDecode())

* Don't re-apply routes on BSD

See issue #1986

* Capture setContent by-value instead of by-reference (#2006)

Co-authored-by: Grant Limberg <[email protected]>

* fix typos (#2010)

* central controller metrics & request path updates (#2012)

* internal db metrics

* use shared mutexes for read/write locks

* remove this lock. only used for a metric

* more metrics

* remove exploratory metrics

place controller request benchmarks behind ifdef

* Improve validation test (#2013)

* fix init order for EmbeddedNetworkController (#2014)

* add constant for getifaddrs cache time

* cache getifaddrs - mac

* cache getifaddrs - linux

* cache getifaddrs - bsd

* cache getifaddrs - windows

* Fix oidc client lookup query

join condition referenced the wrong table.  Worked fine unless there were multiple identical client IDs

* Fix udp sent metric

was only incrementing by 1 for each packet sent

* Allow sending all surface addresses to peer in low-bandwidth mode

* allow enabling of low bandwidth mode on controllers

* don't unborrow bad connections

pool will clean them up later

* Multi-arch controller container (#2037)

create arm64 & amd64 images for central controller

* Update README.md

issue #2009

* docker tags change

* fix oidc auth url memory leak (#2031)

getAuthURL() was not calling zeroidc::free_cstr(url);

the only place authAuthURL is called, the url can be retrieved
from the network config instead.

You could alternatively copy the string and call free_cstr in getAuthURL.
If that's better we can change the PR.

Since now there are no callers of getAuthURL I deleted it.

Co-authored-by: Grant Limberg <[email protected]>

* Bump openssl from 0.10.48 to 0.10.55 in /zeroidc (#2034)

Bumps [openssl](https://github.com/sfackler/rust-openssl) from 0.10.48 to 0.10.55.
- [Release notes](https://github.com/sfackler/rust-openssl/releases)
- [Commits](https://github.com/sfackler/rust-openssl/compare/openssl-v0.10.48...openssl-v0.10.55)

---
updated-dependencies:
- dependency-name: openssl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Grant Limberg <[email protected]>

* zeroidc cargo warnings (#2029)

* fix unused struct member cargo warning

* fix unused import cargo warning

* fix unused return value cargo warning

---------

Co-authored-by: Grant Limberg <[email protected]>

* fix memory leak in macos ipv6/dns helper (#2030)

Co-authored-by: Grant Limberg <[email protected]>

* Consider ZEROTIER_JOIN_NETWORKS in healthcheck (#1978)

* Add a 2nd auth token only for access to /metrics (#2043)

* Add a 2nd auth token for /metrics

Allows administrators to distribute a token that only has access to read
metrics and nothing else.

Also added support for using bearer auth tokens for both types of tokens

Separate endpoint for metrics #2041

* Update readme

* fix a couple of cases of writing the wrong token

* Add warning to cli for allow default on FreeBSD

It doesn't work.
Not possible to fix with deficient network
stack and APIs.

ZeroTierOne-freebsd # zerotier-cli set 9bee8941b5xxxxxx allowDefault=1
400 set Allow Default does not work properly on FreeBSD. See #580
root@freebsd13-a:~/ZeroTierOne-freebsd # zerotier-cli get 9bee8941b5xxxxxx allowDefault
1

* ARM64 Support for TapDriver6 (#1949)

* Release memory previously allocated by UPNP_GetValidIGD

* Fix ifdef that breaks libzt on iOS (#2050)

* less drone (#2060)

* Exit if loading an invalid identity from disk (#2058)

* Exit if loading an invalid identity from disk

Previously, if an invalid identity was loaded from disk, ZeroTier would
generate a new identity & chug along and generate a brand new identity
as if nothing happened.  When running in containers, this introduces the
possibility for key matter loss; especially when running in containers
where the identity files are mounted in the container read only.  In
this case, ZT will continue chugging along with a brand new identity
with no possibility of recovering the private key.

ZeroTier should exit upon loading of invalid identity.public/identity.secret #2056

* add validation test for #2056

* tcp-proxy: fix build

* Adjust tcp-proxy makefile to support metrics

There's no way to get the metrics yet. Someone will
have to add the http service.

* remove ZT_NO_METRIC ifdef

* Implement recvmmsg() for Linux to reduce syscalls. (#2046)

Between 5% and 40% speed improvement on Linux, depending on system configuration and load.

* suppress warnings: comparison of integers of different signs: 'int64_t' (aka 'long') and 'uint64_t' (aka 'unsigned long') [-Wsign-compare] (#2063)

* fix warning: 'OS_STRING' macro redefined [-Wmacro-redefined] (#2064)

Even though this is in ext, these particular chunks of code were added
by us, so are ok to modify.

* Apply default route a different way - macOS

The original way we applied default route, by forking
0.0.0.0/0 into 0/1 and 128/1 works, but if mac os has any networking
hiccups -if you change SSIDs or sleep/wake- macos erases the system default route.
And then all networking on the computer is broken.

to summarize the new way:
allowDefault=1
```
sudo route delete default 192.168.82.1
sudo route add default 10.2.0.2
sudo route add -ifscope en1 default 192.168.82.1
```

gives us this routing table
```
Destination        Gateway            RT_IFA             Flags        Refs      Use    Mtu          Netif Expire    rtt(ms) rttvar(ms)
default            10.2.0.2           10.2.0.18          UGScg          90        1   2800       feth4823
default            192.168.82.1       192.168.82.217     UGScIg
```

allowDefault=0
```
sudo route delete default
sudo route delete -ifscope en1 default
sudo route add default 192.168.82.1
```

Notice the I flag, for -ifscope, on the physical default route.

route change does not seem to work reliably.

* fix docker tag for controllers (#2066)

* Update build.sh (#2068)

fix mkwork compilation errors

* Fix network DNS on macOS

It stopped working for ipv4 only networks in Monterey.
See #1696

We add some config like so to System Configuration

```
scutil
show State:/Network/Service/9bee8941b5xxxxxx/IPv4
<dictionary> {
  Addresses : <array> {
    0 : 10.2.1.36
  }
  InterfaceName : feth4823
  Router : 10.2.1.36
  ServerAddress : 127.0.0.1
}

```

* Add search domain to macos dns configuration

Stumbled upon this while debugging something else.
If we add search domain to our system configuration for
network DNS, then search domains work:

```
ping server1                                                                                                                                                                                    ~
PING server1.my.domain (10.123.3.1): 56 data bytes
64 bytes from 10.123.3.1
```

* Fix reporting of secondaryPort and tertiaryPort See: #2039

* Fix typos (#2075)

* Disable executable stacks on assembly objects (#2071)

Add `--noexecstack` to the assembler flags so the resulting binary
will link with a non-executable stack.

Fixes zerotier/ZeroTierOne#1179

Co-authored-by: Joseph Henry <[email protected]>

* Test that starting zerotier before internet works

* Don't skip hellos when there are no paths available

working on #2082

* Update validate-1m-linux.sh

* Save zt node log files on abort

* Separate test and summary step in validator script

* Don't apply default route until zerotier is "online"

I was running into issues with restarting the zerotier service while
"full tunnel" mode is enabled.
When zerotier first boots, it gets network state from the cache
on disk. So it immediately applies all the routes it knew about
before it shutdown.
The network config may have change in this time.
If it has, then your default route is via a route
you are blocked from talking on. So you  can't get the current
network config, so your internet does not work.

Other options include
- don't use cached network state on boot
- find a better criteria than "online"

* Fix node time-to-online counter in validator script

* Export variables so that they are accessible by exit function

* Fix PortMapper issue on ZeroTier startup

See issue #2082

We use a call to libnatpmp::ininatpp to make sure the computer
has working network sockets before we go into the main
nat-pmp/upnp logic.

With basic exponenetial delay up to 30 seconds.

* testing

* Comment out PortMapper debug

this got left turned on in a confusing merge previously

* fix macos default route again

see commit fb6af1971 * Fix network DNS on macOS
adding that stuff to System Config causes this extra route to be added
which breaks ipv4 default route.
We figured out a weird System Coniguration setting
that works.

--- old
couldn't figure out how to fix it in SystemConfiguration
so here we are# Please enter the commit message for your changes. Lines starting

We also moved the dns setter to before the syncIps stuff
to help with a race condition. It didn't always work when
you re-joined a network with default route enabled.

* Catch all conditions in switch statement, remove trailing whitespaces

* Add setmtu command, fix bond lifetime issue

* Basic cleanups

* Check if null is passed to VirtualNetworkConfig.equals and name fixes

* ANDROID-96: Simplify and use return code from node_init directly

* Windows arm64 (#2099)

* ARM64 changes for 1.12

* 1.12 Windows advanced installer updates and updates for ARM64

* 1.12.0

* Linux build fixes for old distros.

* release notes

---------

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: travis laduke <[email protected]>
Co-authored-by: Grant Limberg <[email protected]>
Co-authored-by: Grant Limberg <[email protected]>
Co-authored-by: Leonardo Amaral <[email protected]>
Co-authored-by: Brenton Bostick <[email protected]>
Co-authored-by: Sean OMeara <[email protected]>
Co-authored-by: Joseph Henry <[email protected]>
Co-authored-by: Roman Peshkichev <[email protected]>
Co-authored-by: Joseph Henry <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Stavros Kois <[email protected]>
Co-authored-by: Jake Vis <[email protected]>
Co-authored-by: Jörg Thalheim <[email protected]>
Co-authored-by: lison <[email protected]>
Co-authored-by: Kenny MacDermid <[email protected]>
Adam Ierymenko 1 год назад
Родитель
Сommit
0e5651f353
100 измененных файлов с 3950 добавлено и 2175 удалено
  1. 240 24
      .drone.jsonnet
  2. 343 36
      .drone.yml
  3. 20 29
      .github/workflows/build.yml
  4. 461 0
      .github/workflows/validate-linux.sh
  5. 24 0
      .github/workflows/validate-report.sh
  6. 56 0
      .github/workflows/validate.yml
  7. 14 0
      .kick
  8. 1 0
      Makefile
  9. 62 2
      README.md
  10. 16 0
      RELEASE-NOTES.md
  11. 1 1
      attic/world/build.sh
  12. 13 0
      ci/Dockerfile-build.deb
  13. 4 4
      ci/Dockerfile-build.el6
  14. 9 0
      ci/Dockerfile-build.rpm
  15. 13 0
      ci/Dockerfile-test.deb
  16. 4 0
      ci/Dockerfile-test.el6
  17. 17 0
      ci/Dockerfile-test.rpm
  18. 0 10
      ci/Dockerfile.deb
  19. 0 5
      ci/Dockerfile.none
  20. 0 9
      ci/Dockerfile.rpm
  21. 29 106
      ci/scripts/build.sh
  22. 63 0
      ci/scripts/lib.sh
  23. 1 1
      ci/scripts/munge_debian_changelog.sh
  24. 38 0
      ci/scripts/publish.sh
  25. 55 0
      ci/scripts/test.sh
  26. 15 1
      controller/ConnectionPool.hpp
  27. 68 26
      controller/DB.cpp
  28. 9 7
      controller/DB.hpp
  29. 22 19
      controller/DBMirrorSet.cpp
  30. 3 3
      controller/DBMirrorSet.hpp
  31. 531 544
      controller/EmbeddedNetworkController.cpp
  32. 36 21
      controller/EmbeddedNetworkController.hpp
  33. 8 2
      controller/FileDB.cpp
  34. 42 24
      controller/PostgreSQL.cpp
  35. 3 0
      controller/PostgreSQL.hpp
  36. 12 209
      controller/README.md
  37. 6 0
      debian/changelog
  38. 1 1
      debian/compat
  39. 1 1
      debian/control
  40. 2 2
      entrypoint.sh.release
  41. 0 36
      ext/bin/tap-mac/tap.kext/Contents/Info.plist
  42. BIN
      ext/bin/tap-mac/tap.kext/Contents/MacOS/tap
  43. 0 105
      ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeResources
  44. BIN
      ext/bin/tap-windows-ndis6/arm64/zttap300.cat
  45. 19 17
      ext/bin/tap-windows-ndis6/arm64/zttap300.inf
  46. BIN
      ext/bin/tap-windows-ndis6/arm64/zttap300.sys
  47. BIN
      ext/bin/tap-windows-ndis6/certutil.exe
  48. BIN
      ext/bin/tap-windows-ndis6/x64.old/ZeroTierOne_NDIS6_x64.msi
  49. BIN
      ext/bin/tap-windows-ndis6/x64.old/zttap300.cat
  50. BIN
      ext/bin/tap-windows-ndis6/x64.old/zttap300.sys
  51. BIN
      ext/bin/tap-windows-ndis6/x64/ZeroTierOne_NDIS6_x64.msi
  52. BIN
      ext/bin/tap-windows-ndis6/x86.old/ZeroTierOne_NDIS6_x86.msi
  53. BIN
      ext/bin/tap-windows-ndis6/x86.old/zttap300.cat
  54. 0 143
      ext/bin/tap-windows-ndis6/x86.old/zttap300.inf
  55. BIN
      ext/bin/tap-windows-ndis6/x86.old/zttap300.sys
  56. BIN
      ext/bin/tap-windows-ndis6/x86/ZeroTierOne_NDIS6_x86.msi
  57. BIN
      ext/bin/tap-windows-ndis6/zttap300.cer
  58. 2 2
      ext/central-controller-docker/Dockerfile
  59. 16 0
      ext/central-controller-docker/Makefile
  60. 6 0
      ext/central-controller-docker/main.sh
  61. 486 206
      ext/cpp-httplib/httplib.h
  62. 0 0
      ext/hiredis-1.0.2/lib/ubuntu22.04/amd64/libhiredis.a
  63. BIN
      ext/hiredis-1.0.2/lib/ubuntu22.04/arm64/libhiredis.a
  64. 1 1
      ext/installfiles/mac/ZeroTier One.pkgproj
  65. 59 89
      ext/installfiles/windows/ZeroTier One.aip
  66. 558 0
      ext/installfiles/windows/ZeroTier One.back.aip
  67. 329 369
      ext/libpqxx-7.7.3/config/config.guess
  68. 231 120
      ext/libpqxx-7.7.3/config/config.sub
  69. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/array
  70. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/array.hxx
  71. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/binarystring
  72. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/binarystring.hxx
  73. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/blob
  74. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/blob.hxx
  75. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/composite
  76. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/composite.hxx
  77. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/config-public-compiler.h
  78. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/connection
  79. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/connection.hxx
  80. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/cursor
  81. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/cursor.hxx
  82. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/dbtransaction
  83. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/dbtransaction.hxx
  84. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/errorhandler
  85. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/errorhandler.hxx
  86. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/except
  87. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/except.hxx
  88. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/field
  89. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/field.hxx
  90. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/array-composite.hxx
  91. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/callgate.hxx
  92. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/concat.hxx
  93. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/conversions.hxx
  94. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/encoding_group.hxx
  95. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/encodings.hxx
  96. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/gates/connection-errorhandler.hxx
  97. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/gates/connection-largeobject.hxx
  98. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/gates/connection-notification_receiver.hxx
  99. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/gates/connection-pipeline.hxx
  100. 0 0
      ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/gates/connection-sql_cursor.hxx

+ 240 - 24
.drone.jsonnet

@@ -1,40 +1,256 @@
+//
+// tweakables
+//
+
 local registry = "084037375216.dkr.ecr.us-east-2.amazonaws.com";
 local registry = "084037375216.dkr.ecr.us-east-2.amazonaws.com";
+local build_channel = "zerotier-builds";
+local release_channel = "zerotier-releases";
 
 
 local targets = [
 local targets = [
-      { "os": "linux",   "name": "sid", "isas": [ "386", "armv7", "amd64", "arm64", "mips64le", "ppc64le", "s390x", "riscv64" ], "events": [ "push", "tag", "custom" ] },
+    { "os": "linux", distro: "redhat", "name": "el9",      "isas": [                 "amd64", "arm64", "ppc64le", "s390x" ],                        "events": [ "tag", "custom" ] },
+    { "os": "linux", distro: "redhat", "name": "el8",      "isas": [                 "amd64", "arm64", "ppc64le", "s390x" ],                        "events": [ "tag" ] },
+    { "os": "linux", distro: "redhat", "name": "el7",      "isas": [ "386",          "amd64",          "ppc64le"],                                  "events": [ "tag" ] },
+    { "os": "linux", distro: "amazon", "name": "amzn2",    "isas": [                 "amd64", "arm64" ],                                            "events": [ "tag" ] },
+    { "os": "linux", distro: "amazon", "name": "amzn2022", "isas": [                 "amd64", "arm64" ],                                            "events": [ "tag" ] },
+    { "os": "linux", distro: "fedora", "name": "fc38",     "isas": [                 "amd64", "arm64", "ppc64le", "s390x" ],                        "events": [ "tag" ] },
+    { "os": "linux", distro: "fedora", "name": "fc37",     "isas": [                 "amd64", "arm64", "ppc64le", "s390x" ],                        "events": [ "tag" ] },
+    { "os": "linux", distro: "fedora", "name": "fc36",     "isas": [                 "amd64", "arm64", "ppc64le", "s390x" ],                        "events": [ "tag" ] },
+    { "os": "linux", distro: "ubuntu", "name": "jammy",    "isas": [        "armv7", "amd64", "arm64", "ppc64le", "s390x", "riscv64" ],             "events": [ "tag" ] },
+    { "os": "linux", distro: "ubuntu", "name": "focal",    "isas": [        "armv7", "amd64", "arm64", "ppc64le", "s390x", "riscv64" ],             "events": [ "tag" ] },
+    { "os": "linux", distro: "ubuntu", "name": "bionic",   "isas": [ "386", "armv7", "amd64", "arm64", "ppc64le", "s390x" ],                        "events": [ "tag" ] },
+    { "os": "linux", distro: "ubuntu", "name": "xenial",   "isas": [ "386", "armv7", "amd64", "arm64", "ppc64le", "s390x" ],                        "events": [ "tag" ] },
+    { "os": "linux", distro: "ubuntu", "name": "trusty",   "isas": [ "386", "armv7", "amd64", "arm64" ],                                            "events": [ "tag" ] },
+    { "os": "linux", distro: "debian", "name": "bookworm", "isas": [ "386", "armv7", "amd64", "arm64", "mips64le", "ppc64le", "s390x" ],            "events": [ "tag"] },
+    { "os": "linux", distro: "debian", "name": "bullseye", "isas": [ "386", "armv7", "amd64", "arm64", "mips64le", "ppc64le", "s390x" ],            "events": [ "push", "tag", "custom" ] },
+    { "os": "linux", distro: "debian", "name": "buster",   "isas": [ "386", "armv7", "amd64", "arm64" ],                                            "events": [ "tag" ] },
+    { "os": "linux", distro: "debian", "name": "stretch",  "isas": [ "386", "armv7", "amd64", "arm64" ],                                            "events": [ "tag" ] },
+    { "os": "linux", distro: "debian", "name": "jessie",   "isas": [ "386", "armv7", "amd64" ],                                                     "events": [ "tag" ] },
+
+//   { "os": "windows", distro: "windows", "name": "windows",  "isas": [ "amd64" ], "events": [ "push", "tag", "custom" ] },
+//   { "os": "darwin", distro: "darwin", "name": "darwin",  "isas": [ "amd64" ], "events": [ "push", "tag", "custom" ] },
+
 ];
 ];
 
 
-local Build(platform, os, isa, events) = {
+local less_targets = [
+      { "os": "linux", distro: "redhat", "name": "el9",      "isas": [                 "amd64", "arm64" ],                        "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "redhat", "name": "el8",      "isas": [                 "amd64", "arm64" ],                        "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "ubuntu", "name": "jammy",    "isas": [        "armv7", "amd64", "arm64" ],             "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "ubuntu", "name": "focal",    "isas": [        "armv7", "amd64", "arm64" ],             "events": [ "push", "tag", "custom" ] },
+];
+
+
+local native_targets = [
+      { "os": "linux", distro: "debian", "name": "bullseye", "isas": [ "386", "armv7", "amd64", "arm64" ],            "events": [ "push", "tag", "custom" ] },
+];    
+
+local master_targets = [
+      //
+      // copypasta from here
+      //
+      { "os": "linux", distro: "redhat", "name": "el9",      "isas": [                 "amd64", "arm64", "ppc64le", "s390x" ],                        "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "redhat", "name": "el8",      "isas": [                 "amd64", "arm64", "ppc64le", "s390x" ],                        "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "redhat", "name": "el7",      "isas": [ "386", "amd64",          "ppc64le"],                                  "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "amazon", "name": "amzn2",    "isas": [                 "amd64", "arm64" ],                                            "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "amazon", "name": "amzn2022", "isas": [                 "amd64", "arm64" ],                                            "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "fedora", "name": "fc38",     "isas": [                 "amd64", "arm64", "ppc64le", "s390x" ],                        "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "fedora", "name": "fc37",     "isas": [                 "amd64", "arm64", "ppc64le", "s390x" ],                        "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "fedora", "name": "fc36",     "isas": [                 "amd64", "arm64", "ppc64le", "s390x" ],                        "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "ubuntu", "name": "jammy",    "isas": [        "armv7", "amd64", "arm64", "ppc64le", "s390x", "riscv64" ],             "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "ubuntu", "name": "focal",    "isas": [        "armv7", "amd64", "arm64", "ppc64le", "s390x", "riscv64" ],             "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "ubuntu", "name": "bionic",   "isas": [ "386", "armv7", "amd64", "arm64", "ppc64le", "s390x" ],                        "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "ubuntu", "name": "xenial",   "isas": [ "386", "armv7", "amd64", "arm64", "ppc64le", "s390x" ],                        "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "ubuntu", "name": "trusty",   "isas": [ "386", "armv7", "amd64", "arm64" ],                                            "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "debian", "name": "sid",      "isas": [ "386", "armv7", "amd64", "arm64", "mips64le", "ppc64le", "s390x", "riscv64" ], "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "debian", "name": "bookworm", "isas": [ "386", "armv7", "amd64", "arm64", "mips64le", "ppc64le", "s390x" ],            "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "debian", "name": "bullseye", "isas": [ "386", "armv7", "amd64", "arm64", "mips64le", "ppc64le", "s390x" ],            "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "debian", "name": "buster",   "isas": [ "386", "armv7", "amd64", "arm64" ],                                            "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "debian", "name": "stretch",  "isas": [ "386", "armv7", "amd64", "arm64" ],                                            "events": [ "push", "tag", "custom" ] },
+      { "os": "linux", distro: "debian", "name": "jessie",   "isas": [ "386", "armv7", "amd64" ],                                                     "events": [ "push", "tag", "custom" ] },
+      { "os": "windows", distro: "windows", "name": "win2k22", "isas": [ "amd64" ],                                                                     "events": [ "push", "tag", "custom" ] }
+];
+
+//
+// functions
+//
+
+local pipeline_type(os)  = if os == "darwin" then "exec" else "docker";
+local builder_image(os)  = if os == "linux" then registry + "/honda-builder" else registry + "/windows-builder";
+local tester_image(os)   = if os == "linux" then registry + "/honda-builder" else registry + "/windows-tester";
+local build_step_volumes(os) = if os == "linux" then [ { name: "zerotier-builds", path: "/zerotier-builds" } ] else [];
+local release_step_volumes(os) = if os == "linux" then [ { name: "zerotier-releases", path: "/zerotier-releases" } ] else [];
+local host_volumes(os)   = if os == "linux" then [
+  { name: "zerotier-builds", host: { path: "/zerotier-builds" } },
+  { name: "zerotier-releases", host: { path: "/zerotier-releases" } },
+] else [];
+
+local index_image(distro) =
+      if distro == "debian" || distro == "ubuntu" then
+          registry + "/apt-builder"
+      else if distro == "redhat" || distro == "fedora" || distro == "amazon" then
+          registry + "/dnf-builder"
+      else if distro == "windows" then
+          registry + "/msi-builder"
+;          
+
+local copy_commands(os, distro, name, isa, version) =
+  if os == "linux" then [
+      std.join(" ", [ "./ci/scripts/publish.sh", name, distro, isa, version, "${DRONE_BUILD_EVENT}" ])
+    ]
+    else if os == "windows" then [  
+      "C:\\scripts\\fix-ec2-metadata.ps1",
+      "Get-ChildItem windows",
+      // "aws s3 cp windows\\bytey-SetupFiles\\bytey.msi s3://zerotier-builds/windows/" + version + "/bytey.msi",
+    ] else if os == "darwin" then [
+        "echo hello"
+      ]
+;
+
+local index_commands(os, channel, distro, name, isas) =
+      if os == "linux" then
+        [ "/usr/local/bin/index " + channel + " " + distro + " " + name  + " " + std.join(" ", isas) ]
+      else if os == "windows" then
+        [ "Get-ChildItem -Recurse windows" ]
+;
+
+local build_commands(os, distro, name, isa, version) =
+      if os == "linux" then
+        [ std.join(" ", [ "./ci/scripts/build.sh", name, distro, isa, version, "${DRONE_BUILD_EVENT}" ]) ]
+      else
+        if os == "windows" then
+           [ "windows/build.ps1", "windows/package.ps1" ]
+      else
+        if os == "darwin" then
+           [ "whoami" ]
+;
+
+local test_commands(os, distro, name, isa, version) =
+  if os == "linux" then
+    [ std.join(" ", [ "./ci/scripts/test.sh", name, distro, isa, version, "${DRONE_BUILD_EVENT}" ]) ]
+  else
+    if os == "windows" then
+      [ "windows/testpackage.ps1 " + version ]
+;
+
+//
+// render
+//
+
+local Build(os, distro, name, isa, events) = {
   "kind": "pipeline",
   "kind": "pipeline",
-  "type": "docker",
+  "type": pipeline_type(os),
+  "name": std.join(" ", [ name, isa, "build" ]),
   "pull": "always",
   "pull": "always",
-  "name": platform + " " + isa + " " + "build",
-  "clone": { "depth": 1 },
+  "clone": { "depth": 1, [ if os == "darwin" then "disable" ]: true },
   "steps": [
   "steps": [
     {
     {
       "name": "build",
       "name": "build",
-      "image": registry + "/honda-builder",
-      "commands": [
-        "aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin " + registry,
-        "./ci/scripts/build.sh " + platform + " " + isa + " " + "100.0.0+${DRONE_COMMIT_SHA:0:8}" + " " + "${DRONE_BUILD_EVENT}"
-      ]
+      "image": builder_image(os),
+      "commands": build_commands(os, distro, name, isa, "100.0.0+${DRONE_COMMIT_SHA:0:8}"),
+      "when": { "event": [ "push" ]},
     },
     },
-    // {
-    //   "name": "list",
-    //   "image": registry + "/honda-builder",
-    //   "commands": [ "ls -la " + platform ]
-    // },
-  ],  
-  [ if isa == "arm64" || isa == "armv7" then "platform" ]: { os: os, arch: "arm64" },
+    {
+      "name": "release",
+      "image": builder_image(os),
+      "commands": build_commands(os, distro, name, isa, "${DRONE_TAG}"),
+      "when": { "event": [ "tag" ]},
+    },    
+    {
+      "name": "copy build",
+      "image": builder_image(os),
+      "commands": copy_commands(os, distro, name, isa, "100.0.0+${DRONE_COMMIT_SHA:0:8}"),
+      "volumes": build_step_volumes(os),
+      "when": { "event": [ "push" ]},
+    },
+    {
+      "name": "copy relase",
+      "image": builder_image(os),
+      "commands": copy_commands(os, distro, name, isa, "${DRONE_TAG}"),
+      "volumes": release_step_volumes(os),
+      "when": { "event": [ "tag" ]},      
+    },    
+  ],
+  "volumes": host_volumes(os),
+  "platform": { "os": os, [ if isa == "arm64" || isa == "armv7" then "arch" ]: "arm64" },
   "trigger": { "event": events }
   "trigger": { "event": events }
 };
 };
 
 
-// puttin on the bits
+local Test(os, distro, name, isa, events) = {
+  "kind": "pipeline",
+  "type": pipeline_type(os),
+  "name": std.join(" ", [ name, isa, "test"]),
+  "pull": "always",
+  "clone": { "depth": 1 },
+  "steps": [
+    {
+      "name": "test build",
+      "image": tester_image(os),
+      "volumes": build_step_volumes(os),
+      "commands": test_commands(os, distro, name, isa, "100.0.0+${DRONE_COMMIT_SHA:0:8}"),
+      "when": { "event": [ "push" ]},
+    },
+    {
+      "name": "test release",
+      "image": tester_image(os),
+      "volumes": release_step_volumes(os),
+      "commands": test_commands(os, distro, name, isa, "${DRONE_TAG}"),
+      "when": { "event": [ "tag" ]},
+    },    
+  ],
+  "volumes": host_volumes(os),
+  "platform": { "os": os, [ if isa == "arm64" || isa == "armv7" then "arch" ]: "arm64" },
+  "depends_on": [ std.join(" ", [ name, "index" ]) ],
+  "trigger": { "event": events }
+};
+
+local Index(p) = {
+  "kind": "pipeline",
+  "type": pipeline_type(p.os),
+  "name": std.join(" ", [ p.name, "index" ]),
+  "pull": "always",
+  "clone": { "depth": 1 },
+  "steps": [
+    {
+      "name": "index build",
+      "image": index_image(p.distro),
+      "commands": index_commands(p.os, "zerotier-builds", p.distro, p.name, p.isas),
+      "volumes": build_step_volumes(p.os),
+      "environment":{ "GPG_PRIVATE_KEY": { from_secret: "gpg-private-key" }},
+      "when": { "event": [ "push" ]},
+    },
+    {
+      "name": "index release",
+      "image": index_image(p.distro),
+      "commands": index_commands(p.os, "zerotier-releases", p.distro, p.name, p.isas),
+      "volumes": release_step_volumes(p.os),
+      "environment":{ "GPG_PRIVATE_KEY": { from_secret: "gpg-private-key" }},
+      "when": { "event": [ "tag" ]},  
+    },    
+  ],
+  "volumes": host_volumes(p.os),
+  "platform": { "os": p.os },
+  depends_on: std.flattenArrays([ [ std.join(" ", [ p.name, isa, "build" ]) ] for isa in p.isas ]),
+  "trigger": { "event": p.events }
+};
+
+//
+// print
+//
 
 
 std.flattenArrays([
 std.flattenArrays([
-  [
-     Build(p.name, p.os, isa, p.events)
-      for isa in p.isas
-  ]
-  for p in targets
-])
+    [
+      Build(p.os, p.distro, p.name, isa, p.events)
+        for isa in p.isas
+    ] +
+    [
+      Index(p)
+    ]
+    for p in native_targets
+ ]) +
+ std.flattenArrays([
+     [
+        Test(p.os, p.distro, p.name, isa, p.events)
+         for isa in p.isas
+     ]
+     for p in native_targets
+ ])
+ 

+ 343 - 36
.drone.yml

@@ -2,157 +2,464 @@
 clone:
 clone:
   depth: 1
   depth: 1
 kind: pipeline
 kind: pipeline
-name: sid 386 build
+name: bullseye 386 build
+platform:
+  os: linux
 pull: always
 pull: always
 steps:
 steps:
 - commands:
 - commands:
-  - aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin
-    084037375216.dkr.ecr.us-east-2.amazonaws.com
-  - ./ci/scripts/build.sh sid 386 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT}
+  - ./ci/scripts/build.sh bullseye debian 386 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT}
   image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
   image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
   name: build
   name: build
+  when:
+    event:
+    - push
+- commands:
+  - ./ci/scripts/build.sh bullseye debian 386 ${DRONE_TAG} ${DRONE_BUILD_EVENT}
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
+  name: release
+  when:
+    event:
+    - tag
+- commands:
+  - ./ci/scripts/publish.sh bullseye debian 386 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT}
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
+  name: copy build
+  volumes:
+  - name: zerotier-builds
+    path: /zerotier-builds
+  when:
+    event:
+    - push
+- commands:
+  - ./ci/scripts/publish.sh bullseye debian 386 ${DRONE_TAG} ${DRONE_BUILD_EVENT}
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
+  name: copy relase
+  volumes:
+  - name: zerotier-releases
+    path: /zerotier-releases
+  when:
+    event:
+    - tag
 trigger:
 trigger:
   event:
   event:
   - push
   - push
   - tag
   - tag
   - custom
   - custom
 type: docker
 type: docker
+volumes:
+- host:
+    path: /zerotier-builds
+  name: zerotier-builds
+- host:
+    path: /zerotier-releases
+  name: zerotier-releases
 ---
 ---
 clone:
 clone:
   depth: 1
   depth: 1
 kind: pipeline
 kind: pipeline
-name: sid armv7 build
+name: bullseye armv7 build
 platform:
 platform:
   arch: arm64
   arch: arm64
   os: linux
   os: linux
 pull: always
 pull: always
 steps:
 steps:
 - commands:
 - commands:
-  - aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin
-    084037375216.dkr.ecr.us-east-2.amazonaws.com
-  - ./ci/scripts/build.sh sid armv7 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT}
+  - ./ci/scripts/build.sh bullseye debian armv7 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT}
   image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
   image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
   name: build
   name: build
+  when:
+    event:
+    - push
+- commands:
+  - ./ci/scripts/build.sh bullseye debian armv7 ${DRONE_TAG} ${DRONE_BUILD_EVENT}
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
+  name: release
+  when:
+    event:
+    - tag
+- commands:
+  - ./ci/scripts/publish.sh bullseye debian armv7 100.0.0+${DRONE_COMMIT_SHA:0:8}
+    ${DRONE_BUILD_EVENT}
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
+  name: copy build
+  volumes:
+  - name: zerotier-builds
+    path: /zerotier-builds
+  when:
+    event:
+    - push
+- commands:
+  - ./ci/scripts/publish.sh bullseye debian armv7 ${DRONE_TAG} ${DRONE_BUILD_EVENT}
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
+  name: copy relase
+  volumes:
+  - name: zerotier-releases
+    path: /zerotier-releases
+  when:
+    event:
+    - tag
 trigger:
 trigger:
   event:
   event:
   - push
   - push
   - tag
   - tag
   - custom
   - custom
 type: docker
 type: docker
+volumes:
+- host:
+    path: /zerotier-builds
+  name: zerotier-builds
+- host:
+    path: /zerotier-releases
+  name: zerotier-releases
 ---
 ---
 clone:
 clone:
   depth: 1
   depth: 1
 kind: pipeline
 kind: pipeline
-name: sid amd64 build
+name: bullseye amd64 build
+platform:
+  os: linux
 pull: always
 pull: always
 steps:
 steps:
 - commands:
 - commands:
-  - aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin
-    084037375216.dkr.ecr.us-east-2.amazonaws.com
-  - ./ci/scripts/build.sh sid amd64 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT}
+  - ./ci/scripts/build.sh bullseye debian amd64 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT}
   image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
   image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
   name: build
   name: build
+  when:
+    event:
+    - push
+- commands:
+  - ./ci/scripts/build.sh bullseye debian amd64 ${DRONE_TAG} ${DRONE_BUILD_EVENT}
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
+  name: release
+  when:
+    event:
+    - tag
+- commands:
+  - ./ci/scripts/publish.sh bullseye debian amd64 100.0.0+${DRONE_COMMIT_SHA:0:8}
+    ${DRONE_BUILD_EVENT}
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
+  name: copy build
+  volumes:
+  - name: zerotier-builds
+    path: /zerotier-builds
+  when:
+    event:
+    - push
+- commands:
+  - ./ci/scripts/publish.sh bullseye debian amd64 ${DRONE_TAG} ${DRONE_BUILD_EVENT}
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
+  name: copy relase
+  volumes:
+  - name: zerotier-releases
+    path: /zerotier-releases
+  when:
+    event:
+    - tag
 trigger:
 trigger:
   event:
   event:
   - push
   - push
   - tag
   - tag
   - custom
   - custom
 type: docker
 type: docker
+volumes:
+- host:
+    path: /zerotier-builds
+  name: zerotier-builds
+- host:
+    path: /zerotier-releases
+  name: zerotier-releases
 ---
 ---
 clone:
 clone:
   depth: 1
   depth: 1
 kind: pipeline
 kind: pipeline
-name: sid arm64 build
+name: bullseye arm64 build
 platform:
 platform:
   arch: arm64
   arch: arm64
   os: linux
   os: linux
 pull: always
 pull: always
 steps:
 steps:
 - commands:
 - commands:
-  - aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin
-    084037375216.dkr.ecr.us-east-2.amazonaws.com
-  - ./ci/scripts/build.sh sid arm64 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT}
+  - ./ci/scripts/build.sh bullseye debian arm64 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT}
   image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
   image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
   name: build
   name: build
+  when:
+    event:
+    - push
+- commands:
+  - ./ci/scripts/build.sh bullseye debian arm64 ${DRONE_TAG} ${DRONE_BUILD_EVENT}
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
+  name: release
+  when:
+    event:
+    - tag
+- commands:
+  - ./ci/scripts/publish.sh bullseye debian arm64 100.0.0+${DRONE_COMMIT_SHA:0:8}
+    ${DRONE_BUILD_EVENT}
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
+  name: copy build
+  volumes:
+  - name: zerotier-builds
+    path: /zerotier-builds
+  when:
+    event:
+    - push
+- commands:
+  - ./ci/scripts/publish.sh bullseye debian arm64 ${DRONE_TAG} ${DRONE_BUILD_EVENT}
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
+  name: copy relase
+  volumes:
+  - name: zerotier-releases
+    path: /zerotier-releases
+  when:
+    event:
+    - tag
 trigger:
 trigger:
   event:
   event:
   - push
   - push
   - tag
   - tag
   - custom
   - custom
 type: docker
 type: docker
+volumes:
+- host:
+    path: /zerotier-builds
+  name: zerotier-builds
+- host:
+    path: /zerotier-releases
+  name: zerotier-releases
 ---
 ---
 clone:
 clone:
   depth: 1
   depth: 1
+depends_on:
+- bullseye 386 build
+- bullseye armv7 build
+- bullseye amd64 build
+- bullseye arm64 build
 kind: pipeline
 kind: pipeline
-name: sid mips64le build
+name: bullseye index
+platform:
+  os: linux
 pull: always
 pull: always
 steps:
 steps:
 - commands:
 - commands:
-  - aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin
-    084037375216.dkr.ecr.us-east-2.amazonaws.com
-  - ./ci/scripts/build.sh sid mips64le 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT}
+  - /usr/local/bin/index zerotier-builds debian bullseye 386 armv7 amd64 arm64
+  environment:
+    GPG_PRIVATE_KEY:
+      from_secret: gpg-private-key
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/apt-builder
+  name: index build
+  volumes:
+  - name: zerotier-builds
+    path: /zerotier-builds
+  when:
+    event:
+    - push
+- commands:
+  - /usr/local/bin/index zerotier-releases debian bullseye 386 armv7 amd64 arm64
+  environment:
+    GPG_PRIVATE_KEY:
+      from_secret: gpg-private-key
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/apt-builder
+  name: index release
+  volumes:
+  - name: zerotier-releases
+    path: /zerotier-releases
+  when:
+    event:
+    - tag
+trigger:
+  event:
+  - push
+  - tag
+  - custom
+type: docker
+volumes:
+- host:
+    path: /zerotier-builds
+  name: zerotier-builds
+- host:
+    path: /zerotier-releases
+  name: zerotier-releases
+---
+clone:
+  depth: 1
+depends_on:
+- bullseye index
+kind: pipeline
+name: bullseye 386 test
+platform:
+  os: linux
+pull: always
+steps:
+- commands:
+  - ./ci/scripts/test.sh bullseye debian 386 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT}
   image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
   image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
-  name: build
+  name: test build
+  volumes:
+  - name: zerotier-builds
+    path: /zerotier-builds
+  when:
+    event:
+    - push
+- commands:
+  - ./ci/scripts/test.sh bullseye debian 386 ${DRONE_TAG} ${DRONE_BUILD_EVENT}
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
+  name: test release
+  volumes:
+  - name: zerotier-releases
+    path: /zerotier-releases
+  when:
+    event:
+    - tag
 trigger:
 trigger:
   event:
   event:
   - push
   - push
   - tag
   - tag
   - custom
   - custom
 type: docker
 type: docker
+volumes:
+- host:
+    path: /zerotier-builds
+  name: zerotier-builds
+- host:
+    path: /zerotier-releases
+  name: zerotier-releases
 ---
 ---
 clone:
 clone:
   depth: 1
   depth: 1
+depends_on:
+- bullseye index
 kind: pipeline
 kind: pipeline
-name: sid ppc64le build
+name: bullseye armv7 test
+platform:
+  arch: arm64
+  os: linux
 pull: always
 pull: always
 steps:
 steps:
 - commands:
 - commands:
-  - aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin
-    084037375216.dkr.ecr.us-east-2.amazonaws.com
-  - ./ci/scripts/build.sh sid ppc64le 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT}
+  - ./ci/scripts/test.sh bullseye debian armv7 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT}
   image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
   image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
-  name: build
+  name: test build
+  volumes:
+  - name: zerotier-builds
+    path: /zerotier-builds
+  when:
+    event:
+    - push
+- commands:
+  - ./ci/scripts/test.sh bullseye debian armv7 ${DRONE_TAG} ${DRONE_BUILD_EVENT}
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
+  name: test release
+  volumes:
+  - name: zerotier-releases
+    path: /zerotier-releases
+  when:
+    event:
+    - tag
 trigger:
 trigger:
   event:
   event:
   - push
   - push
   - tag
   - tag
   - custom
   - custom
 type: docker
 type: docker
+volumes:
+- host:
+    path: /zerotier-builds
+  name: zerotier-builds
+- host:
+    path: /zerotier-releases
+  name: zerotier-releases
 ---
 ---
 clone:
 clone:
   depth: 1
   depth: 1
+depends_on:
+- bullseye index
 kind: pipeline
 kind: pipeline
-name: sid s390x build
+name: bullseye amd64 test
+platform:
+  os: linux
 pull: always
 pull: always
 steps:
 steps:
 - commands:
 - commands:
-  - aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin
-    084037375216.dkr.ecr.us-east-2.amazonaws.com
-  - ./ci/scripts/build.sh sid s390x 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT}
+  - ./ci/scripts/test.sh bullseye debian amd64 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT}
   image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
   image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
-  name: build
+  name: test build
+  volumes:
+  - name: zerotier-builds
+    path: /zerotier-builds
+  when:
+    event:
+    - push
+- commands:
+  - ./ci/scripts/test.sh bullseye debian amd64 ${DRONE_TAG} ${DRONE_BUILD_EVENT}
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
+  name: test release
+  volumes:
+  - name: zerotier-releases
+    path: /zerotier-releases
+  when:
+    event:
+    - tag
 trigger:
 trigger:
   event:
   event:
   - push
   - push
   - tag
   - tag
   - custom
   - custom
 type: docker
 type: docker
+volumes:
+- host:
+    path: /zerotier-builds
+  name: zerotier-builds
+- host:
+    path: /zerotier-releases
+  name: zerotier-releases
 ---
 ---
 clone:
 clone:
   depth: 1
   depth: 1
+depends_on:
+- bullseye index
 kind: pipeline
 kind: pipeline
-name: sid riscv64 build
+name: bullseye arm64 test
+platform:
+  arch: arm64
+  os: linux
 pull: always
 pull: always
 steps:
 steps:
 - commands:
 - commands:
-  - aws ecr get-login-password --region us-east-2 | docker login --username AWS --password-stdin
-    084037375216.dkr.ecr.us-east-2.amazonaws.com
-  - ./ci/scripts/build.sh sid riscv64 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT}
+  - ./ci/scripts/test.sh bullseye debian arm64 100.0.0+${DRONE_COMMIT_SHA:0:8} ${DRONE_BUILD_EVENT}
   image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
   image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
-  name: build
+  name: test build
+  volumes:
+  - name: zerotier-builds
+    path: /zerotier-builds
+  when:
+    event:
+    - push
+- commands:
+  - ./ci/scripts/test.sh bullseye debian arm64 ${DRONE_TAG} ${DRONE_BUILD_EVENT}
+  image: 084037375216.dkr.ecr.us-east-2.amazonaws.com/honda-builder
+  name: test release
+  volumes:
+  - name: zerotier-releases
+    path: /zerotier-releases
+  when:
+    event:
+    - tag
 trigger:
 trigger:
   event:
   event:
   - push
   - push
   - tag
   - tag
   - custom
   - custom
 type: docker
 type: docker
+volumes:
+- host:
+    path: /zerotier-builds
+  name: zerotier-builds
+- host:
+    path: /zerotier-releases
+  name: zerotier-releases
+---
+kind: signature
+hmac: 887a3ef78d3fe8f0149911e1e4876401dd7dd313b36eb893e791fa42f45d7768
+
+...

+ 20 - 29
.github/workflows/build.yml

@@ -14,22 +14,19 @@ jobs:
       uses: actions-rs/toolchain@v1
       uses: actions-rs/toolchain@v1
       with:
       with:
         toolchain: stable
         toolchain: stable
-        target: aarch64-apple-darwin
+        target: x86_64-unknown-linux-gnu
         override: true
         override: true
         components: rustfmt, clippy
         components: rustfmt, clippy
 
 
     - name: Set up cargo cache
     - name: Set up cargo cache
-      uses: actions/cache@v3
+      uses: Swatinem/rust-cache@v2
       continue-on-error: false
       continue-on-error: false
       with:
       with:
-        path: |
-          ~/.cargo/bin/
-          ~/.cargo/registry/index/
-          ~/.cargo/registry/cache/
-          ~/.cargo/git/db/
-          target/
-        key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
-        restore-keys: ${{ runner.os }}-cargo-
+        key: ${{ runner.os }}-cargo-${{ hashFiles('zeroidc//Cargo.lock') }}
+        shared-key: ${{ runner.os }}-cargo-
+        workspaces: |
+          zeroidc/
+
     - name: make
     - name: make
       run: make
       run: make
     - name: selftest
     - name: selftest
@@ -54,17 +51,14 @@ jobs:
         override: true
         override: true
         components: rustfmt, clippy
         components: rustfmt, clippy
     - name: Set up cargo cache
     - name: Set up cargo cache
-      uses: actions/cache@v3
+      uses: Swatinem/rust-cache@v2
       continue-on-error: false
       continue-on-error: false
       with:
       with:
-        path: |
-          ~/.cargo/bin/
-          ~/.cargo/registry/index/
-          ~/.cargo/registry/cache/
-          ~/.cargo/git/db/
-          target/
-        key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
-        restore-keys: ${{ runner.os }}-cargo-
+        key: ${{ runner.os }}-cargo-${{ hashFiles('zeroidc//Cargo.lock') }}
+        shared-key: ${{ runner.os }}-cargo-
+        workspaces: |
+          zeroidc/
+
     - name: make
     - name: make
       run: make
       run: make
     - name: selftest
     - name: selftest
@@ -89,19 +83,16 @@ jobs:
         override: true
         override: true
         components: rustfmt, clippy
         components: rustfmt, clippy
     - name: Set up cargo cache
     - name: Set up cargo cache
-      uses: actions/cache@v3
+      uses: Swatinem/rust-cache@v2
       continue-on-error: false
       continue-on-error: false
       with:
       with:
-        path: |
-          ~/.cargo/bin/
-          ~/.cargo/registry/index/
-          ~/.cargo/registry/cache/
-          ~/.cargo/git/db/
-          target/
-        key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
-        restore-keys: ${{ runner.os }}-cargo-
+        key: ${{ runner.os }}-cargo-${{ hashFiles('zeroidc//Cargo.lock') }}
+        shared-key: ${{ runner.os }}-cargo-
+        workspaces: |
+          zeroidc/
+
     - name: setup msbuild
     - name: setup msbuild
       uses: microsoft/[email protected]
       uses: microsoft/[email protected]
     - name: msbuild
     - name: msbuild
       run: |
       run: |
-        msbuild windows\ZeroTierOne.sln /m /p:Configuration=Release  /property:Platform=x64 /t:ZeroTierOne:Rebuild        
+        msbuild windows\ZeroTierOne.sln /m /p:Configuration=Release  /property:Platform=x64 /t:ZeroTierOne        

+ 461 - 0
.github/workflows/validate-linux.sh

@@ -0,0 +1,461 @@
+#!/bin/bash
+
+# This test script joins Earth and pokes some stuff
+
+TEST_NETWORK=8056c2e21c000001
+RUN_LENGTH=30
+TEST_FINISHED=false
+ZTO_VER=$(git describe --tags $(git rev-list --tags --max-count=1))
+ZTO_COMMIT=$(git rev-parse HEAD)
+ZTO_COMMIT_SHORT=$(git rev-parse --short HEAD)
+TEST_DIR_PREFIX="$ZTO_VER-$ZTO_COMMIT_SHORT-test-results"
+
+TEST_OK=0
+TEST_FAIL=1
+
+echo "Performing test on: $ZTO_VER-$ZTO_COMMIT_SHORT"
+TEST_FILEPATH_PREFIX="$TEST_DIR_PREFIX/$ZTO_COMMIT_SHORT"
+mkdir $TEST_DIR_PREFIX
+
+# How long we will wait for ZT to come online before considering it a failure
+MAX_WAIT_SECS=30
+
+################################################################################
+# Multi-node connectivity and performance test                                 #
+################################################################################
+
+test() {
+
+	echo -e "\nPerforming pre-flight checks"
+
+	check_exit_on_invalid_identity
+
+	echo -e "\nRunning test for $RUN_LENGTH seconds"
+
+	export NS1="ip netns exec ns1"
+	export NS2="ip netns exec ns2"
+
+	export ZT1="$NS1 ./zerotier-cli -p9996 -D$(pwd)/node1"
+	# Specify custom port on one node to ensure that feature works
+	export ZT2="$NS2 ./zerotier-cli -p9997 -D$(pwd)/node2"
+
+	echo -e "\nSetting up network namespaces..."
+	echo "Setting up ns1"
+
+	ip netns add ns1
+	$NS1 ip link set dev lo up
+	ip link add veth0 type veth peer name veth1
+	ip link set veth1 netns ns1
+	ip addr add 192.168.0.1/24 dev veth0
+	ip link set dev veth0 up
+
+	$NS1 ip addr add 192.168.0.2/24 dev veth1
+	$NS1 ip link set dev veth1 up
+
+	# Add default route
+	$NS1 ip route add default via 192.168.0.1
+
+	iptables -t nat -A POSTROUTING -s 192.168.0.0/255.255.255.0 \
+		-o eth0 -j MASQUERADE
+	iptables -A FORWARD -i eth0 -o veth0 -j ACCEPT
+	iptables -A FORWARD -o eth0 -i veth0 -j ACCEPT
+
+	echo "Setting up ns2"
+	ip netns add ns2
+	$NS2 ip link set dev lo up
+	ip link add veth2 type veth peer name veth3
+	ip link set veth3 netns ns2
+	ip addr add 192.168.1.1/24 dev veth2
+	ip link set dev veth2 up
+
+	$NS2 ip addr add 192.168.1.2/24 dev veth3
+	$NS2 ip link set dev veth3 up
+	$NS2 ip route add default via 192.168.1.1
+
+	iptables -t nat -A POSTROUTING -s 192.168.1.0/255.255.255.0 \
+		-o eth0 -j MASQUERADE
+	iptables -A FORWARD -i eth0 -o veth2 -j ACCEPT
+	iptables -A FORWARD -o eth0 -i veth2 -j ACCEPT
+
+	# Allow forwarding
+	sysctl -w net.ipv4.ip_forward=1
+
+	################################################################################
+	# Memory Leak Check                                                            #
+	################################################################################
+
+	export FILENAME_MEMORY_LOG="$TEST_FILEPATH_PREFIX-memory.log"
+
+	echo -e "\nStarting a ZeroTier instance in each namespace..."
+
+	export time_test_start=$(date +%s)
+
+	# Spam the CLI as ZeroTier is starting
+	spam_cli 100
+
+	echo "Starting memory leak check"
+	$NS1 sudo valgrind --demangle=yes --exit-on-first-error=yes \
+		--error-exitcode=1 \
+		--xml=yes \
+		--xml-file=$FILENAME_MEMORY_LOG \
+		--leak-check=full \
+		./zerotier-one node1 -p9996 -U >>node_1.log 2>&1 &
+
+	# Second instance, not run in memory profiler
+	# Don't set up internet access until _after_ zerotier is running
+	# This has been a source of stuckness in the past.
+	$NS2 ip addr del 192.168.1.2/24 dev veth3
+	$NS2 sudo ./zerotier-one node2 -U -p9997 >>node_2.log 2>&1 &
+	sleep 1;
+	$NS2 ip addr add 192.168.1.2/24 dev veth3
+	$NS2 ip route add default via 192.168.1.1
+
+	echo -e "\nPing from host to namespaces"
+
+	ping -c 3 192.168.0.1
+	ping -c 3 192.168.1.1
+
+	echo -e "\nPing from namespace to host"
+
+	$NS1 ping -c 3 192.168.0.1
+	$NS1 ping -c 3 192.168.0.1
+	$NS2 ping -c 3 192.168.0.2
+	$NS2 ping -c 3 192.168.0.2
+
+	echo -e "\nPing from ns1 to ns2"
+
+	$NS1 ping -c 3 192.168.0.1
+
+	echo -e "\nPing from ns2 to ns1"
+
+	$NS2 ping -c 3 192.168.0.1
+
+	################################################################################
+	# Online Check                                                                 #
+	################################################################################
+
+	echo "Waiting for ZeroTier to come online before attempting test..."
+	node1_online=false
+	node2_online=false
+	both_instances_online=false
+	time_zt_node1_start=$(date +%s)
+	time_zt_node2_start=$(date +%s)
+
+	for ((s = 0; s <= $MAX_WAIT_SECS; s++)); do
+		node1_online="$($ZT1 -j info | jq '.online' 2>/dev/null)"
+		node2_online="$($ZT2 -j info | jq '.online' 2>/dev/null)"
+		echo "Checking for online status: try #$s, node1:$node1_online, node2:$node2_online"
+		if [[ "$node2_online" == "true" && "$node1_online" == "true" ]]; then
+			export both_instances_online=true
+			export time_to_both_nodes_online=$(date +%s)
+			break
+		fi
+		sleep 1
+	done
+
+	echo -e "\n\nContents of ZeroTier home paths:"
+
+	ls -lga node1
+	tree node1
+	ls -lga node2
+	tree node2
+
+	echo -e "\n\nRunning ZeroTier processes:"
+	echo -e "\nNode 1:\n"
+	$NS1 ps aux | grep zerotier-one
+	echo -e "\nNode 2:\n"
+	$NS2 ps aux | grep zerotier-one
+
+	echo -e "\n\nStatus of each instance:"
+
+	echo -e "\n\nNode 1:\n"
+	$ZT1 status
+	echo -e "\n\nNode 2:\n"
+	$ZT2 status
+
+	if [[ "$both_instances_online" != "true" ]]; then
+		exit_test_and_generate_report $TEST_FAIL "one or more nodes failed to come online"
+	fi
+
+	echo -e "\nJoining networks"
+
+	$ZT1 join $TEST_NETWORK
+	$ZT2 join $TEST_NETWORK
+
+	sleep 10
+
+	node1_ip4=$($ZT1 get $TEST_NETWORK ip4)
+	node2_ip4=$($ZT2 get $TEST_NETWORK ip4)
+
+	echo "node1_ip4=$node1_ip4"
+	echo "node2_ip4=$node2_ip4"
+
+	echo -e "\nPinging each node"
+
+	PING12_FILENAME="$TEST_FILEPATH_PREFIX-ping-1-to-2.txt"
+	PING21_FILENAME="$TEST_FILEPATH_PREFIX-ping-2-to-1.txt"
+
+	$NS1 ping -c 16 $node2_ip4 >$PING12_FILENAME
+	$NS2 ping -c 16 $node1_ip4 >$PING21_FILENAME
+
+	ping_loss_percent_1_to_2=$(cat $PING12_FILENAME |
+		grep "packet loss" | awk '{print $6}' | sed 's/%//')
+	ping_loss_percent_2_to_1=$(cat $PING21_FILENAME |
+		grep "packet loss" | awk '{print $6}' | sed 's/%//')
+
+	# Normalize loss value
+	export ping_loss_percent_1_to_2=$(echo "scale=2; $ping_loss_percent_1_to_2/100.0" | bc)
+	export ping_loss_percent_2_to_1=$(echo "scale=2; $ping_loss_percent_2_to_1/100.0" | bc)
+
+	################################################################################
+	# CLI Check                                                                    #
+	################################################################################
+
+	echo "Testing basic CLI functionality..."
+
+	spam_cli 10
+
+	$ZT1 join $TEST_NETWORK
+
+	$ZT1 -h
+	$ZT1 -v
+	$ZT1 status
+	$ZT1 info
+	$ZT1 listnetworks
+	$ZT1 peers
+	$ZT1 listpeers
+
+	$ZT1 -j status
+	$ZT1 -j info
+	$ZT1 -j listnetworks
+	$ZT1 -j peers
+	$ZT1 -j listpeers
+
+	$ZT1 dump
+
+	$ZT1 get $TEST_NETWORK allowDNS
+	$ZT1 get $TEST_NETWORK allowDefault
+	$ZT1 get $TEST_NETWORK allowGlobal
+	$ZT1 get $TEST_NETWORK allowManaged
+	$ZT1 get $TEST_NETWORK bridge
+	$ZT1 get $TEST_NETWORK broadcastEnabled
+	$ZT1 get $TEST_NETWORK dhcp
+	$ZT1 get $TEST_NETWORK id
+	$ZT1 get $TEST_NETWORK mac
+	$ZT1 get $TEST_NETWORK mtu
+	$ZT1 get $TEST_NETWORK name
+	$ZT1 get $TEST_NETWORK netconfRevision
+	$ZT1 get $TEST_NETWORK nwid
+	$ZT1 get $TEST_NETWORK portDeviceName
+	$ZT1 get $TEST_NETWORK portError
+	$ZT1 get $TEST_NETWORK status
+	$ZT1 get $TEST_NETWORK type
+
+	# Test an invalid command
+	$ZT1 get $TEST_NETWORK derpderp
+
+	# TODO: Validate JSON
+
+	# Performance Test
+
+	export FILENAME_PERF_JSON="$TEST_FILEPATH_PREFIX-iperf.json"
+
+	echo -e "\nBeginning performance test:"
+
+	echo -e "\nStarting server:"
+
+	echo "$NS1 iperf3 -s &"
+	sleep 1
+
+	echo -e "\nStarting client:"
+	sleep 1
+
+	echo "$NS2 iperf3 --json -c $node1_ip4 > $FILENAME_PERF_JSON"
+
+	cat $FILENAME_PERF_JSON
+
+	# Let ZeroTier idle long enough for various timers
+
+	echo -e "\nIdling ZeroTier for $RUN_LENGTH seconds..."
+	sleep $RUN_LENGTH
+
+	echo -e "\nLeaving networks"
+
+	$ZT1 leave $TEST_NETWORK
+	$ZT2 leave $TEST_NETWORK
+
+	sleep 5
+
+	exit_test_and_generate_report $TEST_OK "completed test"
+}
+
+################################################################################
+# Generate report                                                              #
+################################################################################
+
+exit_test_and_generate_report() {
+
+	echo -e "\nStopping memory check..."
+	sudo pkill -15 -f valgrind
+	sleep 10
+
+	time_test_end=$(date +%s)
+
+	echo "Exiting test with reason: $2 ($1)"
+
+	# Collect ZeroTier dump files
+
+	echo -e "\nCollecting ZeroTier dump files"
+
+	node1_id=$($ZT1 -j status | jq -r .address)
+	node2_id=$($ZT2 -j status | jq -r .address)
+
+	$ZT1 dump
+	mv zerotier_dump.txt "$TEST_FILEPATH_PREFIX-node-dump-$node1_id.txt"
+
+	$ZT2 dump
+	mv zerotier_dump.txt "$TEST_FILEPATH_PREFIX-node-dump-$node2_id.txt"
+
+	# Copy ZeroTier stdout/stderr logs
+
+	cp node_1.log "$TEST_FILEPATH_PREFIX-node-log-$node1_id.txt"
+	cp node_2.log "$TEST_FILEPATH_PREFIX-node-log-$node2_id.txt"
+
+	# Generate report
+
+	cat $FILENAME_MEMORY_LOG
+
+	DEFINITELY_LOST=$(xmlstarlet sel -t -v '/valgrindoutput/error/xwhat' \
+		$FILENAME_MEMORY_LOG | grep "definitely" | awk '{print $1;}')
+	POSSIBLY_LOST=$(xmlstarlet sel -t -v '/valgrindoutput/error/xwhat' \
+		$FILENAME_MEMORY_LOG | grep "possibly" | awk '{print $1;}')
+
+	# Generate coverage report artifact and summary
+
+	FILENAME_COVERAGE_JSON="$TEST_FILEPATH_PREFIX-coverage.json"
+	FILENAME_COVERAGE_HTML="$TEST_FILEPATH_PREFIX-coverage.html"
+
+	echo -e "\nGenerating coverage test report..."
+
+	gcovr -r . --exclude ext --json-summary $FILENAME_COVERAGE_JSON \
+		--html >$FILENAME_COVERAGE_HTML
+
+	cat $FILENAME_COVERAGE_JSON
+
+	COVERAGE_LINE_COVERED=$(cat $FILENAME_COVERAGE_JSON | jq .line_covered)
+	COVERAGE_LINE_TOTAL=$(cat $FILENAME_COVERAGE_JSON | jq .line_total)
+	COVERAGE_LINE_PERCENT=$(cat $FILENAME_COVERAGE_JSON | jq .line_percent)
+
+	COVERAGE_LINE_COVERED="${COVERAGE_LINE_COVERED:-0}"
+	COVERAGE_LINE_TOTAL="${COVERAGE_LINE_TOTAL:-0}"
+	COVERAGE_LINE_PERCENT="${COVERAGE_LINE_PERCENT:-0}"
+
+	# Default values
+
+	DEFINITELY_LOST="${DEFINITELY_LOST:-0}"
+	POSSIBLY_LOST="${POSSIBLY_LOST:-0}"
+	ping_loss_percent_1_to_2="${ping_loss_percent_1_to_2:-100.0}"
+	ping_loss_percent_2_to_1="${ping_loss_percent_2_to_1:-100.0}"
+	time_to_both_nodes_online="${time_to_both_nodes_online:--1}"
+
+	# Summarize and emit json for trend reporting
+
+	FILENAME_SUMMARY="$TEST_FILEPATH_PREFIX-summary.json"
+
+	time_length_test=$((time_test_end - time_test_start))
+	if [[ $time_to_both_nodes_online != -1 ]];
+	then
+		time_to_both_nodes_online=$((time_to_both_nodes_online - time_test_start))
+	fi
+	#time_length_zt_join=$((time_zt_join_end-time_zt_join_start))
+	#time_length_zt_leave=$((time_zt_leave_end-time_zt_leave_start))
+	#time_length_zt_can_still_ping=$((time_zt_can_still_ping-time_zt_leave_start))
+
+	summary=$(
+		cat <<EOF
+{
+  "version":"$ZTO_VER",
+  "commit":"$ZTO_COMMIT",
+  "arch_m":"$(uname -m)",
+  "arch_a":"$(uname -a)",
+  "binary_size":"$(stat -c %s zerotier-one)",
+  "time_length_test":$time_length_test,
+  "time_to_both_nodes_online":$time_to_both_nodes_online,
+  "num_possible_bytes_lost": $POSSIBLY_LOST,
+  "num_definite_bytes_lost": $DEFINITELY_LOST,
+  "num_bad_formattings": $POSSIBLY_LOST,
+  "coverage_lines_covered": $COVERAGE_LINE_COVERED,
+  "coverage_lines_total": $COVERAGE_LINE_TOTAL,
+  "coverage_lines_percent": $COVERAGE_LINE_PERCENT,
+  "ping_loss_percent_1_to_2": $ping_loss_percent_1_to_2,
+  "ping_loss_percent_2_to_1": $ping_loss_percent_2_to_1,
+  "test_exit_code": $1,
+  "test_exit_reason":"$2"
+}
+EOF
+	)
+
+	echo $summary >$FILENAME_SUMMARY
+	cat $FILENAME_SUMMARY
+
+	exit 0
+}
+
+################################################################################
+# CLI Check                                                                    #
+################################################################################
+
+spam_cli() {
+	echo "Spamming CLI..."
+	# Rapidly spam the CLI with joins/leaves
+
+	MAX_TRIES="${1:-10}"
+
+	for ((s = 0; s <= MAX_TRIES; s++)); do
+		$ZT1 status
+		$ZT2 status
+		sleep 0.1
+	done
+
+	SPAM_TRIES=128
+
+	for ((s = 0; s <= SPAM_TRIES; s++)); do
+		$ZT1 join $TEST_NETWORK
+	done
+
+	for ((s = 0; s <= SPAM_TRIES; s++)); do
+		$ZT1 leave $TEST_NETWORK
+	done
+
+	for ((s = 0; s <= SPAM_TRIES; s++)); do
+		$ZT1 leave $TEST_NETWORK
+		$ZT1 join $TEST_NETWORK
+	done
+}
+
+################################################################################
+# Check for proper exit on load of invalid identity                            #
+################################################################################
+
+check_exit_on_invalid_identity() {
+	echo "Checking ZeroTier exits on invalid identity..."
+	mkdir -p $(pwd)/exit_test
+	ZT1="sudo ./zerotier-one -p9999 $(pwd)/exit_test"
+	echo "asdfasdfasdfasdf" > $(pwd)/exit_test/identity.secret
+	echo "asdfasdfasdfasdf" > $(pwd)/exit_test/authtoken.secret
+
+	echo "Launch ZeroTier with an invalid identity"
+	$ZT1 &
+	my_pid=$!
+
+	echo "Waiting 5 seconds"
+	sleep 5
+
+	# check if process is running
+	kill -0 $my_pid
+	if [ $? -eq 0 ]; then
+		exit_test_and_generate_report $TEST_FAIL "Exit test FAILED: Process still running after being fed an invalid identity"
+	fi
+}
+
+test "$@"

+ 24 - 0
.github/workflows/validate-report.sh

@@ -0,0 +1,24 @@
+#!/bin/bash
+
+################################################################################
+# Set exit code depending on tool reports                                      #
+################################################################################
+
+DEFINITELY_LOST=$(cat *test-results/*summary.json | jq .num_definite_bytes_lost)
+EXIT_CODE=$(cat *test-results/*summary.json | jq .exit_code)
+EXIT_REASON=$(cat *test-results/*summary.json | jq .exit_reason)
+
+cat *test-results/*summary.json
+
+echo -e "\nBytes of memory definitely lost: $DEFINITELY_LOST"
+
+if [[ "$DEFINITELY_LOST" -gt 0 ]]; then
+      exit 1
+fi
+
+# Catch-all for other non-zero exit codes
+
+if [[ "$EXIT_CODE" -gt 0 ]]; then
+      echo "Test failed: $EXIT_REASON"
+      exit 1
+fi

+ 56 - 0
.github/workflows/validate.yml

@@ -0,0 +1,56 @@
+on:
+  push:
+  workflow_dispatch:
+
+jobs:
+  build_ubuntu:
+    runs-on: ubuntu-latest
+    steps:
+    - name: gitconfig
+      run: |
+        git config --global core.autocrlf input
+
+    - name: checkout
+      uses: actions/checkout@v3
+      with:
+        fetch-depth: 0
+
+    - name: Install Rust
+      uses: actions-rs/toolchain@v1
+      with:
+        toolchain: stable
+        target: x86_64-unknown-linux-gnu
+        override: true
+        components: rustfmt, clippy
+
+    - name: Set up cargo cache
+      uses: Swatinem/rust-cache@v2
+      continue-on-error: false
+      with:
+        key: ${{ runner.os }}-cargo-${{ hashFiles('zeroidc//Cargo.lock') }}
+        shared-key: ${{ runner.os }}-cargo-
+        workspaces: |
+          zeroidc/
+
+    - name: validate-1m-linux
+      env:
+        CC: 'gcc'
+        CXX: 'g++'
+        BRANCH: ${{  github.ref_name }}
+      run: |
+        sudo apt install -y valgrind xmlstarlet gcovr iperf3 tree
+        make one ZT_COVERAGE=1 ZT_TRACE=1
+        sudo chmod +x ./.github/workflows/validate-linux.sh
+        sudo ./.github/workflows/validate-linux.sh
+
+    - name: Archive test results
+      uses: actions/upload-artifact@v3
+      with:
+        name: ${{github.sha}}-test-results
+        path: "*test-results*"
+
+    - name: final-report
+      run: |
+        sudo chmod +x ./.github/workflows/validate-report.sh
+        sudo ./.github/workflows/validate-report.sh
+

+ 14 - 0
.kick

@@ -0,0 +1,14 @@
+kick
+kick
+kick
+kick
+kick
+kick
+kick
+kick
+kick
+kick
+kick
+kick
+kick
+kick

+ 1 - 0
Makefile

@@ -30,3 +30,4 @@ endif
 drone:
 drone:
 	@echo "rendering .drone.yaml from .drone.jsonnet"
 	@echo "rendering .drone.yaml from .drone.jsonnet"
 	drone jsonnet --format --stream
 	drone jsonnet --format --stream
+	drone sign zerotier/ZeroTierOne --save

+ 62 - 2
README.md

@@ -37,7 +37,6 @@ The base path contains the ZeroTier One service main entry point (`one.cpp`), se
  - `ext/`: third party libraries, binaries that we ship for convenience on some platforms (Mac and Windows), and installation support files.
  - `ext/`: third party libraries, binaries that we ship for convenience on some platforms (Mac and Windows), and installation support files.
  - `include/`: include files for the ZeroTier core.
  - `include/`: include files for the ZeroTier core.
  - `java/`: a JNI wrapper used with our Android mobile app. (The whole Android app is not open source but may be made so in the future.)
  - `java/`: a JNI wrapper used with our Android mobile app. (The whole Android app is not open source but may be made so in the future.)
- - `macui/`: a Macintosh menu-bar app for controlling ZeroTier One, written in Objective C.
  - `node/`: the ZeroTier virtual Ethernet switch core, which is designed to be entirely separate from the rest of the code and able to be built as a stand-alone OS-independent library. Note to developers: do not use C++11 features in here, since we want this to build on old embedded platforms that lack C++11 support. C++11 can be used elsewhere.
  - `node/`: the ZeroTier virtual Ethernet switch core, which is designed to be entirely separate from the rest of the code and able to be built as a stand-alone OS-independent library. Note to developers: do not use C++11 features in here, since we want this to build on old embedded platforms that lack C++11 support. C++11 can be used elsewhere.
  - `osdep/`: code to support and integrate with OSes, including platform-specific stuff only built for certain targets.
  - `osdep/`: code to support and integrate with OSes, including platform-specific stuff only built for certain targets.
  - `rule-compiler/`: JavaScript rules language compiler for defining network-level rules.
  - `rule-compiler/`: JavaScript rules language compiler for defining network-level rules.
@@ -61,6 +60,7 @@ To build on Mac and Linux just type `make`. On FreeBSD and OpenBSD `gmake` (GNU
    - Rust for x86_64 and ARM64 targets *if SSO is enabled in the build*.
    - 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.
+   - `binutils` is required.  Type `pkg install binutils` to install.
    - Rust for x86_64 and ARM64 targets *if SSO is enabled in the 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`).
@@ -104,8 +104,68 @@ On CentOS check `/etc/sysconfig/iptables` for IPTables rules. For other distribu
 
 
 ZeroTier One peers will automatically locate each other and communicate directly over a local wired LAN *if UDP port 9993 inbound is open*. If that port is filtered, they won't be able to see each others' LAN announcement packets. If you're experiencing poor performance between devices on the same physical network, check their firewall settings. Without LAN auto-location peers must attempt "loopback" NAT traversal, which sometimes fails and in any case requires that every packet traverse your external router twice.
 ZeroTier One peers will automatically locate each other and communicate directly over a local wired LAN *if UDP port 9993 inbound is open*. If that port is filtered, they won't be able to see each others' LAN announcement packets. If you're experiencing poor performance between devices on the same physical network, check their firewall settings. Without LAN auto-location peers must attempt "loopback" NAT traversal, which sometimes fails and in any case requires that every packet traverse your external router twice.
 
 
-Users behind certain types of firewalls and "symmetric" NAT devices may not able able to connect to external peers directly at all. ZeroTier has limited support for port prediction and will *attempt* to traverse symmetric NATs, but this doesn't always work. If P2P connectivity fails you'll be bouncing UDP packets off our relay servers resulting in slower performance. Some NAT router(s) have a configurable NAT mode, and setting this to "full cone" will eliminate this problem. If you do this you may also see a magical improvement for things like VoIP phones, Skype, BitTorrent, WebRTC, certain games, etc., since all of these use NAT traversal techniques similar to ours.
+Users behind certain types of firewalls and "symmetric" NAT devices may not be able to connect to external peers directly at all. ZeroTier has limited support for port prediction and will *attempt* to traverse symmetric NATs, but this doesn't always work. If P2P connectivity fails you'll be bouncing UDP packets off our relay servers resulting in slower performance. Some NAT router(s) have a configurable NAT mode, and setting this to "full cone" will eliminate this problem. If you do this you may also see a magical improvement for things like VoIP phones, Skype, BitTorrent, WebRTC, certain games, etc., since all of these use NAT traversal techniques similar to ours.
 
 
 If a firewall between you and the Internet blocks ZeroTier's UDP traffic, you will fall back to last-resort TCP tunneling to rootservers over port 443 (https impersonation). This will work almost anywhere but is *very slow* compared to UDP or direct peer to peer connectivity.
 If a firewall between you and the Internet blocks ZeroTier's UDP traffic, you will fall back to last-resort TCP tunneling to rootservers over port 443 (https impersonation). This will work almost anywhere but is *very slow* compared to UDP or direct peer to peer connectivity.
 
 
 Additional help can be found in our [knowledge base](https://zerotier.atlassian.net/wiki/spaces/SD/overview).
 Additional help can be found in our [knowledge base](https://zerotier.atlassian.net/wiki/spaces/SD/overview).
+
+### Prometheus Metrics
+
+Prometheus Metrics are available at the `/metrics` API endpoint.  This endpoint is protected by an API key stored in `metricstoken.secret` to prevent unwanted information leakage.  Information that could be gleaned from the metrics include joined networks and peers your instance is talking to. 
+
+Access control is via the ZeroTier control interface itself and `metricstoken.secret`. This can be sent as a bearer auth token, via the `X-ZT1-Auth` HTTP header field, or appended to the URL as `?auth=<token>`. You can see the current metrics via `cURL` with the following command:
+
+    // Linux
+    curl -H "X-ZT1-Auth: $(sudo cat /var/lib/zerotier-one/metricstoken.secret)" http://localhost:9993/metrics
+
+    // macOS
+    curl -H "X-XT1-Auth: $(sudo cat /Library/Application\ Support/ZeroTier/One/metricstoken.secret)" http://localhost:9993/metrics
+
+    // Windows PowerShell (Admin)
+    Invoke-RestMethod -Headers @{'X-ZT1-Auth' = "$(Get-Content C:\ProgramData\ZeroTier\One\metricstoken.secret)"; } -Uri http://localhost:9993/metrics
+
+To configure a scrape job in Prometheus on the machine ZeroTier is running on, add this to your Prometheus `scrape_config`:
+
+    - job_name: zerotier-one
+      honor_labels: true
+      scrape_interval: 15s
+      metrics_path: /metrics
+      static_configs:
+      - targets:
+        - 127.0.0.1:9993
+        labels:
+          group: zerotier-one
+          node_id: $YOUR_10_CHARACTER_NODE_ID
+      authorization:
+        credentials: $YOUR_METRICS_TOKEN_SECRET
+
+If neither of these methods are desirable, it is probably possible to distribute metrics via [Prometheus Proxy](https://github.com/pambrose/prometheus-proxy) or some other tool.  Note: We have not tested this internally, but will probably work with the correct configuration.
+
+Metrics are also available on disk in ZeroTier's working directory:
+
+   // Linux
+   /var/lib/zerotier-one/metrics.prom
+
+   // macOS
+   /Library/Application\ Support/ZeroTier/One/metrics.prom
+
+   //Windows
+   C:\ProgramData\ZeroTier\One\metrics.prom
+
+#### Available Metrics
+
+| Metric Name | Labels | Metric Type | Description |
+| ---         | ---    | ---         | ---         |
+| zt_packet | packet_type, direction | Counter | ZeroTier packet type counts |
+| zt_packet_error | error_type, direction | Counter | ZeroTier packet errors|
+| zt_data | protocol, direction | Counter | number of bytes ZeroTier has transmitted or received |
+| zt_num_networks | | Gauge | number of networks this instance is joined to |
+| zt_network_multicast_groups_subscribed | network_id | Gauge | number of multicast groups networks are subscribed to |
+| zt_network_packets | network_id, direction | Counter | number of incoming/outgoing packets per network |
+| zt_peer_latency | node_id | Histogram | peer latency (ms) |
+| zt_peer_path_count | node_id, status | Gauge | number of paths to peer |
+| zt_peer_packets | node_id, direction | Counter | number of packets to/from a peer |
+| zt_peer_packet_errors | node_id | Counter | number of incoming packet errors from a peer |
+
+If there are other metrics you'd like to see tracked, ask us in an Issue or send us a Pull Request!

+ 16 - 0
RELEASE-NOTES.md

@@ -1,6 +1,22 @@
 ZeroTier Release Notes
 ZeroTier Release Notes
 ======
 ======
 
 
+# 2023-08-23 -- Version 1.12.0
+
+  * Experimental Windows ARM64 support
+  * Fix numerous sleep/wake issues on macOS and other platforms
+  * Faster recovery after changes to physical network settings
+  * Prometheus compatible metrics support!
+  * Fix full tunnel mode on recent macOS versions
+  * Numerous macOS DNS fixes
+  * 10-30% speed improvement on Linux
+
+# 2023-03-23 -- Version 1.10.6
+
+  * Prevent binding temporary ipv6 addresses on macos (#1910)
+  * Prevent path-learning loops (#1914)
+  * Prevent infinite loop of UAC prompts in tray app
+
 # 2023-03-10 -- Version 1.10.5
 # 2023-03-10 -- Version 1.10.5
 
 
  * Fix for high CPU usage bug on Windows
  * Fix for high CPU usage bug on Windows

+ 1 - 1
attic/world/build.sh

@@ -1,3 +1,3 @@
 #!/bin/bash
 #!/bin/bash
 
 
-c++ -std=c++11 -I../.. -I.. -g -o mkworld ../../node/C25519.cpp ../../node/Salsa20.cpp ../../node/SHA512.cpp ../../node/Identity.cpp ../../node/Utils.cpp ../../node/InetAddress.cpp ../../osdep/OSUtils.cpp mkworld.cpp -lm
+c++ -std=c++11 -I../.. -I../../ext -I.. -g -o mkworld ../../node/C25519.cpp ../../node/Salsa20.cpp ../../node/SHA512.cpp ../../node/Identity.cpp ../../node/Utils.cpp ../../node/InetAddress.cpp ../../osdep/OSUtils.cpp mkworld.cpp -lm

+ 13 - 0
ci/Dockerfile-build.deb

@@ -0,0 +1,13 @@
+ARG ZT_NAME
+FROM 084037375216.dkr.ecr.us-east-2.amazonaws.com/${ZT_NAME}-builder as builder
+WORKDIR /work/build
+COPY . .
+RUN pwd
+RUN ls -la .
+RUN make clean
+RUN make debian
+RUN ls -ls /work
+
+FROM scratch AS export
+ARG ZT_NAME
+COPY --from=builder /work/*.deb ./${ZT_NAME}/

+ 4 - 4
ci/Dockerfile.el6 → ci/Dockerfile-build.el6

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

+ 9 - 0
ci/Dockerfile-build.rpm

@@ -0,0 +1,9 @@
+ARG ZT_NAME
+FROM 084037375216.dkr.ecr.us-east-2.amazonaws.com/${ZT_NAME}-builder as builder
+WORKDIR /root/rpmbuild/BUILD
+COPY . .
+RUN make redhat
+
+FROM scratch AS export
+ARG ZT_NAME
+COPY --from=builder /root/rpmbuild/RPMS/*/*.rpm ./${ZT_NAME}/

+ 13 - 0
ci/Dockerfile-test.deb

@@ -0,0 +1,13 @@
+ARG ZT_NAME
+FROM 084037375216.dkr.ecr.us-east-2.amazonaws.com/${ZT_NAME}-tester
+ARG BASEURL
+ARG VERSION
+ARG DEB_ARCH
+ARG ZT_NAME
+ARG DISTRO
+RUN curl -s http://${BASEURL}/key.gpg -o /etc/apt/trusted.gpg.d/zerotier.gpg
+RUN echo "deb [arch=${DEB_ARCH} signed-by=/etc/apt/trusted.gpg.d/zerotier.gpg] http://${BASEURL}/${DISTRO} ${ZT_NAME} main" > /etc/apt/sources.list.d/zerotier.list
+RUN apt-get -qq update
+RUN apt-get -qq install zerotier-one=${VERSION}
+
+RUN ldd $(which zerotier-cli)

+ 4 - 0
ci/Dockerfile-test.el6

@@ -0,0 +1,4 @@
+ARG DOCKER_ARCH
+FROM --platform=linux/${DOCKER_ARCH} centos:6
+RUN printf "[C6.10-base]\nname=CentOS-6.10 - Base\nbaseurl=http://vault.epel.cloud/6.10/os/\$basearch/\ngpgcheck=1\ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-6\nenabled=1\nmetadata_expire=never\n" > /etc/yum.repos.d/CentOS-Base.repo
+RUN yum -y install curl

+ 17 - 0
ci/Dockerfile-test.rpm

@@ -0,0 +1,17 @@
+ARG ZT_NAME
+FROM 084037375216.dkr.ecr.us-east-2.amazonaws.com/${ZT_NAME}-tester
+ARG BASEURL
+ARG VERSION
+ARG DEB_ARCH
+ARG ZT_NAME
+ARG DISTRO
+ARG DNF_ARCH
+RUN curl -s http://${BASEURL}/key.asc -o /etc/pki/rpm-gpg/RPM-GPG-KEY-zerotier
+RUN rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-zerotier
+RUN rpm -q gpg-pubkey --qf '%{NAME}-%{VERSION}-%{RELEASE}\t%{SUMMARY}\n'
+RUN printf "[zerotier]\nname=zerotier\nbaseurl=http://${BASEURL}/${DISTRO}/${ZT_NAME}/$basearch/\nenabled=1\ngpgcheck=1\ngpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-zerotier\n" > /etc/yum.repos.d/zerotier.repo
+
+# RUN yum -v repolist
+RUN setarch ${DNF_ARCH} yum -y install zerotier-one-${VERSION}
+RUN file $(which zerotier-cli)
+RUN ldd $(which zerotier-cli)

+ 0 - 10
ci/Dockerfile.deb

@@ -1,10 +0,0 @@
-ARG PLATFORM
-FROM 084037375216.dkr.ecr.us-east-2.amazonaws.com/${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}/

+ 0 - 5
ci/Dockerfile.none

@@ -1,5 +0,0 @@
-ARG PLATFORM
-FROM 084037375216.dkr.ecr.us-east-2.amazonaws.com/${PLATFORM}-builder as stage
-WORKDIR /work
-COPY . .
-RUN make

+ 0 - 9
ci/Dockerfile.rpm

@@ -1,9 +0,0 @@
-ARG PLATFORM
-FROM 084037375216.dkr.ecr.us-east-2.amazonaws.com/${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}/

+ 29 - 106
ci/scripts/build.sh

@@ -2,125 +2,48 @@
 set -euo pipefail
 set -euo pipefail
 IFS=$'\n\t'
 IFS=$'\n\t'
 
 
-export PLATFORM=$1
-export ZT_ISA=$2
-export VERSION=$3
-export EVENT=$4
+ZT_NAME="$1" ; shift
+DISTRO="$1" ; shift
+ZT_ISA="$1" ; shift
+VERSION="$1" ; shift
+BUILD_EVENT="$1" ; shift
 
 
-case $PLATFORM in
-    sid)
-        export PKGFMT=none
-        ;;
-    el*|fc*|amzn*)
-        export PKGFMT=rpm
-        ;;
-    *)
-        export PKGFMT=deb
-esac
+source "$(dirname $0)/lib.sh"
 
 
-#
-# Allow user to drop in custom Dockerfile for PLATFORM
-#
-
-if [ -f "ci/Dockerfile.${PLATFORM}" ]; then
-    export DOCKERFILE="ci/Dockerfile.${PLATFORM}"
+if [ -f "ci/Dockerfile-build.${ZT_NAME}" ]; then
+    DOCKERFILE="ci/Dockerfile-build.${ZT_NAME}"
 else
 else
-    export DOCKERFILE="ci/Dockerfile.${PKGFMT}"
+    DOCKERFILE="ci/Dockerfile-build.${PKGFMT}"
 fi
 fi
 
 
-#
-# Rust sometimes gets confused about where it's running.
-# Normally, the build images will have Rust pre-baked.
-# Pass RUST_TRIPLET for convenience when using a custom Dockerfile
-#
-
-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
-        ;;
-    armv7)
-        export DOCKER_ARCH=arm/v7
-        export RUST_TRIPLET=armv7-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
-
-#
-# Print debug info
-#
-
 echo "#~~~~~~~~~~~~~~~~~~~~"
 echo "#~~~~~~~~~~~~~~~~~~~~"
 echo "$0 variables:"
 echo "$0 variables:"
 echo "nproc: $(nproc)"
 echo "nproc: $(nproc)"
+echo "ZT_NAME: ${ZT_NAME}"
+echo "DISTRO: ${DISTRO}"
 echo "ZT_ISA: ${ZT_ISA}"
 echo "ZT_ISA: ${ZT_ISA}"
+echo "VERSION: ${VERSION}"
+echo "BUILD_EVENT: ${BUILD_EVENT}"
 echo "DOCKER_ARCH: ${DOCKER_ARCH}"
 echo "DOCKER_ARCH: ${DOCKER_ARCH}"
+echo "DNF_ARCH: ${DNF_ARCH}"
 echo "RUST_TRIPLET: ${RUST_TRIPLET}"
 echo "RUST_TRIPLET: ${RUST_TRIPLET}"
-echo "VERSION: ${VERSION}"
-echo "EVENT: ${EVENT}"
 echo "PKGFMT: ${PKGFMT}"
 echo "PKGFMT: ${PKGFMT}"
 echo "PWD: ${PWD}"
 echo "PWD: ${PWD}"
 echo "DOCKERFILE: ${DOCKERFILE}"
 echo "DOCKERFILE: ${DOCKERFILE}"
 echo "#~~~~~~~~~~~~~~~~~~~~"
 echo "#~~~~~~~~~~~~~~~~~~~~"
 
 
-#
-# Munge RPM and Deb
-#
-
-if [ ${PKGFMT} != "none" ] && [ ${EVENT} != "tag" ]; then
-    make munge_rpm zerotier-one.spec VERSION=${VERSION}
-    make munge_deb debian/changelog VERSION=${VERSION}
-fi
-
-#
-# Assemble buildx arguments
-#
-
-build_args=(
-    --no-cache
-    --build-arg PLATFORM=${PLATFORM}
-    --build-arg RUST_TRIPLET=${RUST_TRIPLET}
-    --build-arg DOCKER_ARCH=${DOCKER_ARCH}
-    --platform linux/${DOCKER_ARCH}
-    -f ${DOCKERFILE}
-    -t build
-    .
-)
-
-if [ ${PKGFMT} != "none" ]; then
-    build_args+=("--output type=local,dest=.")
-    build_args+=("--target export")
-fi
-
-#
-# Do build
-#
-
-docker buildx build ${build_args[@]}
+make munge_rpm zerotier-one.spec VERSION=${VERSION}
+make munge_deb debian/changelog VERSION=${VERSION}
+
+docker buildx build \
+       --no-cache=true \
+       --build-arg ZT_NAME="${ZT_NAME}" \
+       --build-arg RUST_TRIPLET="${RUST_TRIPLET}" \
+       --build-arg DOCKER_ARCH="${DOCKER_ARCH}" \
+       --build-arg DNF_ARCH="${DNF_ARCH}" \
+       --platform linux/${DOCKER_ARCH} \
+       -f ${DOCKERFILE} \
+       -t build \
+       . \
+       --output type=local,dest=. \
+       --target export

+ 63 - 0
ci/scripts/lib.sh

@@ -0,0 +1,63 @@
+
+case $ZT_NAME in
+    el*|fc*|amzn*)
+        export PKGFMT=rpm
+        ;;
+    *)
+        export PKGFMT=deb
+esac
+
+case $ZT_ISA in
+    386)
+        export DOCKER_ARCH=386
+        export DEB_ARCH=i386
+        export DNF_ARCH=i686
+        export RUST_TRIPLET=i686-unknown-linux-gnu
+        ;;
+    amd64)
+        export DOCKER_ARCH=amd64
+        export DEB_ARCH=amd64
+        export DNF_ARCH=x86_64
+        export RUST_TRIPLET=x86_64-unknown-linux-gnu
+        ;;
+    armv7)
+        export DOCKER_ARCH=arm/v7
+        export DNF_ARCH=armv7
+        export DEB_ARCH=armhf
+        export RUST_TRIPLET=armv7-unknown-linux-gnueabihf
+        ;;
+    arm64)
+        export DOCKER_ARCH=arm64/v8
+        export DEB_ARCH=arm64
+        export DNF_ARCH=linux64
+        export RUST_TRIPLET=aarch64-unknown-linux-gnu
+        ;;
+    riscv64)
+        export DOCKER_ARCH=riscv64
+        export DEB_ARCH=riscv64
+        export DNF_ARCH=riscv64
+        export RUST_TRIPLET=riscv64gc-unknown-linux-gnu
+        ;;
+    ppc64le)
+        export DOCKER_ARCH=ppc64le
+        export DEB_ARCH=ppc64el
+        export DNF_ARCH=ppc64le
+        export RUST_TRIPLET=powerpc64le-unknown-linux-gnu
+        ;;
+    mips64le)
+        export DOCKER_ARCH=mips64le
+        export DEB_ARCH=mips64le
+        export DNF_ARCH=mips64le
+        export RUST_TRIPLET=mips64el-unknown-linux-gnuabi64
+        ;;
+    s390x)
+        export DOCKER_ARCH=s390x
+        export DEB_ARCH=s390x
+        export DNF_ARCH=s390x
+        export RUST_TRIPLET=s390x-unknown-linux-gnu
+        ;;
+    *)
+        echo "ERROR: could not determine architecture settings. PLEASE FIX ME"
+        exit 1
+        ;;
+esac

+ 1 - 1
ci/scripts/munge_debian_changelog.sh

@@ -31,7 +31,7 @@ else
 fi
 fi
 
 
 awk -v version=${VERSION} -v date=${DATE} -v name=${NAME} -v message=${MESSAGE} \
 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 }' \
+    'BEGIN{print "zerotier-one (" version ") stable; urgency=medium\n\n  * " message "\n\n -- " name "  " date "\n" }{ print }' \
     ${FILE} > ${FILE}.new
     ${FILE} > ${FILE}.new
 
 
 mv ${FILE}.new ${FILE}
 mv ${FILE}.new ${FILE}

+ 38 - 0
ci/scripts/publish.sh

@@ -0,0 +1,38 @@
+#!/bin/bash
+set -euo pipefail
+IFS=$'\n\t'
+
+ZT_NAME="$1" ; shift
+DISTRO="$1" ; shift
+ZT_ISA="$1" ; shift
+VERSION="$1" ; shift
+BUILD_EVENT="$1" ; shift
+
+source "$(dirname $0)/lib.sh"
+
+if [ ${BUILD_EVENT} == "tag" ]; then
+    CHANNEL="zerotier-releases"
+else
+    CHANNEL="zerotier-builds"
+fi
+
+function publish_rpm {
+    mkdir -p /${CHANNEL}/${DISTRO}
+    ls -la /${CHANNEL}    
+    ls -la .
+    cp -a ${ZT_NAME} /${CHANNEL}/${DISTRO}
+}
+
+function publish_deb {
+    mkdir -p /${CHANNEL}/${DISTRO}/pool/dists/${ZT_NAME}/main
+    cp -a ${ZT_NAME}/* /${CHANNEL}/${DISTRO}/pool/dists/${ZT_NAME}/main
+}
+
+case ${PKGFMT} in
+    "rpm")
+        publish_rpm
+        ;;
+    "deb")
+        publish_deb
+esac
+            

+ 55 - 0
ci/scripts/test.sh

@@ -0,0 +1,55 @@
+#!/bin/bash
+set -euo pipefail
+IFS=$'\n\t'
+
+ZT_NAME="$1" ; shift
+DISTRO="$1" ; shift
+ZT_ISA="$1" ; shift
+VERSION="$1" ; shift
+BUILD_EVENT="$1" ; shift
+
+source "$(dirname $0)/lib.sh"
+
+if [ -f "ci/Dockerfile-test.${ZT_NAME}" ]; then
+    DOCKERFILE="ci/Dockerfile-test.${ZT_NAME}"
+else
+    DOCKERFILE="ci/Dockerfile-test.${PKGFMT}"
+fi
+
+if [ ${BUILD_EVENT} == "tag" ]; then
+    BASEURL="zerotier-releases.home.arpa"
+else
+    BASEURL="zerotier-builds.home.arpa"
+fi
+
+echo "#~~~~~~~~~~~~~~~~~~~~"
+echo "$0 variables:"
+echo "nproc: $(nproc)"
+echo "ZT_NAME: ${ZT_NAME}"
+echo "DISTRO: ${DISTRO}"
+echo "ZT_ISA: ${ZT_ISA}"
+echo "VERSION: ${VERSION}"
+echo "BUILD_EVENT: ${BUILD_EVENT}"
+echo "DOCKER_ARCH: ${DOCKER_ARCH}"
+echo "DNF_ARCH: ${DNF_ARCH}"
+echo "RUST_TRIPLET: ${RUST_TRIPLET}"
+echo "PKGFMT: ${PKGFMT}"
+echo "PWD: ${PWD}"
+echo "DOCKERFILE: ${DOCKERFILE}"
+echo "#~~~~~~~~~~~~~~~~~~~~"
+
+# docker pull -q --platform="linux/${DOCKER_ARCH}" 084037375216.dkr.ecr.us-east-2.amazonaws.com/${ZT_NAME}-tester
+
+docker buildx build \
+       --build-arg BASEURL="${BASEURL}" \
+       --build-arg ZT_NAME="${ZT_NAME}" \
+       --build-arg DISTRO="${DISTRO}" \
+       --build-arg DEB_ARCH="${DEB_ARCH}" \
+       --build-arg DNF_ARCH="${DNF_ARCH}" \
+       --build-arg VERSION="${VERSION}" \
+       --build-arg DOCKER_ARCH="${DOCKER_ARCH}" \
+       --platform "linux/${DOCKER_ARCH}" \
+       --no-cache \
+       -f ${DOCKERFILE} \
+       -t test \
+       .

+ 15 - 1
controller/ConnectionPool.hpp

@@ -19,6 +19,8 @@
 	#define _DEBUG(x)
 	#define _DEBUG(x)
 #endif
 #endif
 
 
+#include "../node/Metrics.hpp"
+
 #include <deque>
 #include <deque>
 #include <set>
 #include <set>
 #include <memory>
 #include <memory>
@@ -59,8 +61,11 @@ public:
         , m_minPoolSize(min_pool_size)
         , m_minPoolSize(min_pool_size)
         , m_factory(factory)
         , m_factory(factory)
     {
     {
+        Metrics::max_pool_size += max_pool_size;
+        Metrics::min_pool_size += min_pool_size;
         while(m_pool.size() < m_minPoolSize){
         while(m_pool.size() < m_minPoolSize){
             m_pool.push_back(m_factory->create());
             m_pool.push_back(m_factory->create());
+            Metrics::pool_avail++;
         }
         }
     };
     };
 
 
@@ -91,6 +96,7 @@ public:
         while((m_pool.size() + m_borrowed.size()) < m_minPoolSize) {
         while((m_pool.size() + m_borrowed.size()) < m_minPoolSize) {
             std::shared_ptr<Connection> conn = m_factory->create();
             std::shared_ptr<Connection> conn = m_factory->create();
             m_pool.push_back(conn);
             m_pool.push_back(conn);
+            Metrics::pool_avail++;
         }
         }
 
 
         if(m_pool.size()==0){
         if(m_pool.size()==0){
@@ -99,8 +105,10 @@ public:
                 try {
                 try {
                     std::shared_ptr<Connection> conn = m_factory->create();
                     std::shared_ptr<Connection> conn = m_factory->create();
                     m_borrowed.insert(conn);
                     m_borrowed.insert(conn);
+                    Metrics::pool_in_use++;
                     return std::static_pointer_cast<T>(conn);
                     return std::static_pointer_cast<T>(conn);
                 } catch (std::exception &e) {
                 } catch (std::exception &e) {
+                    Metrics::pool_errors++;
                     throw ConnectionUnavailable();
                     throw ConnectionUnavailable();
                 }
                 }
             } else {
             } else {
@@ -116,11 +124,13 @@ public:
                             return std::static_pointer_cast<T>(conn);
                             return std::static_pointer_cast<T>(conn);
                         } catch(std::exception& e) {
                         } catch(std::exception& e) {
                             // Error creating a replacement connection
                             // Error creating a replacement connection
+                            Metrics::pool_errors++;
                             throw ConnectionUnavailable();
                             throw ConnectionUnavailable();
                         }
                         }
                     }
                     }
                 }
                 }
                 // Nothing available
                 // Nothing available
+                Metrics::pool_errors++;
                 throw ConnectionUnavailable();
                 throw ConnectionUnavailable();
             }
             }
         }
         }
@@ -128,8 +138,10 @@ public:
         // Take one off the front
         // Take one off the front
         std::shared_ptr<Connection> conn = m_pool.front();
         std::shared_ptr<Connection> conn = m_pool.front();
         m_pool.pop_front();
         m_pool.pop_front();
+        Metrics::pool_avail--;
         // Add it to the borrowed list
         // Add it to the borrowed list
         m_borrowed.insert(conn);
         m_borrowed.insert(conn);
+        Metrics::pool_in_use++;
         return std::static_pointer_cast<T>(conn);
         return std::static_pointer_cast<T>(conn);
     };
     };
 
 
@@ -143,7 +155,9 @@ public:
         // Lock
         // Lock
         std::unique_lock<std::mutex> lock(m_poolMutex);
         std::unique_lock<std::mutex> lock(m_poolMutex);
         m_borrowed.erase(conn);
         m_borrowed.erase(conn);
+        Metrics::pool_in_use--;
         if ((m_pool.size() + m_borrowed.size()) < m_maxPoolSize) {
         if ((m_pool.size() + m_borrowed.size()) < m_maxPoolSize) {
+            Metrics::pool_avail++;
             m_pool.push_back(conn);
             m_pool.push_back(conn);
         }
         }
     };
     };
@@ -158,4 +172,4 @@ protected:
 
 
 }
 }
 
 
-#endif
+#endif

+ 68 - 26
controller/DB.cpp

@@ -13,6 +13,7 @@
 
 
 #include "DB.hpp"
 #include "DB.hpp"
 #include "EmbeddedNetworkController.hpp"
 #include "EmbeddedNetworkController.hpp"
+#include "../node/Metrics.hpp"
 
 
 #include <chrono>
 #include <chrono>
 #include <algorithm>
 #include <algorithm>
@@ -107,16 +108,17 @@ DB::~DB() {}
 bool DB::get(const uint64_t networkId,nlohmann::json &network)
 bool DB::get(const uint64_t networkId,nlohmann::json &network)
 {
 {
 	waitForReady();
 	waitForReady();
+	Metrics::db_get_network++;
 	std::shared_ptr<_Network> nw;
 	std::shared_ptr<_Network> nw;
 	{
 	{
-		std::lock_guard<std::mutex> l(_networks_l);
+		std::shared_lock<std::shared_mutex> l(_networks_l);
 		auto nwi = _networks.find(networkId);
 		auto nwi = _networks.find(networkId);
 		if (nwi == _networks.end())
 		if (nwi == _networks.end())
 			return false;
 			return false;
 		nw = nwi->second;
 		nw = nwi->second;
 	}
 	}
 	{
 	{
-		std::lock_guard<std::mutex> l2(nw->lock);
+		std::shared_lock<std::shared_mutex> l2(nw->lock);
 		network = nw->config;
 		network = nw->config;
 	}
 	}
 	return true;
 	return true;
@@ -125,16 +127,17 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network)
 bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member)
 bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member)
 {
 {
 	waitForReady();
 	waitForReady();
+	Metrics::db_get_network_and_member++;
 	std::shared_ptr<_Network> nw;
 	std::shared_ptr<_Network> nw;
 	{
 	{
-		std::lock_guard<std::mutex> l(_networks_l);
+		std::shared_lock<std::shared_mutex> l(_networks_l);
 		auto nwi = _networks.find(networkId);
 		auto nwi = _networks.find(networkId);
 		if (nwi == _networks.end())
 		if (nwi == _networks.end())
 			return false;
 			return false;
 		nw = nwi->second;
 		nw = nwi->second;
 	}
 	}
 	{
 	{
-		std::lock_guard<std::mutex> l2(nw->lock);
+		std::shared_lock<std::shared_mutex> l2(nw->lock);
 		network = nw->config;
 		network = nw->config;
 		auto m = nw->members.find(memberId);
 		auto m = nw->members.find(memberId);
 		if (m == nw->members.end())
 		if (m == nw->members.end())
@@ -147,16 +150,17 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t mem
 bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,NetworkSummaryInfo &info)
 bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,NetworkSummaryInfo &info)
 {
 {
 	waitForReady();
 	waitForReady();
+	Metrics::db_get_network_and_member_and_summary++;
 	std::shared_ptr<_Network> nw;
 	std::shared_ptr<_Network> nw;
 	{
 	{
-		std::lock_guard<std::mutex> l(_networks_l);
+		std::shared_lock<std::shared_mutex> l(_networks_l);
 		auto nwi = _networks.find(networkId);
 		auto nwi = _networks.find(networkId);
 		if (nwi == _networks.end())
 		if (nwi == _networks.end())
 			return false;
 			return false;
 		nw = nwi->second;
 		nw = nwi->second;
 	}
 	}
 	{
 	{
-		std::lock_guard<std::mutex> l2(nw->lock);
+		std::shared_lock<std::shared_mutex> l2(nw->lock);
 		network = nw->config;
 		network = nw->config;
 		_fillSummaryInfo(nw,info);
 		_fillSummaryInfo(nw,info);
 		auto m = nw->members.find(memberId);
 		auto m = nw->members.find(memberId);
@@ -170,16 +174,17 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,const uint64_t mem
 bool DB::get(const uint64_t networkId,nlohmann::json &network,std::vector<nlohmann::json> &members)
 bool DB::get(const uint64_t networkId,nlohmann::json &network,std::vector<nlohmann::json> &members)
 {
 {
 	waitForReady();
 	waitForReady();
+	Metrics::db_get_member_list++;
 	std::shared_ptr<_Network> nw;
 	std::shared_ptr<_Network> nw;
 	{
 	{
-		std::lock_guard<std::mutex> l(_networks_l);
+		std::shared_lock<std::shared_mutex> l(_networks_l);
 		auto nwi = _networks.find(networkId);
 		auto nwi = _networks.find(networkId);
 		if (nwi == _networks.end())
 		if (nwi == _networks.end())
 			return false;
 			return false;
 		nw = nwi->second;
 		nw = nwi->second;
 	}
 	}
 	{
 	{
-		std::lock_guard<std::mutex> l2(nw->lock);
+		std::shared_lock<std::shared_mutex> l2(nw->lock);
 		network = nw->config;
 		network = nw->config;
 		for(auto m=nw->members.begin();m!=nw->members.end();++m) {
 		for(auto m=nw->members.begin();m!=nw->members.end();++m) {
 			members.push_back(m->second);
 			members.push_back(m->second);
@@ -191,13 +196,15 @@ bool DB::get(const uint64_t networkId,nlohmann::json &network,std::vector<nlohma
 void DB::networks(std::set<uint64_t> &networks)
 void DB::networks(std::set<uint64_t> &networks)
 {
 {
 	waitForReady();
 	waitForReady();
-	std::lock_guard<std::mutex> l(_networks_l);
+	Metrics::db_get_member_list++;
+	std::shared_lock<std::shared_mutex> l(_networks_l);
 	for(auto n=_networks.begin();n!=_networks.end();++n)
 	for(auto n=_networks.begin();n!=_networks.end();++n)
 		networks.insert(n->first);
 		networks.insert(n->first);
 }
 }
 
 
 void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners)
 void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners)
 {
 {
+	Metrics::db_member_change++;
 	uint64_t memberId = 0;
 	uint64_t memberId = 0;
 	uint64_t networkId = 0;
 	uint64_t networkId = 0;
 	bool isAuth = false;
 	bool isAuth = false;
@@ -209,18 +216,21 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
 		networkId = OSUtils::jsonIntHex(old["nwid"],0ULL);
 		networkId = OSUtils::jsonIntHex(old["nwid"],0ULL);
 		if ((memberId)&&(networkId)) {
 		if ((memberId)&&(networkId)) {
 			{
 			{
-				std::lock_guard<std::mutex> l(_networks_l);
+				std::unique_lock<std::shared_mutex> l(_networks_l);
 				auto nw2 = _networks.find(networkId);
 				auto nw2 = _networks.find(networkId);
-				if (nw2 != _networks.end())
+				if (nw2 != _networks.end()) {
 					nw = nw2->second;
 					nw = nw2->second;
+				}
 			}
 			}
 			if (nw) {
 			if (nw) {
-				std::lock_guard<std::mutex> l(nw->lock);
-				if (OSUtils::jsonBool(old["activeBridge"],false))
+				std::unique_lock<std::shared_mutex> l(nw->lock);
+				if (OSUtils::jsonBool(old["activeBridge"],false)) {
 					nw->activeBridgeMembers.erase(memberId);
 					nw->activeBridgeMembers.erase(memberId);
+				}
 				wasAuth = OSUtils::jsonBool(old["authorized"],false);
 				wasAuth = OSUtils::jsonBool(old["authorized"],false);
-				if (wasAuth)
+				if (wasAuth) {
 					nw->authorizedMembers.erase(memberId);
 					nw->authorizedMembers.erase(memberId);
+				}
 				json &ips = old["ipAssignments"];
 				json &ips = old["ipAssignments"];
 				if (ips.is_array()) {
 				if (ips.is_array()) {
 					for(unsigned long i=0;i<ips.size();++i) {
 					for(unsigned long i=0;i<ips.size();++i) {
@@ -243,7 +253,7 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
 			networkId = OSUtils::jsonIntHex(memberConfig["nwid"],0ULL);
 			networkId = OSUtils::jsonIntHex(memberConfig["nwid"],0ULL);
 			if ((!memberId)||(!networkId))
 			if ((!memberId)||(!networkId))
 				return;
 				return;
-			std::lock_guard<std::mutex> l(_networks_l);
+			std::unique_lock<std::shared_mutex> l(_networks_l);
 			std::shared_ptr<_Network> &nw2 = _networks[networkId];
 			std::shared_ptr<_Network> &nw2 = _networks[networkId];
 			if (!nw2)
 			if (!nw2)
 				nw2.reset(new _Network);
 				nw2.reset(new _Network);
@@ -251,15 +261,18 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
 		}
 		}
 
 
 		{
 		{
-			std::lock_guard<std::mutex> l(nw->lock);
+			std::unique_lock<std::shared_mutex> l(nw->lock);
 
 
 			nw->members[memberId] = memberConfig;
 			nw->members[memberId] = memberConfig;
 
 
-			if (OSUtils::jsonBool(memberConfig["activeBridge"],false))
+			if (OSUtils::jsonBool(memberConfig["activeBridge"],false)) {
 				nw->activeBridgeMembers.insert(memberId);
 				nw->activeBridgeMembers.insert(memberId);
+			}
 			isAuth = OSUtils::jsonBool(memberConfig["authorized"],false);
 			isAuth = OSUtils::jsonBool(memberConfig["authorized"],false);
-			if (isAuth)
+			if (isAuth) {
+				Metrics::member_auths++;
 				nw->authorizedMembers.insert(memberId);
 				nw->authorizedMembers.insert(memberId);
+			}
 			json &ips = memberConfig["ipAssignments"];
 			json &ips = memberConfig["ipAssignments"];
 			if (ips.is_array()) {
 			if (ips.is_array()) {
 				for(unsigned long i=0;i<ips.size();++i) {
 				for(unsigned long i=0;i<ips.size();++i) {
@@ -281,18 +294,18 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
 		}
 		}
 
 
 		if (notifyListeners) {
 		if (notifyListeners) {
-			std::lock_guard<std::mutex> ll(_changeListeners_l);
+			std::unique_lock<std::shared_mutex> ll(_changeListeners_l);
 			for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) {
 			for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) {
 				(*i)->onNetworkMemberUpdate(this,networkId,memberId,memberConfig);
 				(*i)->onNetworkMemberUpdate(this,networkId,memberId,memberConfig);
 			}
 			}
 		}
 		}
 	} else if (memberId) {
 	} else if (memberId) {
 		if (nw) {
 		if (nw) {
-			std::lock_guard<std::mutex> l(nw->lock);
+			std::unique_lock<std::shared_mutex> l(nw->lock);
 			nw->members.erase(memberId);
 			nw->members.erase(memberId);
 		}
 		}
 		if (networkId) {
 		if (networkId) {
-			std::lock_guard<std::mutex> l(_networks_l);
+			std::unique_lock<std::shared_mutex> l(_networks_l);
 			auto er = _networkByMember.equal_range(memberId);
 			auto er = _networkByMember.equal_range(memberId);
 			for(auto i=er.first;i!=er.second;++i) {
 			for(auto i=er.first;i!=er.second;++i) {
 				if (i->second == networkId) {
 				if (i->second == networkId) {
@@ -303,8 +316,26 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
 		}
 		}
 	}
 	}
 
 
+	if (notifyListeners) {
+		if(networkId != 0 && memberId != 0 && old.is_object() && !memberConfig.is_object()) {
+			// member delete
+			Metrics::member_count--;
+		} else if (networkId != 0 && memberId != 0 && !old.is_object() && memberConfig.is_object()) {
+			// new member
+			Metrics::member_count++;
+		}
+
+		if (!wasAuth && isAuth) {
+			Metrics::member_auths++;
+		} else if (wasAuth && !isAuth) {
+			Metrics::member_deauths++;
+		} else {
+			Metrics::member_changes++;
+		}
+	}
+
 	if ((notifyListeners)&&((wasAuth)&&(!isAuth)&&(networkId)&&(memberId))) {
 	if ((notifyListeners)&&((wasAuth)&&(!isAuth)&&(networkId)&&(memberId))) {
-		std::lock_guard<std::mutex> ll(_changeListeners_l);
+		std::unique_lock<std::shared_mutex> ll(_changeListeners_l);
 		for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) {
 		for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) {
 			(*i)->onNetworkMemberDeauthorize(this,networkId,memberId);
 			(*i)->onNetworkMemberDeauthorize(this,networkId,memberId);
 		}
 		}
@@ -313,24 +344,35 @@ void DB::_memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool no
 
 
 void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners)
 void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool notifyListeners)
 {
 {
+	Metrics::db_network_change++;
+	if (notifyListeners) {
+		if (old.is_object() && old.contains("id") && networkConfig.is_object() && networkConfig.contains("id")) {
+			Metrics::network_changes++;
+		} else if (!old.is_object() && networkConfig.is_object() && networkConfig.contains("id")) {
+			Metrics::network_count++;
+		} else if (old.is_object() && old.contains("id") && !networkConfig.is_object()) {
+			Metrics::network_count--;
+		}
+	}
+
 	if (networkConfig.is_object()) {
 	if (networkConfig.is_object()) {
 		const std::string ids = networkConfig["id"];
 		const std::string ids = networkConfig["id"];
 		const uint64_t networkId = Utils::hexStrToU64(ids.c_str());
 		const uint64_t networkId = Utils::hexStrToU64(ids.c_str());
 		if (networkId) {
 		if (networkId) {
 			std::shared_ptr<_Network> nw;
 			std::shared_ptr<_Network> nw;
 			{
 			{
-				std::lock_guard<std::mutex> l(_networks_l);
+				std::unique_lock<std::shared_mutex> l(_networks_l);
 				std::shared_ptr<_Network> &nw2 = _networks[networkId];
 				std::shared_ptr<_Network> &nw2 = _networks[networkId];
 				if (!nw2)
 				if (!nw2)
 					nw2.reset(new _Network);
 					nw2.reset(new _Network);
 				nw = nw2;
 				nw = nw2;
 			}
 			}
 			{
 			{
-				std::lock_guard<std::mutex> l2(nw->lock);
+				std::unique_lock<std::shared_mutex> l2(nw->lock);
 				nw->config = networkConfig;
 				nw->config = networkConfig;
 			}
 			}
 			if (notifyListeners) {
 			if (notifyListeners) {
-				std::lock_guard<std::mutex> ll(_changeListeners_l);
+				std::unique_lock<std::shared_mutex> ll(_changeListeners_l);
 				for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) {
 				for(auto i=_changeListeners.begin();i!=_changeListeners.end();++i) {
 					(*i)->onNetworkUpdate(this,networkId,networkConfig);
 					(*i)->onNetworkUpdate(this,networkId,networkConfig);
 				}
 				}
@@ -340,7 +382,7 @@ void DB::_networkChanged(nlohmann::json &old,nlohmann::json &networkConfig,bool
 		const std::string ids = old["id"];
 		const std::string ids = old["id"];
 		const uint64_t networkId = Utils::hexStrToU64(ids.c_str());
 		const uint64_t networkId = Utils::hexStrToU64(ids.c_str());
 		if (networkId) {
 		if (networkId) {
-			std::lock_guard<std::mutex> l(_networks_l);
+			std::unique_lock<std::shared_mutex> l(_networks_l);
 			_networks.erase(networkId);
 			_networks.erase(networkId);
 		}
 		}
 	}
 	}

+ 9 - 7
controller/DB.hpp

@@ -29,12 +29,14 @@
 #include <unordered_set>
 #include <unordered_set>
 #include <vector>
 #include <vector>
 #include <atomic>
 #include <atomic>
-#include <mutex>
+#include <shared_mutex>
 #include <set>
 #include <set>
 #include <map>
 #include <map>
 
 
 #include <nlohmann/json.hpp>
 #include <nlohmann/json.hpp>
 
 
+#include <prometheus/simpleapi.h>
+
 #define ZT_MEMBER_AUTH_TIMEOUT_NOTIFY_BEFORE 25000
 #define ZT_MEMBER_AUTH_TIMEOUT_NOTIFY_BEFORE 25000
 
 
 namespace ZeroTier
 namespace ZeroTier
@@ -107,7 +109,7 @@ public:
 
 
 	inline bool hasNetwork(const uint64_t networkId) const
 	inline bool hasNetwork(const uint64_t networkId) const
 	{
 	{
-		std::lock_guard<std::mutex> l(_networks_l);
+		std::shared_lock<std::shared_mutex> l(_networks_l);
 		return (_networks.find(networkId) != _networks.end());
 		return (_networks.find(networkId) != _networks.end());
 	}
 	}
 
 
@@ -122,7 +124,7 @@ public:
 	inline void each(F f)
 	inline void each(F f)
 	{
 	{
 		nlohmann::json nullJson;
 		nlohmann::json nullJson;
-		std::lock_guard<std::mutex> lck(_networks_l);
+		std::unique_lock<std::shared_mutex> lck(_networks_l);
 		for(auto nw=_networks.begin();nw!=_networks.end();++nw) {
 		for(auto nw=_networks.begin();nw!=_networks.end();++nw) {
 			f(nw->first,nw->second->config,0,nullJson); // first provide network with 0 for member ID
 			f(nw->first,nw->second->config,0,nullJson); // first provide network with 0 for member ID
 			for(auto m=nw->second->members.begin();m!=nw->second->members.end();++m) {
 			for(auto m=nw->second->members.begin();m!=nw->second->members.end();++m) {
@@ -140,7 +142,7 @@ public:
 
 
 	inline void addListener(DB::ChangeListener *const listener)
 	inline void addListener(DB::ChangeListener *const listener)
 	{
 	{
-		std::lock_guard<std::mutex> l(_changeListeners_l);
+		std::unique_lock<std::shared_mutex> l(_changeListeners_l);
 		_changeListeners.push_back(listener);
 		_changeListeners.push_back(listener);
 	}
 	}
 
 
@@ -176,7 +178,7 @@ protected:
 		std::unordered_set<uint64_t> authorizedMembers;
 		std::unordered_set<uint64_t> authorizedMembers;
 		std::unordered_set<InetAddress,InetAddress::Hasher> allocatedIps;
 		std::unordered_set<InetAddress,InetAddress::Hasher> allocatedIps;
 		int64_t mostRecentDeauthTime;
 		int64_t mostRecentDeauthTime;
-		std::mutex lock;
+		std::shared_mutex lock;
 	};
 	};
 
 
 	virtual void _memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners);
 	virtual void _memberChanged(nlohmann::json &old,nlohmann::json &memberConfig,bool notifyListeners);
@@ -186,8 +188,8 @@ protected:
 	std::vector<DB::ChangeListener *> _changeListeners;
 	std::vector<DB::ChangeListener *> _changeListeners;
 	std::unordered_map< uint64_t,std::shared_ptr<_Network> > _networks;
 	std::unordered_map< uint64_t,std::shared_ptr<_Network> > _networks;
 	std::unordered_multimap< uint64_t,uint64_t > _networkByMember;
 	std::unordered_multimap< uint64_t,uint64_t > _networkByMember;
-	mutable std::mutex _changeListeners_l;
-	mutable std::mutex _networks_l;
+	mutable std::shared_mutex _changeListeners_l;
+	mutable std::shared_mutex _networks_l;
 };
 };
 
 
 } // namespace ZeroTier
 } // namespace ZeroTier

+ 22 - 19
controller/DBMirrorSet.cpp

@@ -15,9 +15,12 @@
 
 
 namespace ZeroTier {
 namespace ZeroTier {
 
 
-DBMirrorSet::DBMirrorSet(DB::ChangeListener *listener) :
-	_listener(listener),
-	_running(true)
+DBMirrorSet::DBMirrorSet(DB::ChangeListener *listener)
+	: _listener(listener)
+	, _running(true)
+	, _syncCheckerThread()
+	, _dbs()
+	, _dbs_l()
 {
 {
 	_syncCheckerThread = std::thread([this]() {
 	_syncCheckerThread = std::thread([this]() {
 		for(;;) {
 		for(;;) {
@@ -29,7 +32,7 @@ DBMirrorSet::DBMirrorSet(DB::ChangeListener *listener) :
 
 
 			std::vector< std::shared_ptr<DB> > dbs;
 			std::vector< std::shared_ptr<DB> > dbs;
 			{
 			{
-				std::lock_guard<std::mutex> l(_dbs_l);
+				std::unique_lock<std::shared_mutex> l(_dbs_l);
 				if (_dbs.size() <= 1)
 				if (_dbs.size() <= 1)
 					continue; // no need to do this if there's only one DB, so skip the iteration
 					continue; // no need to do this if there's only one DB, so skip the iteration
 				dbs = _dbs;
 				dbs = _dbs;
@@ -76,7 +79,7 @@ DBMirrorSet::~DBMirrorSet()
 
 
 bool DBMirrorSet::hasNetwork(const uint64_t networkId) const
 bool DBMirrorSet::hasNetwork(const uint64_t networkId) const
 {
 {
-	std::lock_guard<std::mutex> l(_dbs_l);
+	std::shared_lock<std::shared_mutex> l(_dbs_l);
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 		if ((*d)->hasNetwork(networkId))
 		if ((*d)->hasNetwork(networkId))
 			return true;
 			return true;
@@ -86,7 +89,7 @@ bool DBMirrorSet::hasNetwork(const uint64_t networkId) const
 
 
 bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network)
 bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network)
 {
 {
-	std::lock_guard<std::mutex> l(_dbs_l);
+	std::shared_lock<std::shared_mutex> l(_dbs_l);
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 		if ((*d)->get(networkId,network)) {
 		if ((*d)->get(networkId,network)) {
 			return true;
 			return true;
@@ -97,7 +100,7 @@ bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network)
 
 
 bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member)
 bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member)
 {
 {
-	std::lock_guard<std::mutex> l(_dbs_l);
+	std::shared_lock<std::shared_mutex> l(_dbs_l);
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 		if ((*d)->get(networkId,network,memberId,member))
 		if ((*d)->get(networkId,network,memberId,member))
 			return true;
 			return true;
@@ -107,7 +110,7 @@ bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,const uin
 
 
 bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,DB::NetworkSummaryInfo &info)
 bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,const uint64_t memberId,nlohmann::json &member,DB::NetworkSummaryInfo &info)
 {
 {
-	std::lock_guard<std::mutex> l(_dbs_l);
+	std::shared_lock<std::shared_mutex> l(_dbs_l);
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 		if ((*d)->get(networkId,network,memberId,member,info))
 		if ((*d)->get(networkId,network,memberId,member,info))
 			return true;
 			return true;
@@ -117,7 +120,7 @@ bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,const uin
 
 
 bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,std::vector<nlohmann::json> &members)
 bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,std::vector<nlohmann::json> &members)
 {
 {
-	std::lock_guard<std::mutex> l(_dbs_l);
+	std::shared_lock<std::shared_mutex> l(_dbs_l);
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 		if ((*d)->get(networkId,network,members))
 		if ((*d)->get(networkId,network,members))
 			return true;
 			return true;
@@ -127,7 +130,7 @@ bool DBMirrorSet::get(const uint64_t networkId,nlohmann::json &network,std::vect
 
 
 AuthInfo DBMirrorSet::getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL) 
 AuthInfo DBMirrorSet::getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL) 
 {
 {
-	std::lock_guard<std::mutex> l(_dbs_l);
+	std::shared_lock<std::shared_mutex> l(_dbs_l);
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) { 
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) { 
 		AuthInfo info = (*d)->getSSOAuthInfo(member, redirectURL);
 		AuthInfo info = (*d)->getSSOAuthInfo(member, redirectURL);
 		if (info.enabled) {
 		if (info.enabled) {
@@ -139,7 +142,7 @@ AuthInfo DBMirrorSet::getSSOAuthInfo(const nlohmann::json &member, const std::st
 
 
 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::shared_lock<std::shared_mutex> l(_dbs_l);
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 		(*d)->networks(networks);
 		(*d)->networks(networks);
 	}
 	}
@@ -148,7 +151,7 @@ void DBMirrorSet::networks(std::set<uint64_t> &networks)
 bool DBMirrorSet::waitForReady()
 bool DBMirrorSet::waitForReady()
 {
 {
 	bool r = false;
 	bool r = false;
-	std::lock_guard<std::mutex> l(_dbs_l);
+	std::shared_lock<std::shared_mutex> l(_dbs_l);
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 		r |= (*d)->waitForReady();
 		r |= (*d)->waitForReady();
 	}
 	}
@@ -157,7 +160,7 @@ bool DBMirrorSet::waitForReady()
 
 
 bool DBMirrorSet::isReady()
 bool DBMirrorSet::isReady()
 {
 {
-	std::lock_guard<std::mutex> l(_dbs_l);
+	std::shared_lock<std::shared_mutex> l(_dbs_l);
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 		if (!(*d)->isReady())
 		if (!(*d)->isReady())
 			return false;
 			return false;
@@ -169,7 +172,7 @@ bool DBMirrorSet::save(nlohmann::json &record,bool notifyListeners)
 {
 {
 	std::vector< std::shared_ptr<DB> > dbs;
 	std::vector< std::shared_ptr<DB> > dbs;
 	{
 	{
-		std::lock_guard<std::mutex> l(_dbs_l);
+		std::unique_lock<std::shared_mutex> l(_dbs_l);
 		dbs = _dbs;
 		dbs = _dbs;
 	}
 	}
 	if (notifyListeners) {
 	if (notifyListeners) {
@@ -189,7 +192,7 @@ bool DBMirrorSet::save(nlohmann::json &record,bool notifyListeners)
 
 
 void DBMirrorSet::eraseNetwork(const uint64_t networkId)
 void DBMirrorSet::eraseNetwork(const uint64_t networkId)
 {
 {
-	std::lock_guard<std::mutex> l(_dbs_l);
+	std::unique_lock<std::shared_mutex> l(_dbs_l);
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 		(*d)->eraseNetwork(networkId);
 		(*d)->eraseNetwork(networkId);
 	}
 	}
@@ -197,7 +200,7 @@ void DBMirrorSet::eraseNetwork(const uint64_t networkId)
 
 
 void DBMirrorSet::eraseMember(const uint64_t networkId,const uint64_t memberId)
 void DBMirrorSet::eraseMember(const uint64_t networkId,const uint64_t memberId)
 {
 {
-	std::lock_guard<std::mutex> l(_dbs_l);
+	std::unique_lock<std::shared_mutex> l(_dbs_l);
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 		(*d)->eraseMember(networkId,memberId);
 		(*d)->eraseMember(networkId,memberId);
 	}
 	}
@@ -205,7 +208,7 @@ void DBMirrorSet::eraseMember(const uint64_t networkId,const uint64_t memberId)
 
 
 void DBMirrorSet::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress)
 void DBMirrorSet::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,const InetAddress &physicalAddress)
 {
 {
-	std::lock_guard<std::mutex> l(_dbs_l);
+	std::shared_lock<std::shared_mutex> l(_dbs_l);
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 		(*d)->nodeIsOnline(networkId,memberId,physicalAddress);
 		(*d)->nodeIsOnline(networkId,memberId,physicalAddress);
 	}
 	}
@@ -214,7 +217,7 @@ void DBMirrorSet::nodeIsOnline(const uint64_t networkId,const uint64_t memberId,
 void DBMirrorSet::onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network)
 void DBMirrorSet::onNetworkUpdate(const void *db,uint64_t networkId,const nlohmann::json &network)
 {
 {
 	nlohmann::json record(network);
 	nlohmann::json record(network);
-	std::lock_guard<std::mutex> l(_dbs_l);
+	std::unique_lock<std::shared_mutex> l(_dbs_l);
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 		if (d->get() != db) {
 		if (d->get() != db) {
 			(*d)->save(record,false);
 			(*d)->save(record,false);
@@ -226,7 +229,7 @@ void DBMirrorSet::onNetworkUpdate(const void *db,uint64_t networkId,const nlohma
 void DBMirrorSet::onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member)
 void DBMirrorSet::onNetworkMemberUpdate(const void *db,uint64_t networkId,uint64_t memberId,const nlohmann::json &member)
 {
 {
 	nlohmann::json record(member);
 	nlohmann::json record(member);
-	std::lock_guard<std::mutex> l(_dbs_l);
+	std::unique_lock<std::shared_mutex> l(_dbs_l);
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 	for(auto d=_dbs.begin();d!=_dbs.end();++d) {
 		if (d->get() != db) {
 		if (d->get() != db) {
 			(*d)->save(record,false);
 			(*d)->save(record,false);

+ 3 - 3
controller/DBMirrorSet.hpp

@@ -18,7 +18,7 @@
 
 
 #include <vector>
 #include <vector>
 #include <memory>
 #include <memory>
-#include <mutex>
+#include <shared_mutex>
 #include <set>
 #include <set>
 #include <thread>
 #include <thread>
 
 
@@ -56,7 +56,7 @@ public:
 	inline void addDB(const std::shared_ptr<DB> &db)
 	inline void addDB(const std::shared_ptr<DB> &db)
 	{
 	{
 		db->addListener(this);
 		db->addListener(this);
-		std::lock_guard<std::mutex> l(_dbs_l);
+		std::unique_lock<std::shared_mutex> l(_dbs_l);
 		_dbs.push_back(db);
 		_dbs.push_back(db);
 	}
 	}
 
 
@@ -65,7 +65,7 @@ private:
 	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::shared_mutex _dbs_l;
 };
 };
 
 
 } // namespace ZeroTier
 } // namespace ZeroTier

Разница между файлами не показана из-за своего большого размера
+ 531 - 544
controller/EmbeddedNetworkController.cpp


+ 36 - 21
controller/EmbeddedNetworkController.hpp

@@ -37,6 +37,8 @@
 
 
 #include <nlohmann/json.hpp>
 #include <nlohmann/json.hpp>
 
 
+#include <cpp-httplib/httplib.h>
+
 #include "DB.hpp"
 #include "DB.hpp"
 #include "DBMirrorSet.hpp"
 #include "DBMirrorSet.hpp"
 
 
@@ -66,27 +68,9 @@ public:
 		const Identity &identity,
 		const Identity &identity,
 		const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
 		const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
 
 
-	unsigned int handleControlPlaneHttpGET(
-		const std::vector<std::string> &path,
-		const std::map<std::string,std::string> &urlArgs,
-		const std::map<std::string,std::string> &headers,
-		const std::string &body,
-		std::string &responseBody,
-		std::string &responseContentType);
-	unsigned int handleControlPlaneHttpPOST(
-		const std::vector<std::string> &path,
-		const std::map<std::string,std::string> &urlArgs,
-		const std::map<std::string,std::string> &headers,
-		const std::string &body,
-		std::string &responseBody,
-		std::string &responseContentType);
-	unsigned int handleControlPlaneHttpDELETE(
-		const std::vector<std::string> &path,
-		const std::map<std::string,std::string> &urlArgs,
-		const std::map<std::string,std::string> &headers,
-		const std::string &body,
-		std::string &responseBody,
-		std::string &responseContentType);
+	void configureHTTPControlPlane(
+		httplib::Server &s,
+		const std::function<void(const httplib::Request&, httplib::Response&, std::string)>);
 
 
 	void handleRemoteTrace(const ZT_RemoteTrace &rt);
 	void handleRemoteTrace(const ZT_RemoteTrace &rt);
 
 
@@ -97,6 +81,9 @@ public:
 private:
 private:
 	void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
 	void _request(uint64_t nwid,const InetAddress &fromAddr,uint64_t requestPacketId,const Identity &identity,const Dictionary<ZT_NETWORKCONFIG_METADATA_DICT_CAPACITY> &metaData);
 	void _startThreads();
 	void _startThreads();
+	void _ssoExpiryThread();
+
+	std::string networkUpdateFromPostData(uint64_t networkID, const std::string &body);
 
 
 	struct _RQEntry
 	struct _RQEntry
 	{
 	{
@@ -160,6 +147,34 @@ private:
 
 
 	RedisConfig *_rc;
 	RedisConfig *_rc;
 	std::string _ssoRedirectURL;
 	std::string _ssoRedirectURL;
+
+	bool _ssoExpiryRunning;
+	std::thread _ssoExpiry;
+
+#ifdef CENTRAL_CONTROLLER_REQUEST_BENCHMARK
+	prometheus::simpleapi::benchmark_family_t _member_status_lookup;
+	prometheus::simpleapi::counter_family_t   _member_status_lookup_count;
+	prometheus::simpleapi::benchmark_family_t _node_is_online;
+	prometheus::simpleapi::counter_family_t   _node_is_online_count;
+	prometheus::simpleapi::benchmark_family_t _get_and_init_member;
+	prometheus::simpleapi::counter_family_t   _get_and_init_member_count;
+	prometheus::simpleapi::benchmark_family_t _have_identity;
+	prometheus::simpleapi::counter_family_t   _have_identity_count;
+	prometheus::simpleapi::benchmark_family_t _determine_auth;
+	prometheus::simpleapi::counter_family_t   _determine_auth_count;
+	prometheus::simpleapi::benchmark_family_t _sso_check;
+	prometheus::simpleapi::counter_family_t   _sso_check_count;
+	prometheus::simpleapi::benchmark_family_t _auth_check;
+	prometheus::simpleapi::counter_family_t   _auth_check_count;
+	prometheus::simpleapi::benchmark_family_t _json_schlep;
+	prometheus::simpleapi::counter_family_t   _json_schlep_count;
+	prometheus::simpleapi::benchmark_family_t _issue_certificate;
+	prometheus::simpleapi::counter_family_t   _issue_certificate_count;
+	prometheus::simpleapi::benchmark_family_t _save_member;
+	prometheus::simpleapi::counter_family_t   _save_member_count;
+	prometheus::simpleapi::benchmark_family_t _send_netconf;
+	prometheus::simpleapi::counter_family_t   _send_netconf_count;
+#endif
 };
 };
 
 
 } // namespace ZeroTier
 } // namespace ZeroTier

+ 8 - 2
controller/FileDB.cpp

@@ -13,6 +13,8 @@
 
 
 #include "FileDB.hpp"
 #include "FileDB.hpp"
 
 
+#include "../node/Metrics.hpp"
+
 namespace ZeroTier
 namespace ZeroTier
 {
 {
 
 
@@ -39,6 +41,7 @@ FileDB::FileDB(const char *path) :
 				if (nwids.length() == 16) {
 				if (nwids.length() == 16) {
 					nlohmann::json nullJson;
 					nlohmann::json nullJson;
 					_networkChanged(nullJson,network,false);
 					_networkChanged(nullJson,network,false);
+					Metrics::network_count++;
 					std::string membersPath(_networksPath + ZT_PATH_SEPARATOR_S + nwids + ZT_PATH_SEPARATOR_S "member");
 					std::string membersPath(_networksPath + ZT_PATH_SEPARATOR_S + nwids + ZT_PATH_SEPARATOR_S "member");
 					std::vector<std::string> members(OSUtils::listDirectory(membersPath.c_str(),false));
 					std::vector<std::string> members(OSUtils::listDirectory(membersPath.c_str(),false));
 					for(auto m=members.begin();m!=members.end();++m) {
 					for(auto m=members.begin();m!=members.end();++m) {
@@ -50,6 +53,7 @@ FileDB::FileDB(const char *path) :
 								if (addrs.length() == 10) {
 								if (addrs.length() == 10) {
 									nlohmann::json nullJson2;
 									nlohmann::json nullJson2;
 									_memberChanged(nullJson2,member,false);
 									_memberChanged(nullJson2,member,false);
+									Metrics::member_count++;
 								}
 								}
 							} catch ( ... ) {}
 							} catch ( ... ) {}
 						}
 						}
@@ -88,8 +92,9 @@ bool FileDB::save(nlohmann::json &record,bool notifyListeners)
 				if ((!old.is_object())||(!_compareRecords(old,record))) {
 				if ((!old.is_object())||(!_compareRecords(old,record))) {
 					record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL;
 					record["revision"] = OSUtils::jsonInt(record["revision"],0ULL) + 1ULL;
 					OSUtils::ztsnprintf(p1,sizeof(p1),"%s" ZT_PATH_SEPARATOR_S "%.16llx.json",_networksPath.c_str(),nwid);
 					OSUtils::ztsnprintf(p1,sizeof(p1),"%s" ZT_PATH_SEPARATOR_S "%.16llx.json",_networksPath.c_str(),nwid);
-					if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1)))
+					if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1))) {
 						fprintf(stderr,"WARNING: controller unable to write to path: %s" ZT_EOL_S,p1);
 						fprintf(stderr,"WARNING: controller unable to write to path: %s" ZT_EOL_S,p1);
+					}
 					_networkChanged(old,record,notifyListeners);
 					_networkChanged(old,record,notifyListeners);
 					modified = true;
 					modified = true;
 				}
 				}
@@ -110,8 +115,9 @@ bool FileDB::save(nlohmann::json &record,bool notifyListeners)
 						OSUtils::ztsnprintf(p2,sizeof(p2),"%s" ZT_PATH_SEPARATOR_S "%.16llx",_networksPath.c_str(),(unsigned long long)nwid);
 						OSUtils::ztsnprintf(p2,sizeof(p2),"%s" ZT_PATH_SEPARATOR_S "%.16llx",_networksPath.c_str(),(unsigned long long)nwid);
 						OSUtils::mkdir(p2);
 						OSUtils::mkdir(p2);
 						OSUtils::mkdir(pb);
 						OSUtils::mkdir(pb);
-						if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1)))
+						if (!OSUtils::writeFile(p1,OSUtils::jsonDump(record,-1))) {
 							fprintf(stderr,"WARNING: controller unable to write to path: %s" ZT_EOL_S,p1);
 							fprintf(stderr,"WARNING: controller unable to write to path: %s" ZT_EOL_S,p1);
+						}
 					}
 					}
 					_memberChanged(old,record,notifyListeners);
 					_memberChanged(old,record,notifyListeners);
 					modified = true;
 					modified = true;

+ 42 - 24
controller/PostgreSQL.cpp

@@ -119,6 +119,7 @@ MemberNotificationReceiver::MemberNotificationReceiver(PostgreSQL *p, pqxx::conn
 
 
 void MemberNotificationReceiver::operator() (const std::string &payload, int packend_pid) {
 void MemberNotificationReceiver::operator() (const std::string &payload, int packend_pid) {
 	fprintf(stderr, "Member Notification received: %s\n", payload.c_str());
 	fprintf(stderr, "Member Notification received: %s\n", payload.c_str());
+	Metrics::pgsql_mem_notification++;
 	json tmp(json::parse(payload));
 	json tmp(json::parse(payload));
 	json &ov = tmp["old_val"];
 	json &ov = tmp["old_val"];
 	json &nv = tmp["new_val"];
 	json &nv = tmp["new_val"];
@@ -141,6 +142,7 @@ NetworkNotificationReceiver::NetworkNotificationReceiver(PostgreSQL *p, pqxx::co
 
 
 void NetworkNotificationReceiver::operator() (const std::string &payload, int packend_pid) {
 void NetworkNotificationReceiver::operator() (const std::string &payload, int packend_pid) {
 	fprintf(stderr, "Network Notification received: %s\n", payload.c_str());
 	fprintf(stderr, "Network Notification received: %s\n", payload.c_str());
+	Metrics::pgsql_net_notification++;
 	json tmp(json::parse(payload));
 	json tmp(json::parse(payload));
 	json &ov = tmp["old_val"];
 	json &ov = tmp["old_val"];
 	json &nv = tmp["new_val"];
 	json &nv = tmp["new_val"];
@@ -372,6 +374,7 @@ void PostgreSQL::nodeIsOnline(const uint64_t networkId, const uint64_t memberId,
 
 
 AuthInfo PostgreSQL::getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL)
 AuthInfo PostgreSQL::getSSOAuthInfo(const nlohmann::json &member, const std::string &redirectURL)
 {
 {
+	Metrics::db_get_sso_info++;
 	// NONCE is just a random character string.  no semantic meaning
 	// NONCE is just a random character string.  no semantic meaning
 	// state = HMAC SHA384 of Nonce based on shared sso key
 	// state = HMAC SHA384 of Nonce based on shared sso key
 	// 
 	// 
@@ -386,9 +389,16 @@ AuthInfo PostgreSQL::getSSOAuthInfo(const nlohmann::json &member, const std::str
 	char authenticationURL[4096] = {0};
 	char authenticationURL[4096] = {0};
 	AuthInfo info;
 	AuthInfo info;
 	info.enabled = true;
 	info.enabled = true;
+
+	//if (memberId == "a10dccea52" && networkId == "8056c2e21c24673d") {
+	//	fprintf(stderr, "invalid authinfo for grant's machine\n");
+	//	info.version=1;
+	//	return info;
+	//}
 	// fprintf(stderr, "PostgreSQL::updateMemberOnLoad: %s-%s\n", networkId.c_str(), memberId.c_str());
 	// fprintf(stderr, "PostgreSQL::updateMemberOnLoad: %s-%s\n", networkId.c_str(), memberId.c_str());
+	std::shared_ptr<PostgresConnection> c;
 	try {
 	try {
-		auto c = _pool->borrow();
+		c = _pool->borrow();
 		pqxx::work w(*c->c);
 		pqxx::work w(*c->c);
 
 
 		char nonceBytes[16] = {0};
 		char nonceBytes[16] = {0};
@@ -450,7 +460,7 @@ AuthInfo PostgreSQL::getSSOAuthInfo(const nlohmann::json &member, const std::str
 			    "LEFT OUTER JOIN ztc_network_oidc_config noc "
 			    "LEFT OUTER JOIN ztc_network_oidc_config noc "
 				"  ON noc.network_id = n.id "
 				"  ON noc.network_id = n.id "
 				"LEFT OUTER JOIN ztc_oidc_config oc "
 				"LEFT OUTER JOIN ztc_oidc_config oc "
-				"  ON noc.client_id = oc.client_id AND noc.org_id = o.org_id "
+				"  ON noc.client_id = oc.client_id AND oc.org_id = o.org_id "
 				"WHERE n.id = $1 AND n.sso_enabled = true", networkId);
 				"WHERE n.id = $1 AND n.sso_enabled = true", networkId);
 		
 		
 			std::string client_id = "";
 			std::string client_id = "";
@@ -460,11 +470,11 @@ AuthInfo PostgreSQL::getSSOAuthInfo(const nlohmann::json &member, const std::str
 			uint64_t sso_version = 0;
 			uint64_t sso_version = 0;
 
 
 			if (r.size() == 1) {
 			if (r.size() == 1) {
-				client_id = r.at(0)[0].as<std::string>();
-				authorization_endpoint = r.at(0)[1].as<std::string>();
-				issuer = r.at(0)[2].as<std::string>();
-				provider = r.at(0)[3].as<std::string>();
-				sso_version = r.at(0)[4].as<uint64_t>();
+				client_id = r.at(0)[0].as<std::optional<std::string>>().value_or("");
+				authorization_endpoint = r.at(0)[1].as<std::optional<std::string>>().value_or("");
+				issuer = r.at(0)[2].as<std::optional<std::string>>().value_or("");
+				provider = r.at(0)[3].as<std::optional<std::string>>().value_or("");
+				sso_version = r.at(0)[4].as<std::optional<uint64_t>>().value_or(1);
 			} else if (r.size() > 1) {
 			} else if (r.size() > 1) {
 				fprintf(stderr, "ERROR: More than one auth endpoint for an organization?!?!? NetworkID: %s\n", networkId.c_str());
 				fprintf(stderr, "ERROR: More than one auth endpoint for an organization?!?!? NetworkID: %s\n", networkId.c_str());
 			} else {
 			} else {
@@ -705,6 +715,8 @@ void PostgreSQL::initializeNetworks()
 				}
 				}
 			}
 			}
 
 
+			Metrics::network_count++;
+
 		 	_networkChanged(empty, config, false);
 		 	_networkChanged(empty, config, false);
 
 
 			auto end = std::chrono::high_resolution_clock::now();
 			auto end = std::chrono::high_resolution_clock::now();
@@ -772,7 +784,7 @@ void PostgreSQL::initializeMembers()
 
 
 		if (_redisMemberStatus) {
 		if (_redisMemberStatus) {
 			fprintf(stderr, "Initialize Redis for members...\n");
 			fprintf(stderr, "Initialize Redis for members...\n");
-			std::lock_guard<std::mutex> l(_networks_l);
+			std::unique_lock<std::shared_mutex> l(_networks_l);
 			std::unordered_set<std::string> deletes;
 			std::unordered_set<std::string> deletes;
 			for ( auto it : _networks) {
 			for ( auto it : _networks) {
 				uint64_t nwid_i = it.first;
 				uint64_t nwid_i = it.first;
@@ -925,6 +937,8 @@ void PostgreSQL::initializeMembers()
 				}
 				}
 			}
 			}
 
 
+			Metrics::member_count++;
+
 			_memberChanged(empty, config, false);
 			_memberChanged(empty, config, false);
 
 
 			memberId = "";
 			memberId = "";
@@ -1011,8 +1025,6 @@ void PostgreSQL::heartbeat()
 		int64_t ts = OSUtils::now();
 		int64_t ts = OSUtils::now();
 
 
 		if(c->c) {
 		if(c->c) {
-			pqxx::work w{*c->c};
-
 			std::string major = std::to_string(ZEROTIER_ONE_VERSION_MAJOR);
 			std::string major = std::to_string(ZEROTIER_ONE_VERSION_MAJOR);
 			std::string minor = std::to_string(ZEROTIER_ONE_VERSION_MINOR);
 			std::string minor = std::to_string(ZEROTIER_ONE_VERSION_MINOR);
 			std::string rev = std::to_string(ZEROTIER_ONE_VERSION_REVISION);
 			std::string rev = std::to_string(ZEROTIER_ONE_VERSION_REVISION);
@@ -1023,21 +1035,23 @@ void PostgreSQL::heartbeat()
 			std::string redis_mem_status = (_redisMemberStatus) ? "true" : "false";
 			std::string redis_mem_status = (_redisMemberStatus) ? "true" : "false";
 			
 			
 			try {
 			try {
-			pqxx::result res = w.exec0("INSERT INTO ztc_controller (id, cluster_host, last_alive, public_identity, v_major, v_minor, v_rev, v_build, host_port, use_redis, redis_member_status) "
-				"VALUES ("+w.quote(controllerId)+", "+w.quote(hostname)+", TO_TIMESTAMP("+now+"::double precision/1000), "+
-				w.quote(publicIdentity)+", "+major+", "+minor+", "+rev+", "+build+", "+host_port+", "+use_redis+", "+redis_mem_status+") "
-				"ON CONFLICT (id) DO UPDATE SET cluster_host = EXCLUDED.cluster_host, last_alive = EXCLUDED.last_alive, "
-				"public_identity = EXCLUDED.public_identity, v_major = EXCLUDED.v_major, v_minor = EXCLUDED.v_minor, "
-				"v_rev = EXCLUDED.v_rev, v_build = EXCLUDED.v_rev, host_port = EXCLUDED.host_port, "
-				"use_redis = EXCLUDED.use_redis, redis_member_status = EXCLUDED.redis_member_status");
+				pqxx::work w{*c->c};
+
+				pqxx::result res =
+					w.exec0("INSERT INTO ztc_controller (id, cluster_host, last_alive, public_identity, v_major, v_minor, v_rev, v_build, host_port, use_redis, redis_member_status) "
+							"VALUES ("+w.quote(controllerId)+", "+w.quote(hostname)+", TO_TIMESTAMP("+now+"::double precision/1000), "+
+							w.quote(publicIdentity)+", "+major+", "+minor+", "+rev+", "+build+", "+host_port+", "+use_redis+", "+redis_mem_status+") "
+							"ON CONFLICT (id) DO UPDATE SET cluster_host = EXCLUDED.cluster_host, last_alive = EXCLUDED.last_alive, "
+							"public_identity = EXCLUDED.public_identity, v_major = EXCLUDED.v_major, v_minor = EXCLUDED.v_minor, "
+							"v_rev = EXCLUDED.v_rev, v_build = EXCLUDED.v_rev, host_port = EXCLUDED.host_port, "
+							"use_redis = EXCLUDED.use_redis, redis_member_status = EXCLUDED.redis_member_status");
+				w.commit();
 			} catch (std::exception &e) {
 			} catch (std::exception &e) {
-				fprintf(stderr, "Heartbeat update failed: %s\n", e.what());
-				w.abort();
-				_pool->unborrow(c);
+				fprintf(stderr, "%s: Heartbeat update failed: %s\n", controllerId, e.what());
 				std::this_thread::sleep_for(std::chrono::milliseconds(1000));
 				std::this_thread::sleep_for(std::chrono::milliseconds(1000));
 				continue;
 				continue;
-			}		
-			w.commit();
+			}
+
 		}
 		}
 		_pool->unborrow(c);
 		_pool->unborrow(c);
 
 
@@ -1138,6 +1152,7 @@ void PostgreSQL::_membersWatcher_Redis() {
 							_redis->xdel(key, id);
 							_redis->xdel(key, id);
 						}
 						}
 						lastID = id;
 						lastID = id;
+						Metrics::redis_mem_notification++;
 					}
 					}
 				}
 				}
 			}
 			}
@@ -1228,6 +1243,7 @@ void PostgreSQL::_networksWatcher_Redis() {
 						}
 						}
 						lastID = id;
 						lastID = id;
 					}
 					}
+					Metrics::redis_net_notification++;
 				}
 				}
 			}
 			}
 		} catch (sw::redis::Error &e) {
 		} catch (sw::redis::Error &e) {
@@ -1261,6 +1277,7 @@ void PostgreSQL::commitThread()
 			continue;
 			continue;
 		}
 		}
 		
 		
+		Metrics::pgsql_commit_ticks++;
 		try {
 		try {
 			nlohmann::json &config = (qitem.first);
 			nlohmann::json &config = (qitem.first);
 			const std::string objtype = config["objtype"];
 			const std::string objtype = config["objtype"];
@@ -1587,7 +1604,6 @@ void PostgreSQL::commitThread()
 		}
 		}
 		_pool->unborrow(c);
 		_pool->unborrow(c);
 		c.reset();
 		c.reset();
-		std::this_thread::sleep_for(std::chrono::milliseconds(100));
 	}
 	}
 
 
 	fprintf(stderr, "%s commitThread finished\n", _myAddressStr.c_str());
 	fprintf(stderr, "%s commitThread finished\n", _myAddressStr.c_str());
@@ -1679,6 +1695,7 @@ void PostgreSQL::onlineNotification_Postgres()
 					<< " ON CONFLICT (network_id, member_id) DO UPDATE SET address = EXCLUDED.address, last_updated = EXCLUDED.last_updated";
 					<< " ON CONFLICT (network_id, member_id) DO UPDATE SET address = EXCLUDED.address, last_updated = EXCLUDED.last_updated";
 
 
 				pipe.insert(memberUpdate.str());
 				pipe.insert(memberUpdate.str());
+				Metrics::pgsql_node_checkin++;
 			}
 			}
 			while(!pipe.empty()) {
 			while(!pipe.empty()) {
 				pipe.retrieve();
 				pipe.retrieve();
@@ -1786,6 +1803,7 @@ uint64_t PostgreSQL::_doRedisUpdate(sw::redis::Transaction &tx, std::string &con
 			.sadd("network-nodes-all:{"+controllerId+"}:"+networkId, memberId)
 			.sadd("network-nodes-all:{"+controllerId+"}:"+networkId, memberId)
 			.hmset("member:{"+controllerId+"}:"+networkId+":"+memberId, record.begin(), record.end());
 			.hmset("member:{"+controllerId+"}:"+networkId+":"+memberId, record.begin(), record.end());
 		++count;
 		++count;
+		Metrics::redis_node_checkin++;
 	}
 	}
 
 
 	// expire records from all-nodes and network-nodes member list
 	// expire records from all-nodes and network-nodes member list
@@ -1801,7 +1819,7 @@ uint64_t PostgreSQL::_doRedisUpdate(sw::redis::Transaction &tx, std::string &con
 						sw::redis::RightBoundedInterval<double>(expireOld,
 						sw::redis::RightBoundedInterval<double>(expireOld,
 																sw::redis::BoundType::LEFT_OPEN));
 																sw::redis::BoundType::LEFT_OPEN));
 	{
 	{
-		std::lock_guard<std::mutex> l(_networks_l);
+		std::shared_lock<std::shared_mutex> l(_networks_l);
 		for (const auto &it : _networks) {
 		for (const auto &it : _networks) {
 			uint64_t nwid_i = it.first;
 			uint64_t nwid_i = it.first;
 			char nwidTmp[64];
 			char nwidTmp[64];

+ 3 - 0
controller/PostgreSQL.hpp

@@ -26,6 +26,8 @@
 #include <memory>
 #include <memory>
 #include <redis++/redis++.h>
 #include <redis++/redis++.h>
 
 
+#include "../node/Metrics.hpp"
+
 extern "C" {
 extern "C" {
 typedef struct pg_conn PGconn;
 typedef struct pg_conn PGconn;
 }
 }
@@ -53,6 +55,7 @@ public:
 	}
 	}
 
 
 	virtual std::shared_ptr<Connection> create() {
 	virtual std::shared_ptr<Connection> create() {
+		Metrics::conn_counter++;
 		auto c = std::shared_ptr<PostgresConnection>(new PostgresConnection());
 		auto c = std::shared_ptr<PostgresConnection>(new PostgresConnection());
 		c->c = std::make_shared<pqxx::connection>(m_connString);
 		c->c = std::make_shared<pqxx::connection>(m_connString);
 		return std::static_pointer_cast<Connection>(c);
 		return std::static_pointer_cast<Connection>(c);

+ 12 - 209
controller/README.md

@@ -3,7 +3,7 @@ Network Controller Microservice
 
 
 Every ZeroTier virtual network has a *network controller* responsible for admitting members to the network, issuing certificates, and issuing default configuration information.
 Every ZeroTier virtual network has a *network controller* responsible for admitting members to the network, issuing certificates, and issuing default configuration information.
 
 
-This is our reference controller implementation and is the same one we use to power our own hosted services at [my.zerotier.com](https://my.zerotier.com/). As of ZeroTier One version 1.2.0 this code is included in normal builds for desktop, laptop, and server (Linux, etc.) targets.
+This is our reference controller implementation and is almost the same as the one we use to power our own hosted services at [my.zerotier.com](https://my.zerotier.com/). The only difference is the database backend used. 
 
 
 Controller data is stored in JSON format under `controller.d` in the ZeroTier working directory. It can be copied, rsync'd, placed in `git`, etc. The files under `controller.d` should not be modified in place while the controller is running or data loss may result, and if they are edited directly take care not to save corrupt JSON since that can also lead to data loss when the controller is restarted. Going through the API is strongly preferred to directly modifying these files.
 Controller data is stored in JSON format under `controller.d` in the ZeroTier working directory. It can be copied, rsync'd, placed in `git`, etc. The files under `controller.d` should not be modified in place while the controller is running or data loss may result, and if they are edited directly take care not to save corrupt JSON since that can also lead to data loss when the controller is restarted. Going through the API is strongly preferred to directly modifying these files.
 
 
@@ -19,10 +19,6 @@ Since ZeroTier nodes are mobile and do not need static IPs, implementing high av
 
 
 ZeroTier network controllers can easily be run in Docker or other container systems. Since containers do not need to actually join networks, extra privilege options like "--device=/dev/net/tun --privileged" are not needed. You'll just need to map the local JSON API port of the running controller and allow it to access the Internet (over UDP/9993 at a minimum) so things can reach and query it.
 ZeroTier network controllers can easily be run in Docker or other container systems. Since containers do not need to actually join networks, extra privilege options like "--device=/dev/net/tun --privileged" are not needed. You'll just need to map the local JSON API port of the running controller and allow it to access the Internet (over UDP/9993 at a minimum) so things can reach and query it.
 
 
-### PostgreSQL Database Implementation
-
-The default controller stores its data in the filesystem in `controller.d` under ZeroTier's home folder. There's an alternative implementation that stores data in PostgreSQL that can be built with `make central-controller`. Right now this is only guaranteed to build and run on Centos 7 Linux with PostgreSQL 10 installed via the [PostgreSQL Yum Repository](https://www.postgresql.org/download/linux/redhat/) and is designed for use with [ZeroTier Central](https://my.zerotier.com/). You're welcome to use it but we don't "officially" support it for end-user use and it could change at any time.
-
 ### Upgrading from Older (1.1.14 or earlier) Versions
 ### Upgrading from Older (1.1.14 or earlier) Versions
 
 
 Older versions of this code used a SQLite database instead of in-filesystem JSON. A migration utility called `migrate-sqlite` is included here and *must* be used to migrate this data to the new format. If the controller is started with an old `controller.db` in its working directory it will terminate after printing an error to *stderr*. This is done to prevent "surprises" for those running DIY controllers using the old code.
 Older versions of this code used a SQLite database instead of in-filesystem JSON. A migration utility called `migrate-sqlite` is included here and *must* be used to migrate this data to the new format. If the controller is started with an old `controller.db` in its working directory it will terminate after printing an error to *stderr*. This is done to prevent "surprises" for those running DIY controllers using the old code.
@@ -43,210 +39,17 @@ While networks with any valid ID can be added to the controller's database, it w
 
 
 The controller JSON API is *very* sensitive about types. Integers must be integers and strings strings, etc. Incorrect types may be ignored, set to default values, or set to undefined values.
 The controller JSON API is *very* sensitive about types. Integers must be integers and strings strings, etc. Incorrect types may be ignored, set to default values, or set to undefined values.
 
 
-#### `/controller`
-
- * Purpose: Check for controller function and return controller status
- * Methods: GET
- * Returns: { object }
-
-| Field              | Type        | Description                                       | Writable |
-| ------------------ | ----------- | ------------------------------------------------- | -------- |
-| controller         | boolean     | Always 'true'                                     | no       |
-| apiVersion         | integer     | Controller API version, currently 3               | no       |
-| clock              | integer     | Current clock on controller, ms since epoch       | no       |
-
-#### `/controller/network`
-
- * Purpose: List all networks hosted by this controller
- * Methods: GET
- * Returns: [ string, ... ]
-
-This returns an array of 16-digit hexadecimal network IDs.
-
-#### `/controller/network/<network ID>`
-
- * Purpose: Create, configure, and delete hosted networks
- * Methods: GET, POST, DELETE
- * Returns: { object }
-
-By making queries to this path you can create, configure, and delete networks. DELETE is final, so don't do it unless you really mean it.
-
-When POSTing new networks take care that their IDs are not in use, otherwise you may overwrite an existing one. To create a new network with a random unused ID, POST to `/controller/network/##########______`. The #'s are the controller's 10-digit ZeroTier address and they're followed by six underscores. Check the `nwid` field of the returned JSON object for your network's newly allocated ID. Subsequent POSTs to this network must refer to its actual path.
-
-Example:
-
-`curl -X POST --header "X-ZT1-Auth: secret" -d '{"name":"my network"}' http://localhost:9993/controller/network/305f406058______`
-
-**Network object format:**
-
-| Field                 | Type          | Description                                       | Writable |
-| --------------------- | ------------- | ------------------------------------------------- | -------- |
-| id                    | string        | 16-digit network ID                               | no       |
-| nwid                  | string        | 16-digit network ID (legacy)                      | no       |
-| objtype               | string        | Always "network"                                  | no       |
-| name                  | string        | A short name for this network                     | YES      |
-| creationTime          | integer       | Time network record was created (ms since epoch)  | no       |
-| private               | boolean       | Is access control enabled?                        | YES      |
-| enableBroadcast       | boolean       | Ethernet ff:ff:ff:ff:ff:ff allowed?               | YES      |
-| v4AssignMode          | object        | IPv4 management and assign options (see below)    | YES      |
-| v6AssignMode          | object        | IPv6 management and assign options (see below)    | YES      |
-| mtu                   | integer       | Network MTU (default: 2800)                       | YES      |
-| multicastLimit        | integer       | Maximum recipients for a multicast packet         | YES      |
-| revision              | integer       | Network config revision counter                   | no       |
-| routes                | array[object] | Managed IPv4 and IPv6 routes; see below           | YES      |
-| ipAssignmentPools     | array[object] | IP auto-assign ranges; see below                  | YES      |
-| rules                 | array[object] | Traffic rules; see below                          | YES      |
-| capabilities          | array[object] | Array of capability objects (see below)           | YES      |
-| tags                  | array[object] | Array of tag objects (see below)                  | YES      |
-| remoteTraceTarget     | string        | 10-digit ZeroTier ID of remote trace target       | YES      |
-| remoteTraceLevel      | integer       | Remote trace verbosity level                      | YES      |
-
- * Networks without rules won't carry any traffic. If you don't specify any on network creation an "accept anything" rule set will automatically be added.
- * Managed IP address assignments and IP assignment pools that do not fall within a route configured in `routes` are ignored and won't be used or sent to members.
- * The default for `private` is `true` and this is probably what you want. Turning `private` off means *anyone* can join your network with only its 16-digit network ID. It's also impossible to de-authorize a member as these networks don't issue or enforce certificates. Such "party line" networks are used for decentralized app backplanes, gaming, and testing but are otherwise not common.
- * Changing the MTU can be disruptive and on some operating systems may require a leave/rejoin of the network or a restart of the ZeroTier service.
-
-**Auto-Assign Modes:**
-
-Auto assign modes (`v4AssignMode` and `v6AssignMode`) contain objects that map assignment modes to booleans.
-
-For IPv4 the only valid setting is `zt` which, if true, causes IPv4 addresses to be auto-assigned from `ipAssignmentPools` to members that do not have an IPv4 assignment. Note that active bridges are exempt and will not get auto-assigned IPs since this can interfere with bridging. (You can still manually assign one if you want.)
-
-IPv6 includes this option and two others: `6plane` and `rfc4193`. These assign private IPv6 addresses to each member based on a deterministic assignment scheme that allows members to emulate IPv6 NDP to skip multicast for better performance and scalability. The `rfc4193` mode gives every member a /128 on a /88 network, while `6plane` gives every member a /80 within a /40 network but uses NDP emulation to route *all* IPs under that /80 to its owner. The `6plane` mode is great for use cases like Docker since it allows every member to assign IPv6 addresses within its /80 that just work instantly and globally across the network.
-
-**IP assignment pool object format:**
-
-| Field                 | Type          | Description                                       |
-| --------------------- | ------------- | ------------------------------------------------- |
-| ipRangeStart          | string        | Starting IP address in range                      |
-| ipRangeEnd            | string        | Ending IP address in range (inclusive)            |
-
-Pools are only used if auto-assignment is on for the given address type (IPv4 or IPv6) and if the entire range falls within a managed route.
-
-IPv6 ranges work just like IPv4 ranges and look like this:
-
-    {
-        "ipRangeStart": "fd00:feed:feed:beef:0000:0000:0000:0000",
-        "ipRangeEnd": "fd00:feed:feed:beef:ffff:ffff:ffff:ffff"
-    }
-
-(You can POST a shortened-form IPv6 address but the API will always report back un-shortened canonical form addresses.)
-
-That defines a range within network `fd00:feed:feed:beef::/64` that contains up to 2^64 addresses. If an IPv6 range is large enough, the controller will assign addresses by placing each member's device ID into the address in a manner similar to the RFC4193 and 6PLANE modes. Otherwise it will assign addresses at random.
-
-**Managed Route object format:**
+Full documentation of the Controller API can be found on our [documentation site](https://docs.zerotier.com/service/v1#tag/controller)
 
 
-| Field                 | Type          | Description                                       |
-| --------------------- | ------------- | ------------------------------------------------- |
-| target                | string        | Subnet in CIDR notation                           |
-| via                   | string/null   | Next hop router IP address                        |
+### Prometheus Metrics
 
 
-Managed Route objects look like this:
-
-      {
-        "target": "10.147.20.0/24"
-      }
-
-or 
-
-      {
-        "target": "192.168.168.0/24",
-        "via": "10.147.20.1"
-      }
-
-**Rule object format:**
-
-Each rule is actually a sequence of zero or more `MATCH_` entries in the rule array followed by an `ACTION_` entry that describes what to do if all the preceding entries match. An `ACTION_` without any preceding `MATCH_` entries is always taken, so setting a single `ACTION_ACCEPT` rule yields a network that allows all traffic. If no rules are present the default action is `ACTION_DROP`.
-
-Rules are evaluated in the order in which they appear in the array. There is currently a limit of 256 entries per network. Capabilities should be used if a larger and more complex rule set is needed since they allow rules to be grouped by purpose and only shipped to members that need them.
-
-Each rule table entry has two common fields.
-
-| Field                 | Type          | Description                                       |
-| --------------------- | ------------- | ------------------------------------------------- |
-| type                  | string        | Entry type (all caps, case sensitive)             |
-| not                   | boolean       | If true, MATCHes match if they don't match        |
-
-The following fields may or may not be present depending on rule type:
-
-| Field                 | Type          | Description                                       |
-| --------------------- | ------------- | ------------------------------------------------- |
-| zt                    | string        | 10-digit hex ZeroTier address                     |
-| etherType             | integer       | Ethernet frame type                               |
-| mac                   | string        | Hex MAC address (with or without :'s)             |
-| ip                    | string        | IPv4 or IPv6 address                              |
-| ipTos                 | integer       | IP type of service                                |
-| ipProtocol            | integer       | IP protocol (e.g. TCP)                            |
-| start                 | integer       | Start of an integer range (e.g. port range)       |
-| end                   | integer       | End of an integer range (inclusive)               |
-| id                    | integer       | Tag ID                                            |
-| value                 | integer       | Tag value or comparison value                     |
-| mask                  | integer       | Bit mask (for characteristics flags)              |
-
-The entry types and their additional fields are:
-
-| Entry type                      | Description                                                       | Fields         |
-| ------------------------------- | ----------------------------------------------------------------- | -------------- |
-| `ACTION_DROP`                   | Drop any packets matching this rule                               | (none)         |
-| `ACTION_ACCEPT`                 | Accept any packets matching this rule                             | (none)         |
-| `ACTION_TEE`                    | Send a copy of this packet to a node (rule parsing continues)     | `zt`           |
-| `ACTION_REDIRECT`               | Redirect this packet to another node                              | `zt`           |
-| `ACTION_DEBUG_LOG`              | Output debug info on match (if built with rules engine debug)     | (none)         |
-| `MATCH_SOURCE_ZEROTIER_ADDRESS` | Match VL1 ZeroTier address of packet sender.                      | `zt`           |
-| `MATCH_DEST_ZEROTIER_ADDRESS`   | Match VL1 ZeroTier address of recipient                           | `zt`           |
-| `MATCH_ETHERTYPE`               | Match Ethernet frame type                                         | `etherType`    |
-| `MATCH_MAC_SOURCE`              | Match source Ethernet MAC address                                 | `mac`          |
-| `MATCH_MAC_DEST`                | Match destination Ethernet MAC address                            | `mac`          |
-| `MATCH_IPV4_SOURCE`             | Match source IPv4 address                                         | `ip`           |
-| `MATCH_IPV4_DEST`               | Match destination IPv4 address                                    | `ip`           |
-| `MATCH_IPV6_SOURCE`             | Match source IPv6 address                                         | `ip`           |
-| `MATCH_IPV6_DEST`               | Match destination IPv6 address                                    | `ip`           |
-| `MATCH_IP_TOS`                  | Match IP TOS field                                                | `ipTos`        |
-| `MATCH_IP_PROTOCOL`             | Match IP protocol field                                           | `ipProtocol`   |
-| `MATCH_IP_SOURCE_PORT_RANGE`    | Match a source IP port range                                      | `start`,`end`  |
-| `MATCH_IP_DEST_PORT_RANGE`      | Match a destination IP port range                                 | `start`,`end`  |
-| `MATCH_CHARACTERISTICS`         | Match on characteristics flags                                    | `mask`,`value` |
-| `MATCH_FRAME_SIZE_RANGE`        | Match a range of Ethernet frame sizes                             | `start`,`end`  |
-| `MATCH_TAGS_SAMENESS`           | Match if both sides' tags differ by no more than value            | `id`,`value`   |
-| `MATCH_TAGS_BITWISE_AND`        | Match if both sides' tags AND to value                            | `id`,`value`   |
-| `MATCH_TAGS_BITWISE_OR`         | Match if both sides' tags OR to value                             | `id`,`value`   |
-| `MATCH_TAGS_BITWISE_XOR`        | Match if both sides' tags XOR to value                            | `id`,`value`   |
-
-Important notes about rules engine behavior:
-
- * IPv4 and IPv6 IP address rules do not match for frames that are not IPv4 or IPv6 respectively.
- * `ACTION_DEBUG_LOG` is a no-op on nodes not built with `ZT_RULES_ENGINE_DEBUGGING` enabled (see Network.cpp). If that is enabled nodes will dump a trace of rule evaluation results to *stdout* when this action is encountered but will otherwise keep evaluating rules. This is used for basic "smoke testing" of the rules engine.
- * Multicast packets and packets destined for bridged devices treated a little differently. They are matched more than once. They are matched at the point of send with a NULL ZeroTier destination address, meaning that `MATCH_DEST_ZEROTIER_ADDRESS` is useless. That's because the true VL1 destination is not yet known. Then they are matched again for each true VL1 destination. On these later subsequent matches TEE actions are ignored and REDIRECT rules are interpreted as DROPs. This prevents multiple TEE or REDIRECT packets from being sent to third party devices.
- * Rules in capabilities are always matched as if the current device is the sender (inbound == false). A capability specifies sender side rules that can be enforced on both sides.
-
-#### `/controller/network/<network ID>/member`
-
- * Purpose: Get a set of all members on this network
- * Methods: GET
- * Returns: { object }
-
-This returns a JSON object containing all member IDs as keys and their `memberRevisionCounter` values as values.
-
-#### `/controller/network/<network ID>/member/<address>`
-
- * Purpose: Create, authorize, or remove a network member
- * Methods: GET, POST, DELETE
- * Returns: { object }
-
-| Field                 | Type          | Description                                       | Writable |
-| --------------------- | ------------- | ------------------------------------------------- | -------- |
-| id                    | string        | Member's 10-digit ZeroTier address                | no       |
-| address               | string        | Member's 10-digit ZeroTier address                | no       |
-| nwid                  | string        | 16-digit network ID                               | no       |
-| authorized            | boolean       | Is member authorized? (for private networks)      | YES      |
-| activeBridge          | boolean       | Member is able to bridge to other Ethernet nets   | YES      |
-| identity              | string        | Member's public ZeroTier identity (if known)      | no       |
-| ipAssignments         | array[string] | Managed IP address assignments                    | YES      |
-| revision              | integer       | Member revision counter                           | no       |
-| vMajor                | integer       | Most recently known major version                 | no       |
-| vMinor                | integer       | Most recently known minor version                 | no       |
-| vRev                  | integer       | Most recently known revision                      | no       |
-| vProto                | integer       | Most recently known protocol version               | no       |
-
-Note that managed IP assignments are only used if they fall within a managed route. Otherwise they are ignored.
+Controller specific metrics are available from the `/metrics` endpoint.
 
 
+| Metric Name | Type | Description |
+| --- | --- | --- |
+| controller_network_count | Gauge | number of networks the controller is serving | 
+| controller_member_count | Gauge | number of network members the controller is serving |
+| controller_network_change_count | Counter | number of times a network configuration is changed |
+| controller_member_change_count | Counter | number of times a network member configuration is changed |
+| controller_member_auth_count | Counter | number of network member auths |
+| controller_member_deauth_count | Counter | number of network member deauths|

+ 6 - 0
debian/changelog

@@ -1,3 +1,9 @@
+zerotier-one (1.12.0) unstable; urgency=medium
+
+  * See RELEASE-NOTES.md for release notes.
+
+ -- Adam Ierymenko <[email protected]>  Thu, 17 Aug 2023 01:00:00 -0700
+
 zerotier-one (1.10.6) unstable; urgency=medium
 zerotier-one (1.10.6) unstable; urgency=medium
 
 
   * See RELEASE-NOTES.md for release notes.
   * See RELEASE-NOTES.md for release notes.

+ 1 - 1
debian/compat

@@ -1 +1 @@
-8
+10

+ 1 - 1
debian/control

@@ -3,7 +3,7 @@ Maintainer: Adam Ierymenko <[email protected]>
 Section: net
 Section: net
 Priority: optional
 Priority: optional
 Standards-Version: 3.9.6
 Standards-Version: 3.9.6
-Build-Depends: debhelper (>= 9)
+Build-Depends: debhelper
 Vcs-Git: git://github.com/zerotier/ZeroTierOne
 Vcs-Git: git://github.com/zerotier/ZeroTierOne
 Vcs-Browser: https://github.com/zerotier/ZeroTierOne
 Vcs-Browser: https://github.com/zerotier/ZeroTierOne
 Homepage: https://www.zerotier.com/
 Homepage: https://www.zerotier.com/

+ 2 - 2
entrypoint.sh.release

@@ -81,7 +81,7 @@ done
 if [ "x$ZEROTIER_JOIN_NETWORKS" != "x" ]
 if [ "x$ZEROTIER_JOIN_NETWORKS" != "x" ]
 then
 then
   log_params "Joining networks from environment:" $ZEROTIER_JOIN_NETWORKS
   log_params "Joining networks from environment:" $ZEROTIER_JOIN_NETWORKS
-  for i in "$ZEROTIER_JOIN_NETWORKS"
+  for i in $ZEROTIER_JOIN_NETWORKS
   do
   do
     log_detail_params "Configuring join:" "$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"
@@ -107,7 +107,7 @@ log_params "Writing healthcheck for networks:" $@
 
 
 cat >/healthcheck.sh <<EOF
 cat >/healthcheck.sh <<EOF
 #!/bin/bash
 #!/bin/bash
-for i in $@
+for i in $@ $ZEROTIER_JOIN_NETWORKS
 do
 do
   [ "\$(zerotier-cli get \$i status)" = "OK" ] || exit 1
   [ "\$(zerotier-cli get \$i status)" = "OK" ] || exit 1
 done
 done

+ 0 - 36
ext/bin/tap-mac/tap.kext/Contents/Info.plist

@@ -1,36 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>CFBundleDevelopmentRegion</key>
-	<string>English</string>
-	<key>CFBundleExecutable</key>
-	<string>tap</string>
-	<key>CFBundleIdentifier</key>
-	<string>com.zerotier.tap</string>
-	<key>CFBundleInfoDictionaryVersion</key>
-	<string>6.0</string>
-	<key>CFBundleName</key>
-	<string>tap</string>
-	<key>CFBundlePackageType</key>
-	<string>KEXT</string>
-	<key>CFBundleShortVersionString</key>
-	<string>20150118</string>
-	<key>CFBundleSignature</key>
-	<string>????</string>
-	<key>CFBundleVersion</key>
-	<string>1.0</string>
-	<key>OSBundleLibraries</key>
-	<dict>
-		<key>com.apple.kpi.mach</key>
-		<string>8.0</string>
-		<key>com.apple.kpi.bsd</key>
-		<string>8.0</string>
-		<key>com.apple.kpi.libkern</key>
-		<string>8.0</string>
-		<key>com.apple.kpi.unsupported</key>
-		<string>8.0</string>
-	</dict>
-</dict>
-</plist>
-

BIN
ext/bin/tap-mac/tap.kext/Contents/MacOS/tap


+ 0 - 105
ext/bin/tap-mac/tap.kext/Contents/_CodeSignature/CodeResources

@@ -1,105 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-	<key>files</key>
-	<dict/>
-	<key>files2</key>
-	<dict/>
-	<key>rules</key>
-	<dict>
-		<key>^Resources/</key>
-		<true/>
-		<key>^Resources/.*\.lproj/</key>
-		<dict>
-			<key>optional</key>
-			<true/>
-			<key>weight</key>
-			<real>1000</real>
-		</dict>
-		<key>^Resources/.*\.lproj/locversion.plist$</key>
-		<dict>
-			<key>omit</key>
-			<true/>
-			<key>weight</key>
-			<real>1100</real>
-		</dict>
-		<key>^version.plist$</key>
-		<true/>
-	</dict>
-	<key>rules2</key>
-	<dict>
-		<key>.*\.dSYM($|/)</key>
-		<dict>
-			<key>weight</key>
-			<real>11</real>
-		</dict>
-		<key>^(.*/)?\.DS_Store$</key>
-		<dict>
-			<key>omit</key>
-			<true/>
-			<key>weight</key>
-			<real>2000</real>
-		</dict>
-		<key>^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/</key>
-		<dict>
-			<key>nested</key>
-			<true/>
-			<key>weight</key>
-			<real>10</real>
-		</dict>
-		<key>^.*</key>
-		<true/>
-		<key>^Info\.plist$</key>
-		<dict>
-			<key>omit</key>
-			<true/>
-			<key>weight</key>
-			<real>20</real>
-		</dict>
-		<key>^PkgInfo$</key>
-		<dict>
-			<key>omit</key>
-			<true/>
-			<key>weight</key>
-			<real>20</real>
-		</dict>
-		<key>^Resources/</key>
-		<dict>
-			<key>weight</key>
-			<real>20</real>
-		</dict>
-		<key>^Resources/.*\.lproj/</key>
-		<dict>
-			<key>optional</key>
-			<true/>
-			<key>weight</key>
-			<real>1000</real>
-		</dict>
-		<key>^Resources/.*\.lproj/locversion.plist$</key>
-		<dict>
-			<key>omit</key>
-			<true/>
-			<key>weight</key>
-			<real>1100</real>
-		</dict>
-		<key>^[^/]+$</key>
-		<dict>
-			<key>nested</key>
-			<true/>
-			<key>weight</key>
-			<real>10</real>
-		</dict>
-		<key>^embedded\.provisionprofile$</key>
-		<dict>
-			<key>weight</key>
-			<real>20</real>
-		</dict>
-		<key>^version\.plist$</key>
-		<dict>
-			<key>weight</key>
-			<real>20</real>
-		</dict>
-	</dict>
-</dict>
-</plist>

BIN
ext/bin/tap-windows-ndis6/arm64/zttap300.cat


+ 19 - 17
ext/bin/tap-windows-ndis6/x64.old/zttap300.inf → ext/bin/tap-windows-ndis6/arm64/zttap300.inf

@@ -1,9 +1,14 @@
 ;
 ;
-; ZeroTier One Virtual Network Port NDIS6 Driver
+; ****************************************************************************
+; * Copyright (C) 2002-2014 OpenVPN Technologies, Inc.                       *
+; *  This program is free software; you can redistribute it and/or modify    *
+; *  it under the terms of the GNU General Public License version 2          *
+; *  as published by the Free Software Foundation.                           *
+; ****************************************************************************
 ;
 ;
-; Based on the OpenVPN tap-windows6 driver version 9.21.1 git
-; commit 48f027cfca52b16b5fd23d82e6016ed8a91fc4d3.
-; See: https://github.com/OpenVPN/tap-windows6
+
+;
+; ZeroTier One Virtual Network Port NDIS6 Driver
 ;
 ;
 ; Modified by ZeroTier, Inc. - https://www.zerotier.com/
 ; Modified by ZeroTier, Inc. - https://www.zerotier.com/
 ;
 ;
@@ -15,14 +20,6 @@
 ; (5) Rename/rebrand driver as ZeroTier network port driver.
 ; (5) Rename/rebrand driver as ZeroTier network port driver.
 ;
 ;
 ; Original copyright below. Modifications released under GPLv2 as well.
 ; Original copyright below. Modifications released under GPLv2 as well.
-;
-; ****************************************************************************
-; * Copyright (C) 2002-2014 OpenVPN Technologies, Inc.                       *
-; *  This program is free software; you can redistribute it and/or modify    *
-; *  it under the terms of the GNU General Public License version 2          *
-; *  as published by the Free Software Foundation.                           *
-; ****************************************************************************
-;
 
 
 [Version]
 [Version]
 Signature = "$Windows NT$"
 Signature = "$Windows NT$"
@@ -30,17 +27,18 @@ CatalogFile = zttap300.cat
 ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
 ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
 Provider = %Provider%
 Provider = %Provider%
 Class = Net
 Class = Net
-DriverVer=08/13/2015,6.2.9200.20557
+DriverVer=11/24/2020,3.00.00.1
 
 
 [Strings]
 [Strings]
-DeviceDescription = "ZeroTier One Virtual Port"
-Provider = "ZeroTier Networks LLC" ; We're ZeroTier, Inc. now but kernel mode certs are $300+ so fuqdat.
+DeviceDescription = "ZeroTier Virtual Port"
+Provider = "ZeroTier"
 
 
-; To build for x86, take NTamd64 off this and off the named section manually, build, then put it back!
 [Manufacturer]
 [Manufacturer]
+%Provider%=zttap300,NTx86
 %Provider%=zttap300,NTamd64
 %Provider%=zttap300,NTamd64
+%Provider%=zttap300,NTarm64
 
 
-[zttap300]
+[zttap300.NTx86]
 %DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated
 %DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated
 %DeviceDescription% = zttap300.ndi, zttap300      ; Legacy
 %DeviceDescription% = zttap300.ndi, zttap300      ; Legacy
 
 
@@ -48,6 +46,10 @@ Provider = "ZeroTier Networks LLC" ; We're ZeroTier, Inc. now but kernel mode ce
 %DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated
 %DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated
 %DeviceDescription% = zttap300.ndi, zttap300      ; Legacy
 %DeviceDescription% = zttap300.ndi, zttap300      ; Legacy
 
 
+[zttap300.NTarm64]
+%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated
+%DeviceDescription% = zttap300.ndi, zttap300      ; Legacy
+
 ;----------------- Characteristics ------------
 ;----------------- Characteristics ------------
 ;    NCF_PHYSICAL = 0x04
 ;    NCF_PHYSICAL = 0x04
 ;    NCF_VIRTUAL = 0x01
 ;    NCF_VIRTUAL = 0x01

BIN
ext/bin/tap-windows-ndis6/arm64/zttap300.sys


BIN
ext/bin/tap-windows-ndis6/certutil.exe


BIN
ext/bin/tap-windows-ndis6/x64.old/ZeroTierOne_NDIS6_x64.msi


BIN
ext/bin/tap-windows-ndis6/x64.old/zttap300.cat


BIN
ext/bin/tap-windows-ndis6/x64.old/zttap300.sys


BIN
ext/bin/tap-windows-ndis6/x64/ZeroTierOne_NDIS6_x64.msi


BIN
ext/bin/tap-windows-ndis6/x86.old/ZeroTierOne_NDIS6_x86.msi


BIN
ext/bin/tap-windows-ndis6/x86.old/zttap300.cat


+ 0 - 143
ext/bin/tap-windows-ndis6/x86.old/zttap300.inf

@@ -1,143 +0,0 @@
-;
-; ZeroTier One Virtual Network Port NDIS6 Driver
-;
-; Based on the OpenVPN tap-windows6 driver version 9.21.1 git
-; commit 48f027cfca52b16b5fd23d82e6016ed8a91fc4d3.
-; See: https://github.com/OpenVPN/tap-windows6
-;
-; Modified by ZeroTier, Inc. - https://www.zerotier.com/
-;
-; (1) Comment out 'tun' functionality and related features such as DHCP
-;     emulation, since we don't use any of that. Just want straight 'tap'.
-; (2) Added custom IOCTL to enumerate L2 multicast memberships.
-; (3) Increase maximum number of multicast memberships to 128.
-; (4) Set default and max device MTU to 2800.
-; (5) Rename/rebrand driver as ZeroTier network port driver.
-;
-; Original copyright below. Modifications released under GPLv2 as well.
-;
-; ****************************************************************************
-; * Copyright (C) 2002-2014 OpenVPN Technologies, Inc.                       *
-; *  This program is free software; you can redistribute it and/or modify    *
-; *  it under the terms of the GNU General Public License version 2          *
-; *  as published by the Free Software Foundation.                           *
-; ****************************************************************************
-;
-
-[Version]
-Signature = "$Windows NT$"
-CatalogFile = zttap300.cat
-ClassGUID = {4d36e972-e325-11ce-bfc1-08002be10318}
-Provider = %Provider%
-Class = Net
-DriverVer=08/13/2015,6.2.9200.20557
-
-[Strings]
-DeviceDescription = "ZeroTier One Virtual Port"
-Provider = "ZeroTier Networks LLC" ; We're ZeroTier, Inc. now but kernel mode certs are $300+ so fuqdat.
-
-; To build for x86, take NTamd64 off this and off the named section manually, build, then put it back!
-[Manufacturer]
-%Provider%=zttap300,NTamd64
-
-[zttap300]
-%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated
-%DeviceDescription% = zttap300.ndi, zttap300      ; Legacy
-
-[zttap300.NTamd64]
-%DeviceDescription% = zttap300.ndi, root\zttap300 ; Root enumerated
-%DeviceDescription% = zttap300.ndi, zttap300      ; Legacy
-
-;----------------- Characteristics ------------
-;    NCF_PHYSICAL = 0x04
-;    NCF_VIRTUAL = 0x01
-;    NCF_SOFTWARE_ENUMERATED = 0x02
-;    NCF_HIDDEN = 0x08
-;    NCF_NO_SERVICE = 0x10
-;    NCF_HAS_UI = 0x80
-;----------------- Characteristics ------------
-[zttap300.ndi]
-CopyFiles       = zttap300.driver, zttap300.files
-AddReg          = zttap300.reg
-AddReg          = zttap300.params.reg
-Characteristics = 0x81
-*IfType            = 0x6 ; IF_TYPE_ETHERNET_CSMACD
-*MediaType         = 0x0 ; NdisMedium802_3
-*PhysicalMediaType = 14  ; NdisPhysicalMedium802_3
-
-[zttap300.ndi.Services]
-AddService = zttap300,        2, zttap300.service
-
-[zttap300.reg]
-HKR, Ndi,            Service,      0, "zttap300"
-HKR, Ndi\Interfaces, UpperRange,   0, "ndis5" ; yes, 'ndis5' is correct... yup, Windows.
-HKR, Ndi\Interfaces, LowerRange,   0, "ethernet"
-HKR, ,               Manufacturer, 0, "%Provider%"
-HKR, ,               ProductName,  0, "%DeviceDescription%"
-
-[zttap300.params.reg]
-HKR, Ndi\params\MTU,                  ParamDesc, 0, "MTU"
-HKR, Ndi\params\MTU,                  Type,      0, "int"
-HKR, Ndi\params\MTU,                  Default,   0, "2800"
-HKR, Ndi\params\MTU,                  Optional,  0, "0"
-HKR, Ndi\params\MTU,                  Min,       0, "100"
-HKR, Ndi\params\MTU,                  Max,       0, "2800"
-HKR, Ndi\params\MTU,                  Step,      0, "1"
-HKR, Ndi\params\MediaStatus,          ParamDesc, 0, "Media Status"
-HKR, Ndi\params\MediaStatus,          Type,      0, "enum"
-HKR, Ndi\params\MediaStatus,          Default,   0, "0"
-HKR, Ndi\params\MediaStatus,          Optional,  0, "0"
-HKR, Ndi\params\MediaStatus\enum,     "0",       0, "Application Controlled"
-HKR, Ndi\params\MediaStatus\enum,     "1",       0, "Always Connected"
-HKR, Ndi\params\MAC,                  ParamDesc, 0, "MAC Address"
-HKR, Ndi\params\MAC,                  Type,      0, "edit"
-HKR, Ndi\params\MAC,                  Optional,  0, "1"
-HKR, Ndi\params\AllowNonAdmin,        ParamDesc, 0, "Non-Admin Access"
-HKR, Ndi\params\AllowNonAdmin,        Type,      0, "enum"
-HKR, Ndi\params\AllowNonAdmin,        Default,   0, "0"
-HKR, Ndi\params\AllowNonAdmin,        Optional,  0, "0"
-HKR, Ndi\params\AllowNonAdmin\enum,   "0",       0, "Not Allowed"
-HKR, Ndi\params\AllowNonAdmin\enum,   "1",       0, "Allowed"
-
-;---------- Service Type -------------
-;    SERVICE_KERNEL_DRIVER     = 0x01
-;    SERVICE_WIN32_OWN_PROCESS = 0x10
-;---------- Service Type -------------
-
-;---------- Start Mode ---------------
-;    SERVICE_BOOT_START   = 0x0
-;    SERVICE_SYSTEM_START = 0x1
-;    SERVICE_AUTO_START   = 0x2
-;    SERVICE_DEMAND_START = 0x3
-;    SERVICE_DISABLED     = 0x4
-;---------- Start Mode ---------------
-
-[zttap300.service]
-DisplayName = %DeviceDescription%
-ServiceType = 1
-StartType = 3
-ErrorControl = 1
-LoadOrderGroup = NDIS
-ServiceBinary = %12%\zttap300.sys
-
-;----------------- Copy Flags ------------
-;    COPYFLG_NOSKIP = 0x02
-;    COPYFLG_NOVERSIONCHECK = 0x04
-;----------------- Copy Flags ------------
-
-[SourceDisksNames]
-1 = %DeviceDescription%, zttap300.sys
-
-[SourceDisksFiles]
-zttap300.sys = 1
-
-[DestinationDirs]
-zttap300.files  = 11
-zttap300.driver = 12
-
-[zttap300.files]
-;
-
-[zttap300.driver]
-zttap300.sys,,,6     ; COPYFLG_NOSKIP | COPYFLG_NOVERSIONCHECK
-

BIN
ext/bin/tap-windows-ndis6/x86.old/zttap300.sys


BIN
ext/bin/tap-windows-ndis6/x86/ZeroTierOne_NDIS6_x86.msi


BIN
ext/bin/tap-windows-ndis6/zttap300.cer


+ 2 - 2
ext/central-controller-docker/Dockerfile

@@ -1,10 +1,10 @@
 # Dockerfile for ZeroTier Central Controllers
 # Dockerfile for ZeroTier Central Controllers
-FROM registry.zerotier.com/zerotier/controller-builder:latest as builder
+FROM registry.zerotier.com/zerotier/ctlbuild:latest as builder
 MAINTAINER Adam Ierymekno <[email protected]>, Grant Limberg <[email protected]>
 MAINTAINER Adam Ierymekno <[email protected]>, Grant Limberg <[email protected]>
 ADD . /ZeroTierOne
 ADD . /ZeroTierOne
 RUN export PATH=$PATH:~/.cargo/bin && cd ZeroTierOne && make clean && make central-controller -j8
 RUN export PATH=$PATH:~/.cargo/bin && cd ZeroTierOne && make clean && make central-controller -j8
 
 
-FROM registry.zerotier.com/zerotier/controller-run:latest
+FROM registry.zerotier.com/zerotier/ctlrun:latest
 COPY --from=builder /ZeroTierOne/zerotier-one /usr/local/bin/zerotier-one
 COPY --from=builder /ZeroTierOne/zerotier-one /usr/local/bin/zerotier-one
 RUN chmod a+x /usr/local/bin/zerotier-one
 RUN chmod a+x /usr/local/bin/zerotier-one
 RUN echo "/usr/local/lib64" > /etc/ld.so.conf.d/usr-local-lib64.conf && ldconfig
 RUN echo "/usr/local/lib64" > /etc/ld.so.conf.d/usr-local-lib64.conf && ldconfig

+ 16 - 0
ext/central-controller-docker/Makefile

@@ -0,0 +1,16 @@
+registry = registry.zerotier.com/zerotier
+
+all:	controller-builder controller-runbase
+
+buildx:
+	@echo "docker buildx create"
+	# docker run --rm --privileged multiarch/qemu-user-static --reset -p yes
+	docker run --privileged --rm tonistiigi/binfmt --install all
+	@echo docker buildx create --name multiarch --driver docker-container --use
+	@echo docker buildx inspect --bootstrap
+
+controller-builder:	buildx
+	docker buildx build --no-cache --platform linux/amd64,linux/arm64 -t $(registry)/ctlbuild:latest -f Dockerfile.builder . --push
+
+controller-runbase: buildx
+	docker buildx build --no-cache --platform linux/amd64,linux/arm64 -t $(registry)/ctlrun:latest -f Dockerfile.run_base . --push

+ 6 - 0
ext/central-controller-docker/main.sh

@@ -58,9 +58,13 @@ mkdir -p /var/lib/zerotier-one
 pushd /var/lib/zerotier-one
 pushd /var/lib/zerotier-one
 ln -s $ZT_IDENTITY_PATH/identity.public identity.public
 ln -s $ZT_IDENTITY_PATH/identity.public identity.public
 ln -s $ZT_IDENTITY_PATH/identity.secret identity.secret
 ln -s $ZT_IDENTITY_PATH/identity.secret identity.secret
+if [ -f  "$ZT_IDENTITY_PATH/authtoken.secret" ]; then
+    ln -s $ZT_IDENTITY_PATH/authtoken.secret authtoken.secret
+fi
 popd
 popd
 
 
 DEFAULT_PORT=9993
 DEFAULT_PORT=9993
+DEFAULT_LB_MODE=false
 
 
 APP_NAME="controller-$(cat /var/lib/zerotier-one/identity.public | cut -d ':' -f 1)"
 APP_NAME="controller-$(cat /var/lib/zerotier-one/identity.public | cut -d ':' -f 1)"
 
 
@@ -73,7 +77,9 @@ echo "{
             \"inot\",
             \"inot\",
             \"nat64\"
             \"nat64\"
         ],
         ],
+        \"lowBandwidthMode\": ${ZT_LB_MODE:-$DEFAULT_LB_MODE},
         \"ssoRedirectURL\": \"${ZT_SSO_REDIRECT_URL}\",
         \"ssoRedirectURL\": \"${ZT_SSO_REDIRECT_URL}\",
+        \"allowManagementFrom\": [\"127.0.0.1\", \"::1\", \"10.0.0.0/8\"],
         ${REDIS}
         ${REDIS}
     }
     }
 }    
 }    

Разница между файлами не показана из-за своего большого размера
+ 486 - 206
ext/cpp-httplib/httplib.h


+ 0 - 0
ext/hiredis-1.0.2/lib/ubuntu22.04/libhiredis.a → ext/hiredis-1.0.2/lib/ubuntu22.04/amd64/libhiredis.a


BIN
ext/hiredis-1.0.2/lib/ubuntu22.04/arm64/libhiredis.a


+ 1 - 1
ext/installfiles/mac/ZeroTier One.pkgproj

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

+ 59 - 89
ext/installfiles/windows/ZeroTier One.aip

@@ -1,25 +1,20 @@
 <?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="20.4.1" Modules="enterprise" RootPath="." Language="en" Id="{DC564647-6BF0-4550-87F4-89C938D0159C}">
+<DOCUMENT Type="Advanced Installer" CreateVersion="10.9" version="20.9.1" Modules="enterprise" RootPath="." Language="en" Id="{DC564647-6BF0-4550-87F4-89C938D0159C}">
   <COMPONENT cid="caphyon.advinst.msicomp.ProjectOptionsComponent">
   <COMPONENT cid="caphyon.advinst.msicomp.ProjectOptionsComponent">
     <ROW Name="HiddenItems" Value="ActSyncAppComponent;CPLAppletComponent;AutorunComponent;GameUxComponent;SilverlightSlnComponent;SharePointSlnComponent;AppXAppDetailsComponent;FixupComponent;AppXCapabilitiesComponent;AppXDependenciesComponent;AppXProductDetailsComponent;AppXVisualAssetsComponent;AppXAppDeclarationsComponent;AppXUriRulesComponent;MsiXDiffComponent;MsixManifestEditorComponent"/>
     <ROW Name="HiddenItems" Value="ActSyncAppComponent;CPLAppletComponent;AutorunComponent;GameUxComponent;SilverlightSlnComponent;SharePointSlnComponent;AppXAppDetailsComponent;FixupComponent;AppXCapabilitiesComponent;AppXDependenciesComponent;AppXProductDetailsComponent;AppXVisualAssetsComponent;AppXAppDeclarationsComponent;AppXUriRulesComponent;MsiXDiffComponent;MsixManifestEditorComponent"/>
   </COMPONENT>
   </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_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_PREDEF_LCONDS_PROPS" Value="AI_DETECTED_DOTNET_VERSION"/>
     <ROW Property="AI_PREREQ_REPAIR_ENABLED" MultiBuildValue="ExeBuild:1"/>
     <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_VERSION" MultiBuildValue="DefaultBuild:4.5" ValueLocId="-"/>
     <ROW Property="AI_ThemeStyle" Value="aero" MsiKey="AI_ThemeStyle"/>
     <ROW Property="AI_ThemeStyle" Value="aero" MsiKey="AI_ThemeStyle"/>
     <ROW Property="AI_UNINSTALLER" Value="msiexec.exe"/>
     <ROW Property="AI_UNINSTALLER" Value="msiexec.exe"/>
     <ROW Property="ALLUSERS" Value="1"/>
     <ROW Property="ALLUSERS" Value="1"/>
     <ROW Property="ARPCOMMENTS" Value="This installer database contains the logic and data required to install [|ProductName]."/>
     <ROW Property="ARPCOMMENTS" Value="This installer database contains the logic and data required to install [|ProductName]."/>
     <ROW Property="ARPCONTACT" Value="[email protected]"/>
     <ROW Property="ARPCONTACT" Value="[email protected]"/>
     <ROW Property="ARPHELPLINK" Value="https://www.zerotier.com/"/>
     <ROW Property="ARPHELPLINK" Value="https://www.zerotier.com/"/>
-    <ROW Property="ARPHELPTELEPHONE" Value="949-505-9993"/>
     <ROW Property="ARPNOMODIFY" MultiBuildValue="DefaultBuild:1"/>
     <ROW Property="ARPNOMODIFY" MultiBuildValue="DefaultBuild:1"/>
     <ROW Property="ARPNOREPAIR" Value="1" MultiBuildValue="ExeBuild:1"/>
     <ROW Property="ARPNOREPAIR" Value="1" MultiBuildValue="ExeBuild:1"/>
     <ROW Property="ARPPRODUCTICON" Value="ZeroTierIcon.exe" Type="8"/>
     <ROW Property="ARPPRODUCTICON" Value="ZeroTierIcon.exe" Type="8"/>
@@ -27,28 +22,27 @@
     <ROW Property="ARPURLINFOABOUT" Value="https://www.zerotier.com/"/>
     <ROW Property="ARPURLINFOABOUT" Value="https://www.zerotier.com/"/>
     <ROW Property="ARPURLUPDATEINFO" Value="https://www.zerotier.com/"/>
     <ROW Property="ARPURLUPDATEINFO" Value="https://www.zerotier.com/"/>
     <ROW Property="AiFeatIcoZeroTierOne" Value="ZeroTierIcon.exe" Type="8"/>
     <ROW Property="AiFeatIcoZeroTierOne" Value="ZeroTierIcon.exe" Type="8"/>
-    <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:{8D8ECA43-43FF-4358-84E9-4629D8855C03} " Type="16"/>
+    <ROW Property="ProductCode" Value="1033:{B07D0036-6C23-4CFD-9F2A-F2C990225591} " 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.10.6"/>
+    <ROW Property="ProductVersion" Value="1.12.0" Options="32"/>
     <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}"/>
     <ROW Property="WindowsType9X" MultiBuildValue="DefaultBuild:Windows 9x/ME#ExeBuild:Windows 9x/ME" ValueLocId="-"/>
     <ROW Property="WindowsType9X" MultiBuildValue="DefaultBuild:Windows 9x/ME#ExeBuild:Windows 9x/ME" ValueLocId="-"/>
     <ROW Property="WindowsType9XDisplay" MultiBuildValue="DefaultBuild:Windows 9x/ME#ExeBuild:Windows 9x/ME" ValueLocId="-"/>
     <ROW Property="WindowsType9XDisplay" MultiBuildValue="DefaultBuild:Windows 9x/ME#ExeBuild:Windows 9x/ME" ValueLocId="-"/>
-    <ROW Property="WindowsTypeNT" MultiBuildValue="DefaultBuild:Windows Vista x86, Windows Server 2008 x86, Windows 7 x86" ValueLocId="-"/>
+    <ROW Property="WindowsTypeNT" MultiBuildValue="DefaultBuild:Windows Vista x86, Windows Server 2008 x86, Windows 7 x86, Windows 8 x86, Windows 8.1 x86" ValueLocId="-"/>
     <ROW Property="WindowsTypeNT40" MultiBuildValue="DefaultBuild:Windows NT 4.0#ExeBuild:Windows NT 4.0" ValueLocId="-"/>
     <ROW Property="WindowsTypeNT40" MultiBuildValue="DefaultBuild:Windows NT 4.0#ExeBuild:Windows NT 4.0" ValueLocId="-"/>
     <ROW Property="WindowsTypeNT40Display" MultiBuildValue="DefaultBuild:Windows NT 4.0#ExeBuild:Windows NT 4.0" ValueLocId="-"/>
     <ROW Property="WindowsTypeNT40Display" MultiBuildValue="DefaultBuild:Windows NT 4.0#ExeBuild:Windows NT 4.0" ValueLocId="-"/>
     <ROW Property="WindowsTypeNT50" MultiBuildValue="DefaultBuild:Windows 2000#ExeBuild:Windows 2000" ValueLocId="-"/>
     <ROW Property="WindowsTypeNT50" MultiBuildValue="DefaultBuild:Windows 2000#ExeBuild:Windows 2000" ValueLocId="-"/>
     <ROW Property="WindowsTypeNT50Display" MultiBuildValue="DefaultBuild:Windows 2000#ExeBuild:Windows 2000" ValueLocId="-"/>
     <ROW Property="WindowsTypeNT50Display" MultiBuildValue="DefaultBuild:Windows 2000#ExeBuild:Windows 2000" ValueLocId="-"/>
     <ROW Property="WindowsTypeNT5X" MultiBuildValue="DefaultBuild:Windows XP/2003#ExeBuild:Windows XP/2003" ValueLocId="-"/>
     <ROW Property="WindowsTypeNT5X" MultiBuildValue="DefaultBuild:Windows XP/2003#ExeBuild:Windows XP/2003" ValueLocId="-"/>
     <ROW Property="WindowsTypeNT5XDisplay" MultiBuildValue="DefaultBuild:Windows XP/2003#ExeBuild:Windows XP/2003" ValueLocId="-"/>
     <ROW Property="WindowsTypeNT5XDisplay" MultiBuildValue="DefaultBuild:Windows XP/2003#ExeBuild:Windows XP/2003" ValueLocId="-"/>
-    <ROW Property="WindowsTypeNT64" MultiBuildValue="DefaultBuild:Windows Vista x64, Windows Server 2008 x64, Windows 7 x64, Windows Server 2008 R2 x64" ValueLocId="-"/>
-    <ROW Property="WindowsTypeNT64Display" MultiBuildValue="DefaultBuild:Windows Vista x64, Windows Server 2008 x64, Windows 7 x64, Windows Server 2008 R2 x64" ValueLocId="-"/>
-    <ROW Property="WindowsTypeNTDisplay" MultiBuildValue="DefaultBuild:Windows Vista x86, Windows Server 2008 x86, Windows 7 x86" ValueLocId="-"/>
+    <ROW Property="WindowsTypeNT64" MultiBuildValue="DefaultBuild:Windows Vista x64, Windows Server 2008 x64, Windows 7 x64, Windows Server 2008 R2 x64, Windows 8 x64, Windows Server 2012 x64, Windows 8.1 x64, Windows Server 2012 R2 x64" ValueLocId="-"/>
+    <ROW Property="WindowsTypeNT64Display" MultiBuildValue="DefaultBuild:Windows Vista x64, Windows Server 2008 x64, Windows 7 x64, Windows Server 2008 R2 x64, Windows 8 x64, Windows Server 2012 x64, Windows 8.1 x64, Windows Server 2012 R2 x64" ValueLocId="-"/>
+    <ROW Property="WindowsTypeNTDisplay" MultiBuildValue="DefaultBuild:Windows Vista x86, Windows Server 2008 x86, Windows 7 x86, Windows 8 x86, Windows 8.1 x86" ValueLocId="-"/>
     <ROW Property="ZTHEADLESS" Value="No"/>
     <ROW Property="ZTHEADLESS" Value="No"/>
   </COMPONENT>
   </COMPONENT>
   <COMPONENT cid="caphyon.advinst.msicomp.MsiDirsComponent">
   <COMPONENT cid="caphyon.advinst.msicomp.MsiDirsComponent">
@@ -59,52 +53,58 @@
     <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" DirectoryOptions="12"/>
     <ROW Directory="ZeroTier_Dir" Directory_Parent="CommonAppDataFolder" DefaultDir="ZeroTier" DirectoryOptions="12"/>
+    <ROW Directory="driverarm64_Dir" Directory_Parent="One_Dir" DefaultDir=".:DRIVER~1|driver-arm64" DirectoryOptions="12"/>
+    <ROW Directory="driverx64_Dir" Directory_Parent="One_Dir" DefaultDir=".:DRIVER~2|driver-x64" DirectoryOptions="15"/>
+    <ROW Directory="driverx86_Dir" Directory_Parent="One_Dir" DefaultDir=".:DRIVER~3|driver-x86" DirectoryOptions="15"/>
     <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="15"/>
     <ROW Directory="i686_Dir" Directory_Parent="APPDIR" DefaultDir=".:i686" DirectoryOptions="15"/>
     <ROW Directory="networks.d_Dir" Directory_Parent="One_Dir" DefaultDir="networks.d" DirectoryOptions="12"/>
     <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" DirectoryOptions="12"/>
     <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" DirectoryOptions="12"/>
-    <ROW Directory="x64_Dir" Directory_Parent="tapwindows_Dir" DefaultDir="x64" DirectoryOptions="12"/>
-    <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="AI_CustomARPName" ComponentId="{D8521222-B184-44D4-84AE-8B6549555BD8}" Directory_="APPDIR" Attributes="4" KeyPath="DisplayName" Options="1"/>
+    <ROW Component="AI_CustomARPName" ComponentId="{0C83327B-255D-4E69-A702-EC9414459A68}" 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="One" ComponentId="{41AB11E7-066E-414A-96F8-F051D3D3B353}" Directory_="One_Dir" Attributes="0"/>
     <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="ZeroTier" ComponentId="{8864F744-9BDF-4891-88A1-6D23D76BCCB1}" Directory_="ZeroTier_Dir" Attributes="0"/>
     <ROW Component="ZeroTier" ComponentId="{8864F744-9BDF-4891-88A1-6D23D76BCCB1}" Directory_="ZeroTier_Dir" Attributes="0"/>
+    <ROW Component="driverarm64" ComponentId="{EF9A1336-B00D-409A-BD93-EBA3A266F06D}" Directory_="driverarm64_Dir" Attributes="0" Condition="(VersionNT &gt;= 500) AND AiArm64"/>
+    <ROW Component="driverx64" ComponentId="{29698845-0BA3-46C9-957C-E034B5BE5123}" Directory_="driverx64_Dir" Attributes="0" Condition="VersionNT64 AND NOT AiArm64"/>
+    <ROW Component="driverx86" ComponentId="{60D9AE83-35CD-4E0C-B799-A228D0288D04}" Directory_="driverx86_Dir" Attributes="0" Condition="(VersionNT &gt;= 500) AND NOT VersionNT64 AND NOT AiArm64"/>
     <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="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 AND NOT AiArm64" 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"/>
-    <ROW Component="zerotierone_x86.exe" ComponentId="{5D2F3366-4FE1-40A4-A81A-66C49FA11F1C}" Directory_="One_Dir" Attributes="0" Condition="NOT VersionNT64" KeyPath="zerotierone_x86.exe"/>
-    <ROW Component="zttap300_x64_win10" ComponentId="{D4839F5E-FB94-41CB-9B1B-177A97ADC904}" Directory_="x64_Dir" Attributes="256" Condition="VersionNT64" KeyPath="zttap300.inf"/>
-    <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="zerotierone_x86.exe" ComponentId="{5D2F3366-4FE1-40A4-A81A-66C49FA11F1C}" Directory_="One_Dir" Attributes="0" Condition="NOT VersionNT64 AND NOT AiArm64" KeyPath="zerotierone_x86.exe"/>
+    <ROW Component="zttap300.inf" ComponentId="{2591DB80-835D-445D-86FB-DF0717D2D904}" Directory_="driverx64_Dir" Attributes="256" Condition="VersionNT64 AND NOT AiArm64" KeyPath="zttap300.inf"/>
+    <ROW Component="zttap300.inf_1" ComponentId="{DE7DABB5-7393-4FCD-B2D6-4DD6CAC0E742}" Directory_="driverx86_Dir" Attributes="0" Condition="(VersionNT &gt;= 500) AND NOT VersionNT64 AND NOT AiArm64" KeyPath="zttap300.inf_1"/>
+    <ROW Component="zttap300.inf_2" ComponentId="{8CD16F5C-D1A7-4991-9B77-C0D1ABEA21F6}" Directory_="driverarm64_Dir" Attributes="256" Condition="(VersionNT &gt;= 500) AND AiArm64" KeyPath="zttap300.inf_2"/>
   </COMPONENT>
   </COMPONENT>
   <COMPONENT cid="caphyon.advinst.msicomp.MsiFeatsComponent">
   <COMPONENT cid="caphyon.advinst.msicomp.MsiFeatsComponent">
-    <ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" Level="1" Directory_="APPDIR" 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"/>
+    <ROW Feature="zttap300" Feature_Parent="ZeroTierOne" Title="zttap300" Description="Description" Display="7" Level="1" Directory_="APPDIR" Attributes="0"/>
+    <ROW Feature="zttap300_1" Feature_Parent="ZeroTierOne" Title="zttap300" Description="Description" Display="3" Level="1" Directory_="APPDIR" Attributes="0"/>
+    <ROW Feature="zttap300_2" Feature_Parent="ZeroTierOne" Title="zttap300" Description="Description" Display="5" Level="1" Directory_="APPDIR" Attributes="0"/>
     <ATTRIBUTE name="CurrentFeature" value="ZeroTierOne"/>
     <ATTRIBUTE name="CurrentFeature" value="ZeroTierOne"/>
   </COMPONENT>
   </COMPONENT>
   <COMPONENT cid="caphyon.advinst.msicomp.MsiFilesComponent">
   <COMPONENT cid="caphyon.advinst.msicomp.MsiFilesComponent">
     <ROW File="zerotierone_x86.exe" Component_="zerotierone_x86.exe" FileName="ZEROTI~1.EXE|zerotier-one_x86.exe" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\windows\Build\Win32\Release\zerotier-one_x86.exe" SelfReg="false" DigSign="true"/>
     <ROW File="zerotierone_x86.exe" Component_="zerotierone_x86.exe" FileName="ZEROTI~1.EXE|zerotier-one_x86.exe" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\windows\Build\Win32\Release\zerotier-one_x86.exe" SelfReg="false" DigSign="true"/>
     <ROW File="zerotierone_x64.exe" Component_="zerotierone_x64.exe" FileName="ZEROTI~2.EXE|zerotier-one_x64.exe" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\windows\Build\x64\Release\zerotier-one_x64.exe" SelfReg="false" DigSign="true"/>
     <ROW File="zerotierone_x64.exe" Component_="zerotierone_x64.exe" FileName="ZEROTI~2.EXE|zerotier-one_x64.exe" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\windows\Build\x64\Release\zerotier-one_x64.exe" SelfReg="false" DigSign="true"/>
-    <ROW File="zttap300.cat_2" Component_="zttap300_x64_win10" FileName="zttap300.cat" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x64\zttap300.cat" SelfReg="false"/>
-    <ROW File="zttap300.sys_2" Component_="zttap300_x64_win10" FileName="zttap300.sys" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x64\zttap300.sys" SelfReg="false"/>
-    <ROW File="zttap300.inf" Component_="zttap300_x64_win10" FileName="zttap300.inf" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x64\zttap300.inf" SelfReg="false"/>
-    <ROW File="zttap300.cat_3" Component_="zttap300_x86_win10" FileName="zttap300.cat" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x86\zttap300.cat" SelfReg="false"/>
-    <ROW File="zttap300.sys_3" Component_="zttap300_x86_win10" FileName="zttap300.sys" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x86\zttap300.sys" SelfReg="false"/>
-    <ROW File="zttap300.inf_1" Component_="zttap300_x86_win10" FileName="zttap300.inf" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x86\zttap300.inf" SelfReg="false"/>
     <ROW File="zerotier_desktop_ui.exe" Component_="zerotier_desktop_ui.exe" FileName="ZEROTI~2.EXE|zerotier_desktop_ui.exe" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\..\DesktopUI\target\x86_64-pc-windows-msvc\release\zerotier_desktop_ui.exe" SelfReg="false" DigSign="true"/>
     <ROW File="zerotier_desktop_ui.exe" Component_="zerotier_desktop_ui.exe" FileName="ZEROTI~2.EXE|zerotier_desktop_ui.exe" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\..\DesktopUI\target\x86_64-pc-windows-msvc\release\zerotier_desktop_ui.exe" SelfReg="false" DigSign="true"/>
     <ROW File="zerotier_desktop_ui.exe_1" Component_="zerotier_desktop_ui.exe_1" FileName="ZEROTI~1.EXE|zerotier_desktop_ui.exe" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\..\DesktopUI\target\i686-pc-windows-msvc\release\zerotier_desktop_ui.exe" SelfReg="false" DigSign="true"/>
     <ROW File="zerotier_desktop_ui.exe_1" Component_="zerotier_desktop_ui.exe_1" FileName="ZEROTI~1.EXE|zerotier_desktop_ui.exe" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\..\DesktopUI\target\i686-pc-windows-msvc\release\zerotier_desktop_ui.exe" SelfReg="false" DigSign="true"/>
+    <ROW File="zttap300.inf" Component_="zttap300.inf" FileName="zttap300.inf" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x64\zttap300.inf" SelfReg="false"/>
+    <ROW File="zttap300.sys" Component_="zttap300.inf" FileName="zttap300.sys" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x64\zttap300.sys" SelfReg="false"/>
+    <ROW File="zttap300.cat" Component_="zttap300.inf" FileName="zttap300.cat" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x64\zttap300.cat" SelfReg="false"/>
+    <ROW File="zttap300.cat_1" Component_="zttap300.inf_1" FileName="zttap300.cat" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x86\zttap300.cat" SelfReg="false"/>
+    <ROW File="zttap300.inf_1" Component_="zttap300.inf_1" FileName="zttap300.inf" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x86\zttap300.inf" SelfReg="false"/>
+    <ROW File="zttap300.sys_1" Component_="zttap300.inf_1" FileName="zttap300.sys" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x86\zttap300.sys" SelfReg="false"/>
+    <ROW File="zttap300.cat_2" Component_="zttap300.inf_2" FileName="zttap300.cat" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\arm64\zttap300.cat" SelfReg="false"/>
+    <ROW File="zttap300.inf_2" Component_="zttap300.inf_2" FileName="zttap300.inf" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\arm64\zttap300.inf" SelfReg="false"/>
+    <ROW File="zttap300.sys_2" Component_="zttap300.inf_2" FileName="zttap300.sys" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\arm64\zttap300.sys" SelfReg="false"/>
   </COMPONENT>
   </COMPONENT>
   <COMPONENT cid="caphyon.advinst.custcomp.AiComponentAliasComponent">
   <COMPONENT cid="caphyon.advinst.custcomp.AiComponentAliasComponent">
     <ROW AliasRowId="AI_CustomARPName" AliasRowOperation="2" Condition="#DefaultBuild:ZTHEADLESS=&quot;No&quot;"/>
     <ROW AliasRowId="AI_CustomARPName" AliasRowOperation="2" Condition="#DefaultBuild:ZTHEADLESS=&quot;No&quot;"/>
@@ -112,9 +112,6 @@
   <COMPONENT cid="caphyon.advinst.msicomp.BootstrOptComponent">
   <COMPONENT cid="caphyon.advinst.msicomp.BootstrOptComponent">
     <ROW BootstrOptKey="GlobalOptions" GeneralOptions="qh" DownloadFolder="[AppDataFolder][|Manufacturer]\[|ProductName]\prerequisites"/>
     <ROW BootstrOptKey="GlobalOptions" GeneralOptions="qh" DownloadFolder="[AppDataFolder][|Manufacturer]\[|ProductName]\prerequisites"/>
   </COMPONENT>
   </COMPONENT>
-  <COMPONENT cid="caphyon.advinst.msicomp.BootstrapperUISequenceComponent">
-    <ROW Action="AI_DetectSoftware" Sequence="101"/>
-  </COMPONENT>
   <COMPONENT cid="caphyon.advinst.msicomp.BuildComponent">
   <COMPONENT cid="caphyon.advinst.msicomp.BuildComponent">
     <ROW BuildKey="DefaultBuild" BuildName="MSI" BuildOrder="1" BuildType="0" PackageFolder="..\..\.." PackageFileName="ZeroTier One" Languages="en" InstallationType="4" ExtUI="true" UseLargeSchema="true"/>
     <ROW BuildKey="DefaultBuild" BuildName="MSI" BuildOrder="1" BuildType="0" PackageFolder="..\..\.." PackageFileName="ZeroTier One" Languages="en" InstallationType="4" ExtUI="true" UseLargeSchema="true"/>
     <ROW BuildKey="ExeBuild" BuildName="update" BuildOrder="2" BuildType="0" PackageFolder="..\..\.." PackageFileName="ZeroTier One" Languages="en" InstallationType="2" CabsLocation="1" CompressCabs="false" UseLzma="true" LzmaMethod="2" LzmaCompressionLevel="4" PackageType="1" FilesInsideExe="true" ExeIconPath="..\..\..\artwork\ZeroTierIcon.ico" ExtractionFolder="[AppDataFolder][|Manufacturer]\[|ProductName] [|ProductVersion]\install" MsiCmdLine="/qn" ExtUI="true" UseLargeSchema="true" ExeName="zt1_update_2_1,2_[|ProductVersion]_0"/>
     <ROW BuildKey="ExeBuild" BuildName="update" BuildOrder="2" BuildType="0" PackageFolder="..\..\.." PackageFileName="ZeroTier One" Languages="en" InstallationType="2" CabsLocation="1" CompressCabs="false" UseLzma="true" LzmaMethod="2" LzmaCompressionLevel="4" PackageType="1" FilesInsideExe="true" ExeIconPath="..\..\..\artwork\ZeroTierIcon.ico" ExtractionFolder="[AppDataFolder][|Manufacturer]\[|ProductName] [|ProductVersion]\install" MsiCmdLine="/qn" ExtUI="true" UseLargeSchema="true" ExeName="zt1_update_2_1,2_[|ProductVersion]_0"/>
@@ -122,14 +119,6 @@
   <COMPONENT cid="caphyon.advinst.msicomp.CacheComponent">
   <COMPONENT cid="caphyon.advinst.msicomp.CacheComponent">
     <ATTRIBUTE name="Enable" value="false"/>
     <ATTRIBUTE name="Enable" value="false"/>
   </COMPONENT>
   </COMPONENT>
-  <COMPONENT cid="caphyon.advinst.msicomp.ChainedPackageComponent">
-    <ROW ChainedPackage="ZeroTierOne_NDIS6_x64.msi" Order="1" Options="110" InstallCondition="VersionNT64 AND VersionNT &gt;= 1000" MaintenanceCondition="FALSE" RemoveCondition="REMOVE=&quot;ALL&quot; AND VersionNT64"/>
-    <ROW ChainedPackage="ZeroTierOne_NDIS6_x86.msi" Order="2" Options="110" InstallCondition="(NOT VersionNT64) And VersionNT &gt;= 1000" MaintenanceCondition="FALSE" RemoveCondition="REMOVE=&quot;ALL&quot; AND (NOT VersionNT64)"/>
-  </COMPONENT>
-  <COMPONENT cid="caphyon.advinst.msicomp.ChainedPackageFileComponent">
-    <ROW FileId="ZeroTierOne_NDIS6_x64.msi" ChainedPackage="ZeroTierOne_NDIS6_x64.msi" Options="1" TargetPath="ZeroTierOne_NDIS6_x64.msi" Content="..\..\bin\tap-windows-ndis6\x64\ZeroTierOne_NDIS6_x64.msi"/>
-    <ROW FileId="ZeroTierOne_NDIS6_x86.msi" ChainedPackage="ZeroTierOne_NDIS6_x86.msi" Options="1" TargetPath="ZeroTierOne_NDIS6_x86.msi" Content="..\..\bin\tap-windows-ndis6\x86\ZeroTierOne_NDIS6_x86.msi"/>
-  </COMPONENT>
   <COMPONENT cid="caphyon.advinst.msicomp.DictionaryComponent">
   <COMPONENT cid="caphyon.advinst.msicomp.DictionaryComponent">
     <ROW Path="&lt;AI_DICTS&gt;ui.ail"/>
     <ROW Path="&lt;AI_DICTS&gt;ui.ail"/>
     <ROW Path="&lt;AI_DICTS&gt;ui_en.ail"/>
     <ROW Path="&lt;AI_DICTS&gt;ui_en.ail"/>
@@ -186,15 +175,17 @@
     <ROW Name="ExternalUICleaner.dll" SourcePath="&lt;AI_CUSTACTS&gt;ExternalUICleaner.dll"/>
     <ROW Name="ExternalUICleaner.dll" SourcePath="&lt;AI_CUSTACTS&gt;ExternalUICleaner.dll"/>
     <ROW Name="NetFirewall.dll" SourcePath="&lt;AI_CUSTACTS&gt;NetFirewall.dll"/>
     <ROW Name="NetFirewall.dll" SourcePath="&lt;AI_CUSTACTS&gt;NetFirewall.dll"/>
     <ROW Name="Prereq.dll" SourcePath="&lt;AI_CUSTACTS&gt;Prereq.dll"/>
     <ROW Name="Prereq.dll" SourcePath="&lt;AI_CUSTACTS&gt;Prereq.dll"/>
-    <ROW Name="SoftwareDetector.dll" SourcePath="&lt;AI_CUSTACTS&gt;SoftwareDetector.dll"/>
     <ROW Name="TxtUpdater.dll" SourcePath="&lt;AI_CUSTACTS&gt;TxtUpdater.dll"/>
     <ROW Name="TxtUpdater.dll" SourcePath="&lt;AI_CUSTACTS&gt;TxtUpdater.dll"/>
     <ROW Name="aicustact.dll" SourcePath="&lt;AI_CUSTACTS&gt;aicustact.dll"/>
     <ROW Name="aicustact.dll" SourcePath="&lt;AI_CUSTACTS&gt;aicustact.dll"/>
-    <ROW Name="chainersupport.dll" SourcePath="&lt;AI_CUSTACTS&gt;chainersupport.dll"/>
     <ROW Name="lzmaextractor.dll" SourcePath="&lt;AI_CUSTACTS&gt;lzmaextractor.dll"/>
     <ROW Name="lzmaextractor.dll" SourcePath="&lt;AI_CUSTACTS&gt;lzmaextractor.dll"/>
-    <ROW Name="msichainer.exe" SourcePath="&lt;AI_CUSTACTS&gt;msichainer.exe"/>
     <ROW Name="viewer.exe" SourcePath="&lt;AI_CUSTACTS&gt;viewer.exe" DigSign="true"/>
     <ROW Name="viewer.exe" SourcePath="&lt;AI_CUSTACTS&gt;viewer.exe" DigSign="true"/>
     <ROW Name="xmlCfg.dll" SourcePath="&lt;AI_CUSTACTS&gt;xmlCfg.dll"/>
     <ROW Name="xmlCfg.dll" SourcePath="&lt;AI_CUSTACTS&gt;xmlCfg.dll"/>
   </COMPONENT>
   </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiConditionComponent">
+    <ROW Feature_="zttap300" Level="0" Condition="((VersionNT &lt; 500) OR (NOT VersionNT))"/>
+    <ROW Feature_="zttap300_1" Level="0" Condition="((VersionNT &lt; 500) OR (NOT VersionNT))"/>
+    <ROW Feature_="zttap300_2" Level="0" Condition="((VersionNT &lt; 500) OR (NOT VersionNT))"/>
+  </COMPONENT>
   <COMPONENT cid="caphyon.advinst.msicomp.MsiControlComponent">
   <COMPONENT cid="caphyon.advinst.msicomp.MsiControlComponent">
     <ROW Dialog_="ExitDialog" Control="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Attributes="0" Text="[ButtonText_Cancel]" Order="200" TextLocId="-" MsiKey="ExitDialog#Cancel" Options="1"/>
     <ROW Dialog_="ExitDialog" Control="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Attributes="0" Text="[ButtonText_Cancel]" Order="200" TextLocId="-" MsiKey="ExitDialog#Cancel" Options="1"/>
     <ROW Dialog_="ExitDialog" Control="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Attributes="0" Text="[ButtonText_Back]" Order="400" TextLocId="-" MsiKey="ExitDialog#Back" Options="1"/>
     <ROW Dialog_="ExitDialog" Control="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Attributes="0" Text="[ButtonText_Back]" Order="400" TextLocId="-" MsiKey="ExitDialog#Back" Options="1"/>
@@ -203,6 +194,7 @@
     <ROW Dialog_="ExitDialog" Control="LaunchProdCheckBox" Type="CheckBox" X="135" Y="170" Width="10" Height="10" Attributes="2" Property="RUNAPPLICATION" Order="700" MsiKey="ExitDialog#LaunchProdCheckBox" Options="1"/>
     <ROW Dialog_="ExitDialog" Control="LaunchProdCheckBox" Type="CheckBox" X="135" Y="170" Width="10" Height="10" Attributes="2" Property="RUNAPPLICATION" Order="700" MsiKey="ExitDialog#LaunchProdCheckBox" Options="1"/>
     <ROW Dialog_="ExitDialog" Control="Description" Type="Text" X="135" Y="86" Width="220" Height="20" Attributes="196611" Text="Click the &quot;Finish&quot; button to exit the [Wizard]." Order="800" TextLocId="Control.Text.ExitDialog#Description" MsiKey="ExitDialog#Description"/>
     <ROW Dialog_="ExitDialog" Control="Description" Type="Text" X="135" Y="86" Width="220" Height="20" Attributes="196611" Text="Click the &quot;Finish&quot; button to exit the [Wizard]." Order="800" TextLocId="Control.Text.ExitDialog#Description" MsiKey="ExitDialog#Description"/>
     <ROW Dialog_="ExitDialog" Control="BottomLine" Type="Line" X="0" Y="234" Width="372" Height="0" Attributes="1" Order="900" MsiKey="ExitDialog#BottomLine"/>
     <ROW Dialog_="ExitDialog" Control="BottomLine" Type="Line" X="0" Y="234" Width="372" Height="0" Attributes="1" Order="900" MsiKey="ExitDialog#BottomLine"/>
+    <ROW Dialog_="ExitDialog" Control="Hyperlink" Type="Hyperlink" X="135" Y="140" Width="220" Height="20" Attributes="65539" Property="AiReadmeLink" Text="&lt;a href=&quot;[AiReadmeLink]&quot;&gt;View readme&lt;/a&gt;" Order="1000" TextLocId="Control.Text.ExitDialog#ViewReadmeHyperlink" MsiKey="ExitDialog#Hyperlink"/>
     <ROW Dialog_="WelcomeDlg" Control="WelcomeDlgDialogInitializer" Type="DialogInitializer" X="0" Y="0" Width="0" Height="0" Attributes="0" Order="-1" TextLocId="-" HelpLocId="-" ExtDataLocId="-"/>
     <ROW Dialog_="WelcomeDlg" Control="WelcomeDlgDialogInitializer" Type="DialogInitializer" X="0" Y="0" Width="0" Height="0" Attributes="0" Order="-1" TextLocId="-" HelpLocId="-" ExtDataLocId="-"/>
     <ROW Dialog_="Windows7Warning" Control="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Attributes="3" Text="[ButtonText_Next]" Order="100" Options="1"/>
     <ROW Dialog_="Windows7Warning" Control="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Attributes="3" Text="[ButtonText_Next]" Order="100" Options="1"/>
     <ROW Dialog_="Windows7Warning" Control="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Attributes="3" Text="[ButtonText_Cancel]" Order="200" Options="1"/>
     <ROW Dialog_="Windows7Warning" Control="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Attributes="3" Text="[ButtonText_Cancel]" Order="200" Options="1"/>
@@ -216,7 +208,7 @@
     <ATTRIBUTE name="DeletedRows" value="ExitDialog#LaunchProdText@ExitDialog#ViewReadmeText"/>
     <ATTRIBUTE name="DeletedRows" value="ExitDialog#LaunchProdText@ExitDialog#ViewReadmeText"/>
   </COMPONENT>
   </COMPONENT>
   <COMPONENT cid="caphyon.advinst.msicomp.MsiControlConditionComponent">
   <COMPONENT cid="caphyon.advinst.msicomp.MsiControlConditionComponent">
-    <ATTRIBUTE name="DeletedRows" value="ExitDialog#LaunchProdText#Hide#((NOT AI_INSTALL) AND (NOT AI_PATCH)) OR ((CTRLS &lt;&gt; 2) AND (CTRLS &lt;&gt; 3))@ExitDialog#ViewReadmeText#Hide#((NOT AI_INSTALL) AND (NOT AI_PATCH)) OR ((CTRLS &lt;&gt; 1) AND (CTRLS &lt;&gt; 3))"/>
+    <ATTRIBUTE name="DeletedRows" value="ExitDialog#LaunchProdText#Hide#((NOT AI_INSTALL) AND (NOT AI_PATCH)) OR ((CTRLS &lt;&gt; 2) AND (CTRLS &lt;&gt; 3))@ExitDialog#ViewReadmeText#Hide#(((NOT AI_INSTALL) AND (NOT AI_PATCH)) OR ((CTRLS &lt;&gt; 1) AND (CTRLS &lt;&gt; 3))) OR AiReadmeLink"/>
   </COMPONENT>
   </COMPONENT>
   <COMPONENT cid="caphyon.advinst.msicomp.MsiControlEventComponent">
   <COMPONENT cid="caphyon.advinst.msicomp.MsiControlEventComponent">
     <ROW Dialog_="WelcomeDlg" Control_="Next" Event="EndDialog" Argument="Return" Condition="AI_INSTALL" Ordering="3"/>
     <ROW Dialog_="WelcomeDlg" Control_="Next" Event="EndDialog" Argument="Return" Condition="AI_INSTALL" Ordering="3"/>
@@ -247,7 +239,6 @@
     <ROW Dialog_="WelcomeDlg" Control_="WelcomeDlgDialogInitializer" Event="[Text_Next]" Argument="[Text_Install]" Condition="AI_INSTALL" Ordering="3" Options="2"/>
     <ROW Dialog_="WelcomeDlg" Control_="WelcomeDlgDialogInitializer" Event="[Text_Next]" Argument="[Text_Install]" Condition="AI_INSTALL" Ordering="3" 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="[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"/>
   </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"/>
@@ -256,16 +247,13 @@
     <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_="ZeroTier_Dir" Component_="ZeroTier" ManualDelete="true"/>
     <ROW Directory_="One_Dir" Component_="One" ManualDelete="false"/>
     <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_="driverx64_Dir" Component_="driverx64" ManualDelete="false"/>
+    <ROW Directory_="driverx86_Dir" Component_="driverx86" ManualDelete="false"/>
     <ROW Directory_="i686_Dir" Component_="i686_1" ManualDelete="false"/>
     <ROW Directory_="i686_Dir" Component_="i686_1" ManualDelete="false"/>
+    <ROW Directory_="driverarm64_Dir" Component_="driverarm64" 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_BACKUP_AI_SETUPEXEPATH" Type="51" Source="AI_SETUPEXEPATH_ORIGINAL" Target="[AI_SETUPEXEPATH]"/>
     <ROW Action="AI_BACKUP_AI_SETUPEXEPATH" Type="51" Source="AI_SETUPEXEPATH_ORIGINAL" Target="[AI_SETUPEXEPATH]"/>
-    <ROW Action="AI_ChainerScheduleReboot" Type="1" Source="chainersupport.dll" Target="ScheduleReboot" WithoutSeq="true"/>
-    <ROW Action="AI_CommitChainers" Type="11841" Source="chainersupport.dll" Target="CommitChainedPackages" WithoutSeq="true"/>
     <ROW Action="AI_DATA_SETTER" Type="51" Source="CustomActionData" Target="[~]"/>
     <ROW Action="AI_DATA_SETTER" Type="51" Source="CustomActionData" Target="[~]"/>
     <ROW Action="AI_DATA_SETTER_1" Type="51" Source="CustomActionData" Target="[~]"/>
     <ROW Action="AI_DATA_SETTER_1" Type="51" Source="CustomActionData" Target="[~]"/>
     <ROW Action="AI_DATA_SETTER_2" Type="51" Source="CustomActionData" Target="[~]"/>
     <ROW Action="AI_DATA_SETTER_2" Type="51" Source="CustomActionData" Target="[~]"/>
@@ -278,7 +266,6 @@
     <ROW Action="AI_DeleteLzma" Type="1025" Source="lzmaextractor.dll" Target="DeleteLZMAFiles"/>
     <ROW Action="AI_DeleteLzma" Type="1025" Source="lzmaextractor.dll" Target="DeleteLZMAFiles"/>
     <ROW Action="AI_DeleteRCadLzma" Type="51" Source="AI_DeleteRLzma" Target="[AI_SETUPEXEPATH]"/>
     <ROW Action="AI_DeleteRCadLzma" Type="51" Source="AI_DeleteRLzma" Target="[AI_SETUPEXEPATH]"/>
     <ROW Action="AI_DeleteRLzma" Type="1281" Source="lzmaextractor.dll" Target="DeleteLZMAFiles"/>
     <ROW Action="AI_DeleteRLzma" Type="1281" Source="lzmaextractor.dll" Target="DeleteLZMAFiles"/>
-    <ROW Action="AI_DetectSoftware" Type="257" Source="SoftwareDetector.dll" Target="OnDetectSoftware"/>
     <ROW Action="AI_DoRemoveExternalUIStub" Type="3585" Source="ExternalUICleaner.dll" Target="DoRemoveExternalUIStub" WithoutSeq="true"/>
     <ROW Action="AI_DoRemoveExternalUIStub" Type="3585" Source="ExternalUICleaner.dll" Target="DoRemoveExternalUIStub" WithoutSeq="true"/>
     <ROW Action="AI_DpiContentScale" Type="1" Source="aicustact.dll" Target="DpiContentScale"/>
     <ROW Action="AI_DpiContentScale" Type="1" Source="aicustact.dll" Target="DpiContentScale"/>
     <ROW Action="AI_EnableDebugLog" Type="321" Source="aicustact.dll" Target="EnableDebugLog"/>
     <ROW Action="AI_EnableDebugLog" Type="321" Source="aicustact.dll" Target="EnableDebugLog"/>
@@ -295,13 +282,11 @@
     <ROW Action="AI_InstallModeCheck" Type="1" Source="aicustact.dll" Target="UpdateInstallMode" WithoutSeq="true"/>
     <ROW Action="AI_InstallModeCheck" Type="1" Source="aicustact.dll" Target="UpdateInstallMode" WithoutSeq="true"/>
     <ROW Action="AI_PREPARE_UPGRADE" Type="65" Source="aicustact.dll" Target="PrepareUpgrade"/>
     <ROW Action="AI_PREPARE_UPGRADE" Type="65" Source="aicustact.dll" Target="PrepareUpgrade"/>
     <ROW Action="AI_PRESERVE_INSTALL_TYPE" Type="65" Source="aicustact.dll" Target="PreserveInstallType"/>
     <ROW Action="AI_PRESERVE_INSTALL_TYPE" Type="65" Source="aicustact.dll" Target="PreserveInstallType"/>
-    <ROW Action="AI_PrepareChainers" Type="1" Source="chainersupport.dll" Target="PrepareChainedPackages"/>
     <ROW Action="AI_RESTORE_AI_SETUPEXEPATH" Type="51" Source="AI_SETUPEXEPATH" Target="[AI_SETUPEXEPATH_ORIGINAL]"/>
     <ROW Action="AI_RESTORE_AI_SETUPEXEPATH" Type="51" Source="AI_SETUPEXEPATH" Target="[AI_SETUPEXEPATH_ORIGINAL]"/>
     <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_ResolveLocalizedCredentials" Type="1" Source="aicustact.dll" Target="GetLocalizedCredentials"/>
-    <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]"/>
     <ROW Action="AI_TxtUpdaterCommit" Type="11777" Source="TxtUpdater.dll" Target="OnTxtUpdaterCommit" WithoutSeq="true"/>
     <ROW Action="AI_TxtUpdaterCommit" Type="11777" Source="TxtUpdater.dll" Target="OnTxtUpdaterCommit" WithoutSeq="true"/>
@@ -326,9 +311,6 @@
   <COMPONENT cid="caphyon.advinst.msicomp.MsiDialogComponent">
   <COMPONENT cid="caphyon.advinst.msicomp.MsiDialogComponent">
     <ROW Dialog="Windows7Warning" HCentering="50" VCentering="50" Width="370" Height="270" Attributes="3" Title="[ProductName] [Setup]" Control_Default="Next" Control_Cancel="Cancel"/>
     <ROW Dialog="Windows7Warning" HCentering="50" VCentering="50" Width="370" Height="270" Attributes="3" Title="[ProductName] [Setup]" Control_Default="Next" Control_Cancel="Cancel"/>
   </COMPONENT>
   </COMPONENT>
-  <COMPONENT cid="caphyon.advinst.msicomp.MsiEmbeddedChainerComponent">
-    <ROW MsiEmbeddedChainer="msichainer.exe" Condition="VersionMsi &gt;= &quot;4.05&quot;" CommandLine="[AI_CHAINER_CMD_LINE]" Source="msichainer.exe" Type="2"/>
-  </COMPONENT>
   <COMPONENT cid="caphyon.advinst.msicomp.MsiEnvComponent">
   <COMPONENT cid="caphyon.advinst.msicomp.MsiEnvComponent">
     <ROW Environment="Path" Name="=-*Path" Value="[~];[APPDIR]" Component_="regid.201001.com.zerotier"/>
     <ROW Environment="Path" Name="=-*Path" Value="[~];[APPDIR]" Component_="regid.201001.com.zerotier"/>
   </COMPONENT>
   </COMPONENT>
@@ -338,21 +320,22 @@
     <ROW Feature_="ZeroTierOne" Component_="regid.201001.com.zerotier"/>
     <ROW Feature_="ZeroTierOne" Component_="regid.201001.com.zerotier"/>
     <ROW Feature_="ZeroTierOne" Component_="zerotierone_x64.exe"/>
     <ROW Feature_="ZeroTierOne" Component_="zerotierone_x64.exe"/>
     <ROW Feature_="ZeroTierOne" Component_="zerotierone_x86.exe"/>
     <ROW Feature_="ZeroTierOne" Component_="zerotierone_x86.exe"/>
-    <ROW Feature_="ZeroTierOne" Component_="zttap300_x86_win10"/>
-    <ROW Feature_="MainFeature" Component_="APPDIR"/>
-    <ROW Feature_="ZeroTierOne" Component_="zttap300_x64_win10"/>
     <ROW Feature_="ZeroTierOne" Component_="AI_CustomARPName"/>
     <ROW Feature_="ZeroTierOne" Component_="AI_CustomARPName"/>
     <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_="ZeroTierOne" Component_="AI_ExePath"/>
     <ROW Feature_="ZeroTierOne" Component_="i686"/>
     <ROW Feature_="ZeroTierOne" Component_="i686"/>
     <ROW Feature_="ZeroTierOne" Component_="ZeroTier"/>
     <ROW Feature_="ZeroTierOne" Component_="ZeroTier"/>
     <ROW Feature_="ZeroTierOne" Component_="One"/>
     <ROW Feature_="ZeroTierOne" Component_="One"/>
-    <ROW Feature_="ZeroTierOne" Component_="tapwindows"/>
-    <ROW Feature_="ZeroTierOne" Component_="x64"/>
-    <ROW Feature_="ZeroTierOne" Component_="x86"/>
+    <ROW Feature_="ZeroTierOne" Component_="driverx64"/>
     <ROW Feature_="ZeroTierOne" Component_="i686_1"/>
     <ROW Feature_="ZeroTierOne" Component_="i686_1"/>
+    <ROW Feature_="zttap300" Component_="zttap300.inf"/>
+    <ROW Feature_="ZeroTierOne" Component_="driverx86"/>
+    <ROW Feature_="zttap300_1" Component_="zttap300.inf_1"/>
+    <ROW Feature_="ZeroTierOne" Component_="driverarm64"/>
+    <ROW Feature_="zttap300_2" Component_="zttap300.inf_2"/>
+    <ROW Feature_="ZeroTierOne" Component_="APPDIR"/>
+    <ROW Feature_="ZeroTierOne" Component_="AI_ExePath"/>
   </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"/>
@@ -375,10 +358,9 @@
     <ROW Action="AI_DATA_SETTER_2" Condition="(VersionNT &gt;= 501) AND (REMOVE &lt;&gt; &quot;ALL&quot;)" Sequence="5801"/>
     <ROW Action="AI_DATA_SETTER_2" Condition="(VersionNT &gt;= 501) AND (REMOVE &lt;&gt; &quot;ALL&quot;)" Sequence="5801"/>
     <ROW Action="AI_FwUninstall" Condition="(VersionNT &gt;= 501) AND (REMOVE=&quot;ALL&quot;)" Sequence="1702"/>
     <ROW Action="AI_FwUninstall" Condition="(VersionNT &gt;= 501) AND (REMOVE=&quot;ALL&quot;)" Sequence="1702"/>
     <ROW Action="AI_DATA_SETTER_3" Condition="(VersionNT &gt;= 501) AND (REMOVE=&quot;ALL&quot;)" Sequence="1701"/>
     <ROW Action="AI_DATA_SETTER_3" Condition="(VersionNT &gt;= 501) AND (REMOVE=&quot;ALL&quot;)" Sequence="1701"/>
-    <ROW Action="AI_DetectSoftware" Sequence="103"/>
     <ROW Action="AI_TxtUpdaterInstall" Sequence="5101"/>
     <ROW Action="AI_TxtUpdaterInstall" Sequence="5101"/>
     <ROW Action="AI_BACKUP_AI_SETUPEXEPATH" Sequence="99" Builds="ExeBuild"/>
     <ROW Action="AI_BACKUP_AI_SETUPEXEPATH" Sequence="99" Builds="ExeBuild"/>
-    <ROW Action="AI_RESTORE_AI_SETUPEXEPATH" Condition="AI_SETUPEXEPATH_ORIGINAL" Sequence="102" Builds="ExeBuild"/>
+    <ROW Action="AI_RESTORE_AI_SETUPEXEPATH" Condition="AI_SETUPEXEPATH_ORIGINAL" Sequence="101" Builds="ExeBuild"/>
     <ROW Action="AI_DeleteCadLzma" 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="199" Builds="ExeBuild"/>
     <ROW Action="AI_DeleteCadLzma" 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="199" Builds="ExeBuild"/>
     <ROW Action="AI_DeleteRCadLzma" 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="198" Builds="ExeBuild"/>
     <ROW Action="AI_DeleteRCadLzma" 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="198" Builds="ExeBuild"/>
     <ROW Action="AI_ExtractCadLzma" 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="197" Builds="ExeBuild"/>
     <ROW Action="AI_ExtractCadLzma" 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="197" Builds="ExeBuild"/>
@@ -389,8 +371,6 @@
     <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="52"/>
     <ROW Action="AI_EnableDebugLog" Sequence="52"/>
-    <ROW Action="AI_AppSearchEx" Sequence="101"/>
-    <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"/>
     <ROW Action="AI_DATA_SETTER_4" Sequence="1398"/>
     <ROW Action="AI_DATA_SETTER_4" Sequence="1398"/>
     <ROW Action="AI_GetArpIconPath" Sequence="1401"/>
     <ROW Action="AI_GetArpIconPath" Sequence="1401"/>
@@ -405,22 +385,18 @@
     <ROW Action="AI_ResolveKnownFolders" Sequence="54"/>
     <ROW Action="AI_ResolveKnownFolders" Sequence="54"/>
     <ROW Action="AI_DpiContentScale" Sequence="53"/>
     <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="101"/>
     <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_EnableDebugLog" Sequence="52"/>
     <ROW Action="AI_EnableDebugLog" Sequence="52"/>
-    <ROW Action="AI_AppSearchEx" Sequence="101"/>
     <ROW Action="AI_ResolveLocalizedCredentials" Sequence="51"/>
     <ROW Action="AI_ResolveLocalizedCredentials" Sequence="51"/>
     <ROW Action="AI_PRESERVE_INSTALL_TYPE" Sequence="199"/>
     <ROW Action="AI_PRESERVE_INSTALL_TYPE" Sequence="199"/>
   </COMPONENT>
   </COMPONENT>
   <COMPONENT cid="caphyon.advinst.msicomp.MsiLaunchConditionsComponent">
   <COMPONENT cid="caphyon.advinst.msicomp.MsiLaunchConditionsComponent">
-    <ROW Condition="( Version9X OR ( NOT VersionNT64 ) OR ( VersionNT64 AND ((VersionNT64 &lt;&gt; 600) OR (MsiNTProductType &lt;&gt; 1)) AND ((VersionNT64 &lt;&gt; 600) OR (MsiNTProductType = 1)) AND ((VersionNT64 &lt;&gt; 601) OR (MsiNTProductType &lt;&gt; 1)) AND ((VersionNT64 &lt;&gt; 601) OR (MsiNTProductType = 1)) ) )" Description="[ProductName] cannot be installed on the following Windows versions: [WindowsTypeNT64Display]." DescriptionLocId="AI.LaunchCondition.NoSpecificNT64" IsPredefined="true" Builds="DefaultBuild"/>
-    <ROW Condition="( Version9X OR VersionNT64 OR ( VersionNT AND ((VersionNT &lt;&gt; 600) OR (MsiNTProductType &lt;&gt; 1)) AND ((VersionNT &lt;&gt; 600) OR (MsiNTProductType = 1)) AND (VersionNT &lt;&gt; 601) ) )" Description="[ProductName] cannot be installed on the following Windows versions: [WindowsTypeNTDisplay]." DescriptionLocId="AI.LaunchCondition.NoSpecificNT" IsPredefined="true" Builds="DefaultBuild"/>
+    <ROW Condition="( Version9X OR ( NOT VersionNT64 ) OR ( VersionNT64 AND ((VersionNT64 &lt;&gt; 600) OR (MsiNTProductType &lt;&gt; 1)) AND ((VersionNT64 &lt;&gt; 600) OR (MsiNTProductType = 1)) AND ((VersionNT64 &lt;&gt; 601) OR (MsiNTProductType &lt;&gt; 1)) AND ((VersionNT64 &lt;&gt; 601) OR (MsiNTProductType = 1)) AND ((VersionNT64 &lt;&gt; 602) OR (MsiNTProductType &lt;&gt; 1)) AND ((VersionNT64 &lt;&gt; 602) OR (MsiNTProductType = 1)) AND ((VersionNT64 &lt;&gt; 603) OR (MsiNTProductType &lt;&gt; 1)) AND ((VersionNT64 &lt;&gt; 603) OR (MsiNTProductType = 1)) ) )" Description="[ProductName] cannot be installed on the following Windows versions: [WindowsTypeNT64Display]." DescriptionLocId="AI.LaunchCondition.NoSpecificNT64" IsPredefined="true" Builds="DefaultBuild"/>
+    <ROW Condition="( Version9X OR VersionNT64 OR ( VersionNT AND ((VersionNT &lt;&gt; 600) OR (MsiNTProductType &lt;&gt; 1)) AND ((VersionNT &lt;&gt; 600) OR (MsiNTProductType = 1)) AND (VersionNT &lt;&gt; 601) AND (VersionNT &lt;&gt; 602) AND (VersionNT &lt;&gt; 603) ) )" Description="[ProductName] cannot be installed on the following Windows versions: [WindowsTypeNTDisplay]." DescriptionLocId="AI.LaunchCondition.NoSpecificNT" IsPredefined="true" Builds="DefaultBuild"/>
     <ROW Condition="((VersionNT &lt;&gt; 501) AND (VersionNT &lt;&gt; 502))" Description="[ProductName] cannot be installed on [WindowsTypeNT5XDisplay]." DescriptionLocId="AI.LaunchCondition.NoNT5X" IsPredefined="true" Builds="DefaultBuild;ExeBuild"/>
     <ROW Condition="((VersionNT &lt;&gt; 501) AND (VersionNT &lt;&gt; 502))" Description="[ProductName] cannot be installed on [WindowsTypeNT5XDisplay]." DescriptionLocId="AI.LaunchCondition.NoNT5X" IsPredefined="true" Builds="DefaultBuild;ExeBuild"/>
     <ROW Condition="(VersionNT &lt;&gt; 400)" Description="[ProductName] cannot be installed on [WindowsTypeNT40Display]." DescriptionLocId="AI.LaunchCondition.NoNT40" IsPredefined="true" Builds="DefaultBuild;ExeBuild"/>
     <ROW Condition="(VersionNT &lt;&gt; 400)" Description="[ProductName] cannot be installed on [WindowsTypeNT40Display]." DescriptionLocId="AI.LaunchCondition.NoNT40" IsPredefined="true" Builds="DefaultBuild;ExeBuild"/>
     <ROW Condition="(VersionNT &lt;&gt; 500)" Description="[ProductName] cannot be installed on [WindowsTypeNT50Display]." DescriptionLocId="AI.LaunchCondition.NoNT50" IsPredefined="true" Builds="DefaultBuild;ExeBuild"/>
     <ROW Condition="(VersionNT &lt;&gt; 500)" Description="[ProductName] cannot be installed on [WindowsTypeNT50Display]." DescriptionLocId="AI.LaunchCondition.NoNT50" IsPredefined="true" Builds="DefaultBuild;ExeBuild"/>
-    <ROW Condition="AI_DETECTED_DOTNET_VERSION &gt;= AI_REQUIRED_DOTNET_VERSION" Description="[ProductName] cannot be installed on systems with .NET Framework version lower than [AI_REQUIRED_DOTNET_DISPLAY]." DescriptionLocId="AI.LaunchCondition.DotNET" IsPredefined="true" Builds="DefaultBuild"/>
-    <ROW Condition="NOT AiArm64" Description="[ProductName] cannot be installed on systems running on ARM64 processors. Check for a ARM64 version of [ProductName]" DescriptionLocId="AI.LaunchCondition.ARM64" IsPredefined="true" Builds="DefaultBuild"/>
     <ROW Condition="Privileged" Description="[ProductName] requires administrative privileges to install." DescriptionLocId="AI.LaunchCondition.Privileged" IsPredefined="true" Builds="DefaultBuild"/>
     <ROW Condition="Privileged" Description="[ProductName] requires administrative privileges to install." DescriptionLocId="AI.LaunchCondition.Privileged" IsPredefined="true" Builds="DefaultBuild"/>
     <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"/>
@@ -432,15 +408,13 @@
     <ROW LockObject="One_Dir" Table="CreateFolder" User="[GRP_EVERYONE]" Permission="1179817" 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_ADMINISTRATORS]" Permission="1245631" Flags="0"/>
     <ROW LockObject="networks.d_Dir" Table="CreateFolder" User="[GRP_EVERYONE]" Permission="1179817" 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="driverx64_Dir" Table="CreateFolder" User="[GRP_EVERYONE]" Permission="1179817" Flags="0"/>
+    <ROW LockObject="driverx86_Dir" Table="CreateFolder" User="[GRP_EVERYONE]" Permission="1179817" Flags="0"/>
+    <ROW LockObject="driverarm64_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="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="APPDIR" Table="CreateFolder" User="[GRP_EVERYONE]" Permission="1179817" Flags="0"/>
     <ROW LockObject="i686_Dir" Table="CreateFolder" User="[GRP_EVERYONE]" Permission="1179817" Flags="0"/>
     <ROW LockObject="i686_Dir" Table="CreateFolder" User="[GRP_EVERYONE]" Permission="1179817" Flags="0"/>
+    <ROW LockObject="driverarm64_Dir" Table="CreateFolder" User="[GRP_ADMINISTRATORS]" Permission="1245631" Flags="0"/>
   </COMPONENT>
   </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"/>
@@ -503,10 +477,6 @@
     <ROW UpgradeCode="[|UpgradeCode]" VersionMin="0.0.1" VersionMax="[|ProductVersion]" Attributes="257" ActionProperty="OLDPRODUCTS"/>
     <ROW UpgradeCode="[|UpgradeCode]" VersionMin="0.0.1" VersionMax="[|ProductVersion]" Attributes="257" ActionProperty="OLDPRODUCTS"/>
     <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.PreReqSearchComponent">
-    <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"/>
-  </COMPONENT>
   <COMPONENT cid="caphyon.advinst.msicomp.SoftwareIdentificationComponent">
   <COMPONENT cid="caphyon.advinst.msicomp.SoftwareIdentificationComponent">
     <ATTRIBUTE name="LocalFile" value="regid.199509.com.example_ProductName.swidtag"/>
     <ATTRIBUTE name="LocalFile" value="regid.199509.com.example_ProductName.swidtag"/>
     <ATTRIBUTE name="SystemFile" value="regid.199509.com.example_ProductName.swidtag_1"/>
     <ATTRIBUTE name="SystemFile" value="regid.199509.com.example_ProductName.swidtag_1"/>
@@ -528,10 +498,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="10" UpdateIndexInParent="0"/>
+    <ROW XmlElement="swidminor" ParentElement="swidnumeric" Name="swid:minor" Condition="1" Order="1" Flags="14" Text="12" 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"/>

+ 558 - 0
ext/installfiles/windows/ZeroTier One.back.aip

@@ -0,0 +1,558 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<DOCUMENT Type="Advanced Installer" CreateVersion="10.9" version="20.4.1" 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;SharePointSlnComponent;AppXAppDetailsComponent;FixupComponent;AppXCapabilitiesComponent;AppXDependenciesComponent;AppXProductDetailsComponent;AppXVisualAssetsComponent;AppXAppDeclarationsComponent;AppXUriRulesComponent;MsiXDiffComponent;MsixManifestEditorComponent"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiPropsComponent">
+    <ROW Property="AI_BITMAP_DISPLAY_MODE" Value="0"/>
+    <ROW Property="AI_EMBD_MSI_EXTR_PATH" Value="[TempFolder]" ValueLocId="-"/>
+    <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_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_REQUIRED_DOTNET_DISPLAY" MultiBuildValue="DefaultBuild:4.5" ValueLocId="-"/>
+    <ROW Property="AI_REQUIRED_DOTNET_VERSION" MultiBuildValue="DefaultBuild:4.5" ValueLocId="-"/>
+    <ROW Property="AI_ThemeStyle" Value="aero" MsiKey="AI_ThemeStyle"/>
+    <ROW Property="AI_UNINSTALLER" Value="msiexec.exe"/>
+    <ROW Property="ALLUSERS" Value="1"/>
+    <ROW Property="ARPCOMMENTS" Value="This installer database contains the logic and data required to install [|ProductName]."/>
+    <ROW Property="ARPCONTACT" Value="[email protected]"/>
+    <ROW Property="ARPHELPLINK" Value="https://www.zerotier.com/"/>
+    <ROW Property="ARPHELPTELEPHONE" Value="949-505-9993"/>
+    <ROW Property="ARPNOMODIFY" MultiBuildValue="DefaultBuild:1"/>
+    <ROW Property="ARPNOREPAIR" Value="1" MultiBuildValue="ExeBuild:1"/>
+    <ROW Property="ARPPRODUCTICON" Value="ZeroTierIcon.exe" Type="8"/>
+    <ROW Property="ARPSYSTEMCOMPONENT" Value="1"/>
+    <ROW Property="ARPURLINFOABOUT" Value="https://www.zerotier.com/"/>
+    <ROW Property="ARPURLUPDATEINFO" Value="https://www.zerotier.com/"/>
+    <ROW Property="AiFeatIcoZeroTierOne" Value="ZeroTierIcon.exe" Type="8"/>
+    <ROW Property="LIMITUI" MultiBuildValue="DefaultBuild:1"/>
+    <ROW Property="MSIFASTINSTALL" MultiBuildValue="DefaultBuild:2"/>
+    <ROW Property="Manufacturer" Value="ZeroTier, Inc."/>
+    <ROW Property="ProductCode" Value="1033:{8D8ECA43-43FF-4358-84E9-4629D8855C03} " Type="16"/>
+    <ROW Property="ProductLanguage" Value="1033"/>
+    <ROW Property="ProductName" Value="ZeroTier One"/>
+    <ROW Property="ProductVersion" Value="1.10.6"/>
+    <ROW Property="REBOOT" MultiBuildValue="DefaultBuild:ReallySuppress"/>
+    <ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND;AI_SETUPEXEPATH;SETUPEXEDIR"/>
+    <ROW Property="UpgradeCode" Value="{B0E2A5F3-88B6-4E77-B922-CB4739B4C4C8}"/>
+    <ROW Property="WindowsType9X" MultiBuildValue="DefaultBuild:Windows 9x/ME#ExeBuild:Windows 9x/ME" ValueLocId="-"/>
+    <ROW Property="WindowsType9XDisplay" MultiBuildValue="DefaultBuild:Windows 9x/ME#ExeBuild:Windows 9x/ME" ValueLocId="-"/>
+    <ROW Property="WindowsTypeNT" MultiBuildValue="DefaultBuild:Windows Vista x86, Windows Server 2008 x86, Windows 7 x86" ValueLocId="-"/>
+    <ROW Property="WindowsTypeNT40" MultiBuildValue="DefaultBuild:Windows NT 4.0#ExeBuild:Windows NT 4.0" ValueLocId="-"/>
+    <ROW Property="WindowsTypeNT40Display" MultiBuildValue="DefaultBuild:Windows NT 4.0#ExeBuild:Windows NT 4.0" ValueLocId="-"/>
+    <ROW Property="WindowsTypeNT50" MultiBuildValue="DefaultBuild:Windows 2000#ExeBuild:Windows 2000" ValueLocId="-"/>
+    <ROW Property="WindowsTypeNT50Display" MultiBuildValue="DefaultBuild:Windows 2000#ExeBuild:Windows 2000" ValueLocId="-"/>
+    <ROW Property="WindowsTypeNT5X" MultiBuildValue="DefaultBuild:Windows XP/2003#ExeBuild:Windows XP/2003" ValueLocId="-"/>
+    <ROW Property="WindowsTypeNT5XDisplay" MultiBuildValue="DefaultBuild:Windows XP/2003#ExeBuild:Windows XP/2003" ValueLocId="-"/>
+    <ROW Property="WindowsTypeNT64" MultiBuildValue="DefaultBuild:Windows Vista x64, Windows Server 2008 x64, Windows 7 x64, Windows Server 2008 R2 x64" ValueLocId="-"/>
+    <ROW Property="WindowsTypeNT64Display" MultiBuildValue="DefaultBuild:Windows Vista x64, Windows Server 2008 x64, Windows 7 x64, Windows Server 2008 R2 x64" ValueLocId="-"/>
+    <ROW Property="WindowsTypeNTDisplay" MultiBuildValue="DefaultBuild:Windows Vista x86, Windows Server 2008 x86, Windows 7 x86" ValueLocId="-"/>
+    <ROW Property="ZTHEADLESS" Value="No"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiDirsComponent">
+    <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="One_Dir" Directory_Parent="ZeroTier_Dir" DefaultDir="One" DirectoryOptions="12"/>
+    <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="TARGETDIR" DefaultDir="SourceDir"/>
+    <ROW Directory="ZeroTier_Dir" Directory_Parent="CommonAppDataFolder" DefaultDir="ZeroTier" DirectoryOptions="12"/>
+    <ROW Directory="i686_1_Dir" Directory_Parent="ProgramMenuFolder" DefaultDir=".:i686"/>
+    <ROW Directory="i686_Dir" Directory_Parent="APPDIR" DefaultDir=".:i686" DirectoryOptions="15"/>
+    <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" DirectoryOptions="12"/>
+    <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" DirectoryOptions="12"/>
+    <ROW Directory="x86_Dir" Directory_Parent="tapwindows_Dir" DefaultDir="x86" DirectoryOptions="12"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiCompsComponent">
+    <ROW Component="AI_CustomARPName" ComponentId="{D8521222-B184-44D4-84AE-8B6549555BD8}" 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_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="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="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_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="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_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_x86.exe" ComponentId="{5D2F3366-4FE1-40A4-A81A-66C49FA11F1C}" Directory_="One_Dir" Attributes="0" Condition="NOT VersionNT64" KeyPath="zerotierone_x86.exe"/>
+    <ROW Component="zttap300_x64_win10" ComponentId="{D4839F5E-FB94-41CB-9B1B-177A97ADC904}" Directory_="x64_Dir" Attributes="256" Condition="VersionNT64" KeyPath="zttap300.inf"/>
+    <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 cid="caphyon.advinst.msicomp.MsiFeatsComponent">
+    <ROW Feature="MainFeature" Title="MainFeature" Description="Description" Display="1" 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"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiFilesComponent">
+    <ROW File="zerotierone_x86.exe" Component_="zerotierone_x86.exe" FileName="ZEROTI~1.EXE|zerotier-one_x86.exe" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\windows\Build\Win32\Release\zerotier-one_x86.exe" SelfReg="false" DigSign="true"/>
+    <ROW File="zerotierone_x64.exe" Component_="zerotierone_x64.exe" FileName="ZEROTI~2.EXE|zerotier-one_x64.exe" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\windows\Build\x64\Release\zerotier-one_x64.exe" SelfReg="false" DigSign="true"/>
+    <ROW File="zttap300.cat_2" Component_="zttap300_x64_win10" FileName="zttap300.cat" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x64\zttap300.cat" SelfReg="false"/>
+    <ROW File="zttap300.sys_2" Component_="zttap300_x64_win10" FileName="zttap300.sys" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x64\zttap300.sys" SelfReg="false"/>
+    <ROW File="zttap300.inf" Component_="zttap300_x64_win10" FileName="zttap300.inf" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x64\zttap300.inf" SelfReg="false"/>
+    <ROW File="zttap300.cat_3" Component_="zttap300_x86_win10" FileName="zttap300.cat" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x86\zttap300.cat" SelfReg="false"/>
+    <ROW File="zttap300.sys_3" Component_="zttap300_x86_win10" FileName="zttap300.sys" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x86\zttap300.sys" SelfReg="false"/>
+    <ROW File="zttap300.inf_1" Component_="zttap300_x86_win10" FileName="zttap300.inf" Attributes="0" SourcePath="..\..\bin\tap-windows-ndis6\x86\zttap300.inf" SelfReg="false"/>
+    <ROW File="zerotier_desktop_ui.exe" Component_="zerotier_desktop_ui.exe" FileName="ZEROTI~2.EXE|zerotier_desktop_ui.exe" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\..\DesktopUI\target\x86_64-pc-windows-msvc\release\zerotier_desktop_ui.exe" SelfReg="false" DigSign="true"/>
+    <ROW File="zerotier_desktop_ui.exe_1" Component_="zerotier_desktop_ui.exe_1" FileName="ZEROTI~1.EXE|zerotier_desktop_ui.exe" Version="65535.65535.65535.65535" Attributes="0" SourcePath="..\..\..\..\DesktopUI\target\i686-pc-windows-msvc\release\zerotier_desktop_ui.exe" SelfReg="false" DigSign="true"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.custcomp.AiComponentAliasComponent">
+    <ROW AliasRowId="AI_CustomARPName" AliasRowOperation="2" Condition="#DefaultBuild:ZTHEADLESS=&quot;No&quot;"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.BootstrOptComponent">
+    <ROW BootstrOptKey="GlobalOptions" GeneralOptions="qh" DownloadFolder="[AppDataFolder][|Manufacturer]\[|ProductName]\prerequisites"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.BootstrapperUISequenceComponent">
+    <ROW Action="AI_DetectSoftware" Sequence="101"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.BuildComponent">
+    <ROW BuildKey="DefaultBuild" BuildName="MSI" BuildOrder="1" BuildType="0" PackageFolder="..\..\.." PackageFileName="ZeroTier One" Languages="en" InstallationType="4" ExtUI="true" UseLargeSchema="true"/>
+    <ROW BuildKey="ExeBuild" BuildName="update" BuildOrder="2" BuildType="0" PackageFolder="..\..\.." PackageFileName="ZeroTier One" Languages="en" InstallationType="2" CabsLocation="1" CompressCabs="false" UseLzma="true" LzmaMethod="2" LzmaCompressionLevel="4" PackageType="1" FilesInsideExe="true" ExeIconPath="..\..\..\artwork\ZeroTierIcon.ico" ExtractionFolder="[AppDataFolder][|Manufacturer]\[|ProductName] [|ProductVersion]\install" MsiCmdLine="/qn" ExtUI="true" UseLargeSchema="true" ExeName="zt1_update_2_1,2_[|ProductVersion]_0"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.CacheComponent">
+    <ATTRIBUTE name="Enable" value="false"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.ChainedPackageComponent">
+    <ROW ChainedPackage="ZeroTierOne_NDIS6_x64.msi" Order="1" Options="110" InstallCondition="VersionNT64 AND VersionNT &gt;= 1000" MaintenanceCondition="FALSE" RemoveCondition="REMOVE=&quot;ALL&quot; AND VersionNT64"/>
+    <ROW ChainedPackage="ZeroTierOne_NDIS6_x86.msi" Order="2" Options="110" InstallCondition="(NOT VersionNT64) And VersionNT &gt;= 1000" MaintenanceCondition="FALSE" RemoveCondition="REMOVE=&quot;ALL&quot; AND (NOT VersionNT64)"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.ChainedPackageFileComponent">
+    <ROW FileId="ZeroTierOne_NDIS6_x64.msi" ChainedPackage="ZeroTierOne_NDIS6_x64.msi" Options="1" TargetPath="ZeroTierOne_NDIS6_x64.msi" Content="..\..\bin\tap-windows-ndis6\x64\ZeroTierOne_NDIS6_x64.msi"/>
+    <ROW FileId="ZeroTierOne_NDIS6_x86.msi" ChainedPackage="ZeroTierOne_NDIS6_x86.msi" Options="1" TargetPath="ZeroTierOne_NDIS6_x86.msi" Content="..\..\bin\tap-windows-ndis6\x86\ZeroTierOne_NDIS6_x86.msi"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.DictionaryComponent">
+    <ROW Path="&lt;AI_DICTS&gt;ui.ail"/>
+    <ROW Path="&lt;AI_DICTS&gt;ui_en.ail"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.DigCertStoreComponent">
+    <ROW TimeStampUrl="http://timestamp.digicert.com" SignerDescription="ZeroTier One" DescriptionUrl="https://www.zerotier.com/" SignOptions="7" SignTool="5" UseSha256="1" KVTenantId="5300bf3b-0eff-4a5f-a63f-821e22ed1730" KVAppId="5f94d77e-b795-41fd-afe7-ec913b03c1d3" KVName="ZeroTier-CS" KVCertName="ZT-EV-CS" KVCertVersion="442c2d6f77874ff99eed4b36f5cb401c"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.FirewallExceptionComponent">
+    <ROW FirewallException="ZeroTierOneUDP9993" Direction="1" Action="1" DisplayName="ZeroTier UDP/9993 In" GroupName="ZeroTierOne" Enabled="1" Scope="*" Condition="1" Profiles="7" Port="9993" Protocol="UDP"/>
+    <ROW FirewallException="ZeroTierOnex64Binary" Direction="1" Action="1" DisplayName="ZeroTier x64 Binary In" GroupName="ZeroTierOne" Enabled="1" Scope="*" Condition="((?zerotierone_x64.exe=2) AND ($zerotierone_x64.exe=3))" Profiles="7" AppPath="[#zerotierone_x64.exe]" Port="*" Protocol="ANY"/>
+    <ROW FirewallException="ZeroTierOnex86Binary" Direction="1" Action="1" DisplayName="ZeroTier x86 Binary In" GroupName="ZeroTierOne" Enabled="1" Scope="*" Condition="((?zerotierone_x86.exe=2) AND ($zerotierone_x86.exe=3))" Profiles="7" AppPath="[#zerotierone_x86.exe]" Port="*" Protocol="ANY"/>
+    <ROW FirewallException="ZeroTierUDP9993Out" Direction="2" Action="1" DisplayName="ZeroTier UDP/9993 Out" GroupName="ZeroTierOne" Enabled="1" Scope="*" Condition="1" Profiles="7" Port="9993" Protocol="UDP"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.FragmentComponent">
+    <ROW Fragment="CommonUI.aip" Path="&lt;AI_FRAGS&gt;CommonUI.aip"/>
+    <ROW Fragment="MaintenanceTypeDlg.aip" Path="&lt;AI_THEMES&gt;classic\fragments\MaintenanceTypeDlg.aip"/>
+    <ROW Fragment="MaintenanceWelcomeDlg.aip" Path="&lt;AI_THEMES&gt;classic\fragments\MaintenanceWelcomeDlg.aip"/>
+    <ROW Fragment="SequenceDialogs.aip" Path="&lt;AI_THEMES&gt;classic\fragments\SequenceDialogs.aip"/>
+    <ROW Fragment="Sequences.aip" Path="&lt;AI_FRAGS&gt;Sequences.aip"/>
+    <ROW Fragment="StaticUIStrings.aip" Path="&lt;AI_FRAGS&gt;StaticUIStrings.aip"/>
+    <ROW Fragment="Themes.aip" Path="&lt;AI_FRAGS&gt;Themes.aip"/>
+    <ROW Fragment="UI.aip" Path="&lt;AI_THEMES&gt;classic\fragments\UI.aip"/>
+    <ROW Fragment="Validation.aip" Path="&lt;AI_FRAGS&gt;Validation.aip"/>
+    <ROW Fragment="VerifyRemoveDlg.aip" Path="&lt;AI_THEMES&gt;classic\fragments\VerifyRemoveDlg.aip"/>
+    <ROW Fragment="VerifyRepairDlg.aip" Path="&lt;AI_THEMES&gt;classic\fragments\VerifyRepairDlg.aip"/>
+    <ROW Fragment="WelcomeDlg.aip" Path="&lt;AI_THEMES&gt;classic\fragments\WelcomeDlg.aip"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiActionTextComponent">
+    <ROW Action="AI_DeleteLzma" Description="Deleting files extracted from archive" DescriptionLocId="ActionText.Description.AI_DeleteLzma" TemplateLocId="-"/>
+    <ROW Action="AI_DeleteRLzma" Description="Deleting files extracted from archive" DescriptionLocId="ActionText.Description.AI_DeleteLzma" TemplateLocId="-"/>
+    <ROW Action="AI_ExtractFiles" Description="Extracting files from archive" DescriptionLocId="ActionText.Description.AI_ExtractLzma" TemplateLocId="-"/>
+    <ROW Action="AI_ExtractLzma" Description="Extracting files from archive" DescriptionLocId="ActionText.Description.AI_ExtractLzma" TemplateLocId="-"/>
+    <ROW Action="AI_FwConfig" Description="Executing Windows Firewall configurations" DescriptionLocId="ActionText.Description.AI_FwConfig" Template="Configuring Windows Firewall rule: &quot;[1]&quot;" TemplateLocId="ActionText.Template.AI_FwConfig"/>
+    <ROW Action="AI_FwInstall" Description="Generating actions to configure Windows Firewall" DescriptionLocId="ActionText.Description.AI_FwInstall"/>
+    <ROW Action="AI_FwRemove" Description="Executing Windows Firewall configurations" DescriptionLocId="ActionText.Description.AI_FwRemove" Template="Configuring Windows Firewall rule:  &quot;[1]&quot;" TemplateLocId="ActionText.Template.AI_FwRemove"/>
+    <ROW Action="AI_FwRollback" Description="Rolling back Windows Firewall configurations." DescriptionLocId="ActionText.Description.AI_FwRollback" Template="Rolling back Windows Firewall configurations." TemplateLocId="ActionText.Template.AI_FwRollback"/>
+    <ROW Action="AI_FwUninstall" Description="Generating actions to configure Windows Firewall" DescriptionLocId="ActionText.Description.AI_FwUninstall"/>
+    <ROW Action="AI_TxtUpdaterCommit" Description="Commit text file changes. " DescriptionLocId="ActionText.Description.AI_TxtUpdaterCommit" Template="Commit text file changes." TemplateLocId="ActionText.Template.AI_TxtUpdaterCommit"/>
+    <ROW Action="AI_TxtUpdaterConfig" Description="Executing text file updates" DescriptionLocId="ActionText.Description.AI_TxtUpdaterConfig" Template="Updating text file: &quot;[1]&quot;" TemplateLocId="ActionText.Template.AI_TxtUpdaterConfig"/>
+    <ROW Action="AI_TxtUpdaterInstall" Description="Generating actions to configure text files updates" DescriptionLocId="ActionText.Description.AI_TxtUpdaterInstall"/>
+    <ROW Action="AI_TxtUpdaterRollback" Description="Rolling back text file changes. " DescriptionLocId="ActionText.Description.AI_TxtUpdaterRollback" Template="Rolling back text file changes." TemplateLocId="ActionText.Template.AI_TxtUpdaterRollback"/>
+    <ROW Action="AI_XmlCommit" Description="Committing XML file configurations." DescriptionLocId="ActionText.Description.AI_XmlCommit" Template="Committing XML file configurations." TemplateLocId="ActionText.Template.AI_XmlCommit"/>
+    <ROW Action="AI_XmlConfig" Description="Executing XML file configurations" DescriptionLocId="ActionText.Description.AI_XmlConfig" Template="Configuring XML file: &quot;[1]&quot;" TemplateLocId="ActionText.Template.AI_XmlConfig"/>
+    <ROW Action="AI_XmlInstall" Description="Generating actions to configure XML files" DescriptionLocId="ActionText.Description.AI_XmlInstall"/>
+    <ROW Action="AI_XmlRemove" Description="Executing XML file configurations" DescriptionLocId="ActionText.Description.AI_XmlRemove" Template="Configuring XML file: &quot;[1]&quot;" TemplateLocId="ActionText.Template.AI_XmlRemove"/>
+    <ROW Action="AI_XmlRollback" Description="Rolling back XML file configurations." DescriptionLocId="ActionText.Description.AI_XmlRollback" Template="Rolling back XML file configurations." TemplateLocId="ActionText.Template.AI_XmlRollback"/>
+    <ROW Action="AI_XmlUninstall" Description="Generating actions to configure XML files" DescriptionLocId="ActionText.Description.AI_XmlUninstall"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiAppSearchComponent">
+    <ROW Property="AI_SETUPEXEPATH" Signature_="AI_EXE_PATH_CU" Builds="ExeBuild"/>
+    <ROW Property="AI_SETUPEXEPATH" Signature_="AI_EXE_PATH_LM" Builds="ExeBuild"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiBinaryComponent">
+    <ROW Name="ExternalUICleaner.dll" SourcePath="&lt;AI_CUSTACTS&gt;ExternalUICleaner.dll"/>
+    <ROW Name="NetFirewall.dll" SourcePath="&lt;AI_CUSTACTS&gt;NetFirewall.dll"/>
+    <ROW Name="Prereq.dll" SourcePath="&lt;AI_CUSTACTS&gt;Prereq.dll"/>
+    <ROW Name="SoftwareDetector.dll" SourcePath="&lt;AI_CUSTACTS&gt;SoftwareDetector.dll"/>
+    <ROW Name="TxtUpdater.dll" SourcePath="&lt;AI_CUSTACTS&gt;TxtUpdater.dll"/>
+    <ROW Name="aicustact.dll" SourcePath="&lt;AI_CUSTACTS&gt;aicustact.dll"/>
+    <ROW Name="chainersupport.dll" SourcePath="&lt;AI_CUSTACTS&gt;chainersupport.dll"/>
+    <ROW Name="lzmaextractor.dll" SourcePath="&lt;AI_CUSTACTS&gt;lzmaextractor.dll"/>
+    <ROW Name="msichainer.exe" SourcePath="&lt;AI_CUSTACTS&gt;msichainer.exe"/>
+    <ROW Name="viewer.exe" SourcePath="&lt;AI_CUSTACTS&gt;viewer.exe" DigSign="true"/>
+    <ROW Name="xmlCfg.dll" SourcePath="&lt;AI_CUSTACTS&gt;xmlCfg.dll"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiControlComponent">
+    <ROW Dialog_="ExitDialog" Control="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Attributes="0" Text="[ButtonText_Cancel]" Order="200" TextLocId="-" MsiKey="ExitDialog#Cancel" Options="1"/>
+    <ROW Dialog_="ExitDialog" Control="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Attributes="0" Text="[ButtonText_Back]" Order="400" TextLocId="-" MsiKey="ExitDialog#Back" Options="1"/>
+    <ROW Dialog_="ExitDialog" Control="ViewReadmeCheckBox" Type="CheckBox" X="135" Y="140" Width="10" Height="10" Attributes="2" Property="VIEWREADME" Order="500" MsiKey="ExitDialog#ViewReadmeCheckBox" Options="1"/>
+    <ROW Dialog_="ExitDialog" Control="Title" Type="Text" X="135" Y="20" Width="220" Height="60" Attributes="196611" Text="Completing the [ProductName] [Wizard]" TextStyle="VerdanaBold13" Order="600" TextLocId="Control.Text.ExitDialog#Title" MsiKey="ExitDialog#Title"/>
+    <ROW Dialog_="ExitDialog" Control="LaunchProdCheckBox" Type="CheckBox" X="135" Y="170" Width="10" Height="10" Attributes="2" Property="RUNAPPLICATION" Order="700" MsiKey="ExitDialog#LaunchProdCheckBox" Options="1"/>
+    <ROW Dialog_="ExitDialog" Control="Description" Type="Text" X="135" Y="86" Width="220" Height="20" Attributes="196611" Text="Click the &quot;Finish&quot; button to exit the [Wizard]." Order="800" TextLocId="Control.Text.ExitDialog#Description" MsiKey="ExitDialog#Description"/>
+    <ROW Dialog_="ExitDialog" Control="BottomLine" Type="Line" X="0" Y="234" Width="372" Height="0" Attributes="1" Order="900" MsiKey="ExitDialog#BottomLine"/>
+    <ROW Dialog_="WelcomeDlg" Control="WelcomeDlgDialogInitializer" Type="DialogInitializer" X="0" Y="0" Width="0" Height="0" Attributes="0" Order="-1" TextLocId="-" HelpLocId="-" ExtDataLocId="-"/>
+    <ROW Dialog_="Windows7Warning" Control="Next" Type="PushButton" X="236" Y="243" Width="56" Height="17" Attributes="3" Text="[ButtonText_Next]" Order="100" Options="1"/>
+    <ROW Dialog_="Windows7Warning" Control="Cancel" Type="PushButton" X="304" Y="243" Width="56" Height="17" Attributes="3" Text="[ButtonText_Cancel]" Order="200" Options="1"/>
+    <ROW Dialog_="Windows7Warning" Control="Back" Type="PushButton" X="180" Y="243" Width="56" Height="17" Attributes="3" Text="[ButtonText_Back]" Order="300" Options="1"/>
+    <ROW Dialog_="Windows7Warning" Control="BannerBitmap" Type="Bitmap" X="0" Y="0" Width="370" Height="44" Attributes="1048577" Text="[BannerBitmap]" Order="400"/>
+    <ROW Dialog_="Windows7Warning" Control="BannerLine" Type="Line" X="0" Y="44" Width="372" Height="0" Attributes="1" Order="500"/>
+    <ROW Dialog_="Windows7Warning" Control="BottomLine" Type="Line" X="5" Y="234" Width="368" Height="0" Attributes="1" Order="600"/>
+    <ROW Dialog_="Windows7Warning" Control="Logo" Type="Text" X="4" Y="228" Width="70" Height="12" Attributes="1" Text="Advanced Installer" Order="700"/>
+    <ROW Dialog_="Windows7Warning" Control="Title" Type="Text" X="15" Y="6" Width="200" Height="15" Attributes="196611" Text="Warning: Unsupported Windows Version" TextStyle="[DlgTitleFont]" Order="800"/>
+    <ROW Dialog_="Windows7Warning" Control="Text_1" Type="Text" X="15" Y="59" Width="344" Height="159" Attributes="65539" Property="TEXT_1_PROP" Text="ZeroTier does not officially support versions of Windows prior to Windows 10, and the ZeroTier graphical tray and control panel application does not run on EOL versions of Windows. You may still install ZeroTier and attempt to use it by opening an administrator-mode command prompt and controlling the service from the command line with &quot;zerotier-cli&quot;." TextStyle="VerdanaBold13" Order="900"/>
+    <ATTRIBUTE name="DeletedRows" value="ExitDialog#LaunchProdText@ExitDialog#ViewReadmeText"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiControlConditionComponent">
+    <ATTRIBUTE name="DeletedRows" value="ExitDialog#LaunchProdText#Hide#((NOT AI_INSTALL) AND (NOT AI_PATCH)) OR ((CTRLS &lt;&gt; 2) AND (CTRLS &lt;&gt; 3))@ExitDialog#ViewReadmeText#Hide#((NOT AI_INSTALL) AND (NOT AI_PATCH)) OR ((CTRLS &lt;&gt; 1) AND (CTRLS &lt;&gt; 3))"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiControlEventComponent">
+    <ROW Dialog_="WelcomeDlg" Control_="Next" Event="EndDialog" Argument="Return" Condition="AI_INSTALL" Ordering="3"/>
+    <ROW Dialog_="MaintenanceWelcomeDlg" Control_="Next" Event="NewDialog" Argument="MaintenanceTypeDlg" Condition="AI_MAINT" Ordering="99"/>
+    <ROW Dialog_="CustomizeDlg" Control_="Next" Event="NewDialog" Argument="VerifyReadyDlg" Condition="AI_MAINT" Ordering="101"/>
+    <ROW Dialog_="CustomizeDlg" Control_="Back" Event="NewDialog" Argument="MaintenanceTypeDlg" Condition="AI_MAINT" Ordering="1"/>
+    <ROW Dialog_="VerifyReadyDlg" Control_="Install" Event="EndDialog" Argument="Return" Condition="AI_MAINT" Ordering="198"/>
+    <ROW Dialog_="VerifyReadyDlg" Control_="Back" Event="NewDialog" Argument="CustomizeDlg" Condition="AI_MAINT" Ordering="202"/>
+    <ROW Dialog_="MaintenanceTypeDlg" Control_="ChangeButton" Event="NewDialog" Argument="CustomizeDlg" Condition="AI_MAINT" Ordering="501"/>
+    <ROW Dialog_="MaintenanceTypeDlg" Control_="Back" Event="NewDialog" Argument="MaintenanceWelcomeDlg" Condition="AI_MAINT" Ordering="1"/>
+    <ROW Dialog_="MaintenanceTypeDlg" Control_="RemoveButton" Event="NewDialog" Argument="VerifyRemoveDlg" Condition="AI_MAINT AND InstallMode=&quot;Remove&quot;" Ordering="601"/>
+    <ROW Dialog_="VerifyRemoveDlg" Control_="Back" Event="NewDialog" Argument="MaintenanceTypeDlg" Condition="AI_MAINT AND InstallMode=&quot;Remove&quot;" Ordering="1"/>
+    <ROW Dialog_="MaintenanceTypeDlg" Control_="RepairButton" Event="NewDialog" Argument="VerifyRepairDlg" Condition="AI_MAINT AND InstallMode=&quot;Repair&quot;" Ordering="601"/>
+    <ROW Dialog_="VerifyRepairDlg" Control_="Back" Event="NewDialog" Argument="MaintenanceTypeDlg" Condition="AI_MAINT AND InstallMode=&quot;Repair&quot;" Ordering="1"/>
+    <ROW Dialog_="VerifyRepairDlg" Control_="Repair" Event="EndDialog" Argument="Return" Condition="AI_MAINT AND InstallMode=&quot;Repair&quot;" Ordering="399" Options="1"/>
+    <ROW Dialog_="VerifyRemoveDlg" Control_="Remove" Event="EndDialog" Argument="Return" Condition="AI_MAINT AND InstallMode=&quot;Remove&quot;" Ordering="299" Options="1"/>
+    <ROW Dialog_="PatchWelcomeDlg" Control_="Next" Event="NewDialog" Argument="VerifyReadyDlg" Condition="AI_PATCH" Ordering="201"/>
+    <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_="ResumeDlg" Control_="Install" Event="EndDialog" Argument="Return" Condition="AI_RESUME" Ordering="299"/>
+    <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="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="SpawnDialog" Argument="OutOfDiskDlg" Condition="AI_INSTALL AND ( (OutOfDiskSpace = 1 AND OutOfNoRbDiskSpace = 1) OR (OutOfDiskSpace = 1 AND PROMPTROLLBACKCOST=&quot;F&quot;) )" Ordering="7" Options="2"/>
+    <ROW Dialog_="WelcomeDlg" Control_="WelcomeDlgDialogInitializer" Event="[AI_ButtonText_Next_Orig]" Argument="[ButtonText_Next]" Condition="AI_INSTALL" Ordering="0" Options="2"/>
+    <ROW Dialog_="WelcomeDlg" Control_="WelcomeDlgDialogInitializer" Event="[ButtonText_Next]" Argument="[[AI_CommitButton]]" Condition="AI_INSTALL" Ordering="1" Options="2"/>
+    <ROW Dialog_="WelcomeDlg" Control_="WelcomeDlgDialogInitializer" Event="[AI_Text_Next_Orig]" Argument="[Text_Next]" Condition="AI_INSTALL" Ordering="2" Options="2"/>
+    <ROW Dialog_="WelcomeDlg" Control_="WelcomeDlgDialogInitializer" Event="[Text_Next]" Argument="[Text_Install]" Condition="AI_INSTALL" Ordering="3" 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_="ExitDialog" Control_="Finish" Event="DoAction" Argument="AI_ChainerScheduleReboot" Condition="Not AIEXTERNALUI" Ordering="302"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiCreateFolderComponent">
+    <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_="APPDIR" Component_="APPDIR" ManualDelete="true"/>
+    <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 cid="caphyon.advinst.msicomp.MsiCustActComponent">
+    <ROW Action="AI_AppSearchEx" Type="1" Source="Prereq.dll" Target="DoAppSearchEx"/>
+    <ROW Action="AI_BACKUP_AI_SETUPEXEPATH" Type="51" Source="AI_SETUPEXEPATH_ORIGINAL" Target="[AI_SETUPEXEPATH]"/>
+    <ROW Action="AI_ChainerScheduleReboot" Type="1" Source="chainersupport.dll" Target="ScheduleReboot" WithoutSeq="true"/>
+    <ROW Action="AI_CommitChainers" Type="11841" Source="chainersupport.dll" Target="CommitChainedPackages" WithoutSeq="true"/>
+    <ROW Action="AI_DATA_SETTER" Type="51" Source="CustomActionData" Target="[~]"/>
+    <ROW Action="AI_DATA_SETTER_1" Type="51" Source="CustomActionData" Target="[~]"/>
+    <ROW Action="AI_DATA_SETTER_2" Type="51" Source="CustomActionData" Target="[~]"/>
+    <ROW Action="AI_DATA_SETTER_3" Type="51" Source="CustomActionData" Target="[~]"/>
+    <ROW Action="AI_DATA_SETTER_4" Type="51" Source="CustomActionData" Target="[AI_SETUPEXEPATH]"/>
+    <ROW Action="AI_DATA_SETTER_5" Type="51" Source="CustomActionData" Target="zerotier_desktop_ui.exe"/>
+    <ROW Action="AI_DATA_SETTER_6" Type="51" Source="CustomActionData" Target="ZeroTier One.exe"/>
+    <ROW Action="AI_DOWNGRADE" Type="19" Target="4010"/>
+    <ROW Action="AI_DeleteCadLzma" Type="51" Source="AI_DeleteLzma" Target="[AI_SETUPEXEPATH]"/>
+    <ROW Action="AI_DeleteLzma" Type="1025" Source="lzmaextractor.dll" Target="DeleteLZMAFiles"/>
+    <ROW Action="AI_DeleteRCadLzma" Type="51" Source="AI_DeleteRLzma" Target="[AI_SETUPEXEPATH]"/>
+    <ROW Action="AI_DeleteRLzma" Type="1281" Source="lzmaextractor.dll" Target="DeleteLZMAFiles"/>
+    <ROW Action="AI_DetectSoftware" Type="257" Source="SoftwareDetector.dll" Target="OnDetectSoftware"/>
+    <ROW Action="AI_DoRemoveExternalUIStub" Type="3585" Source="ExternalUICleaner.dll" Target="DoRemoveExternalUIStub" WithoutSeq="true"/>
+    <ROW Action="AI_DpiContentScale" Type="1" Source="aicustact.dll" Target="DpiContentScale"/>
+    <ROW Action="AI_EnableDebugLog" Type="321" Source="aicustact.dll" Target="EnableDebugLog"/>
+    <ROW Action="AI_ExtractCadLzma" Type="51" Source="AI_ExtractLzma" Target="[AI_SETUPEXEPATH]"/>
+    <ROW Action="AI_ExtractFiles" Type="1" Source="Prereq.dll" Target="ExtractSourceFiles" AdditionalSeq="AI_DATA_SETTER_4"/>
+    <ROW Action="AI_ExtractLzma" Type="1025" Source="lzmaextractor.dll" Target="ExtractLZMAFiles"/>
+    <ROW Action="AI_FindExeLzma" Type="1" Source="lzmaextractor.dll" Target="FindEXE"/>
+    <ROW Action="AI_FwConfig" Type="11265" Source="NetFirewall.dll" Target="OnFwConfig" WithoutSeq="true"/>
+    <ROW Action="AI_FwInstall" Type="1" Source="NetFirewall.dll" Target="OnFwInstall" AdditionalSeq="AI_DATA_SETTER_2"/>
+    <ROW Action="AI_FwRemove" Type="11265" Source="NetFirewall.dll" Target="OnFwRemove" WithoutSeq="true"/>
+    <ROW Action="AI_FwRollback" Type="11521" Source="NetFirewall.dll" Target="OnFwRollback" WithoutSeq="true"/>
+    <ROW Action="AI_FwUninstall" Type="1" Source="NetFirewall.dll" Target="OnFwUninstall" AdditionalSeq="AI_DATA_SETTER_3"/>
+    <ROW Action="AI_GetArpIconPath" Type="1" Source="aicustact.dll" Target="GetArpIconPath"/>
+    <ROW Action="AI_InstallModeCheck" Type="1" Source="aicustact.dll" Target="UpdateInstallMode" WithoutSeq="true"/>
+    <ROW Action="AI_PREPARE_UPGRADE" Type="65" Source="aicustact.dll" Target="PrepareUpgrade"/>
+    <ROW Action="AI_PRESERVE_INSTALL_TYPE" Type="65" Source="aicustact.dll" Target="PreserveInstallType"/>
+    <ROW Action="AI_PrepareChainers" Type="1" Source="chainersupport.dll" Target="PrepareChainedPackages"/>
+    <ROW Action="AI_RESTORE_AI_SETUPEXEPATH" Type="51" Source="AI_SETUPEXEPATH" Target="[AI_SETUPEXEPATH_ORIGINAL]"/>
+    <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_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_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_TxtUpdaterCommit" Type="11777" Source="TxtUpdater.dll" Target="OnTxtUpdaterCommit" WithoutSeq="true"/>
+    <ROW Action="AI_TxtUpdaterConfig" Type="11265" Source="TxtUpdater.dll" Target="OnTxtUpdaterConfig" WithoutSeq="true"/>
+    <ROW Action="AI_TxtUpdaterInstall" Type="1" Source="TxtUpdater.dll" Target="OnTxtUpdaterInstall"/>
+    <ROW Action="AI_TxtUpdaterRollback" Type="11521" Source="TxtUpdater.dll" Target="OnTxtUpdaterRollback" WithoutSeq="true"/>
+    <ROW Action="AI_XmlCommit" Type="11777" Source="xmlCfg.dll" Target="OnXmlCommit" WithoutSeq="true"/>
+    <ROW Action="AI_XmlConfig" Type="11265" Source="xmlCfg.dll" Target="OnXmlConfig" WithoutSeq="true"/>
+    <ROW Action="AI_XmlInstall" Type="1" Source="xmlCfg.dll" Target="OnXmlInstall" AdditionalSeq="AI_DATA_SETTER"/>
+    <ROW Action="AI_XmlRemove" Type="11265" Source="xmlCfg.dll" Target="OnXmlRemove" WithoutSeq="true"/>
+    <ROW Action="AI_XmlRollback" Type="11521" Source="xmlCfg.dll" Target="OnXmlRollback" WithoutSeq="true"/>
+    <ROW Action="AI_XmlUninstall" Type="1" Source="xmlCfg.dll" Target="OnXmlUninstall" AdditionalSeq="AI_DATA_SETTER_1"/>
+    <ROW Action="LaunchUI" Type="194" Source="viewer.exe" Target="/DontWait &quot;[APPDIR]zerotier_desktop_ui.exe&quot;" Options="1"/>
+    <ROW Action="SET_APPDIR" Type="307" Source="APPDIR" Target="[ProgramFilesFolder][Manufacturer]\[ProductName]" MultiBuildTarget="DefaultBuild:[ProgramFilesFolder]ZeroTier\One"/>
+    <ROW Action="SET_SHORTCUTDIR" Type="307" Source="SHORTCUTDIR" Target="[ProgramMenuFolder][ProductName]"/>
+    <ROW Action="SET_TARGETDIR_TO_APPDIR" Type="51" Source="TARGETDIR" Target="[APPDIR]"/>
+    <ROW Action="TapDeviceRemove32" Type="3154" Source="zerotierone_x86.exe" Target="-D"/>
+    <ROW Action="TapDeviceRemove64" Type="3154" Source="zerotierone_x64.exe" Target="-D"/>
+    <ROW Action="TerminateUINew" Type="65" Source="aicustact.dll" Target="StopProcess" Options="1" AdditionalSeq="AI_DATA_SETTER_5"/>
+    <ROW Action="TerminateUIOld" Type="65" Source="aicustact.dll" Target="StopProcess" Options="1" AdditionalSeq="AI_DATA_SETTER_6"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiDialogComponent">
+    <ROW Dialog="Windows7Warning" HCentering="50" VCentering="50" Width="370" Height="270" Attributes="3" Title="[ProductName] [Setup]" Control_Default="Next" Control_Cancel="Cancel"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiEmbeddedChainerComponent">
+    <ROW MsiEmbeddedChainer="msichainer.exe" Condition="VersionMsi &gt;= &quot;4.05&quot;" CommandLine="[AI_CHAINER_CMD_LINE]" Source="msichainer.exe" Type="2"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiEnvComponent">
+    <ROW Environment="Path" Name="=-*Path" Value="[~];[APPDIR]" Component_="regid.201001.com.zerotier"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiFeatCompsComponent">
+    <ROW Feature_="ZeroTierOne" Component_="ProductInformation"/>
+    <ROW Feature_="ZeroTierOne" Component_="networks.d"/>
+    <ROW Feature_="ZeroTierOne" Component_="regid.201001.com.zerotier"/>
+    <ROW Feature_="ZeroTierOne" Component_="zerotierone_x64.exe"/>
+    <ROW Feature_="ZeroTierOne" Component_="zerotierone_x86.exe"/>
+    <ROW Feature_="ZeroTierOne" Component_="zttap300_x86_win10"/>
+    <ROW Feature_="MainFeature" Component_="APPDIR"/>
+    <ROW Feature_="ZeroTierOne" Component_="zttap300_x64_win10"/>
+    <ROW Feature_="ZeroTierOne" Component_="AI_CustomARPName"/>
+    <ROW Feature_="ZeroTierOne" Component_="AI_DisableModify"/>
+    <ROW Feature_="ZeroTierOne" Component_="zerotier_desktop_ui.exe"/>
+    <ROW Feature_="ZeroTierOne" Component_="zerotier_desktop_ui.exe_1"/>
+    <ROW Feature_="ZeroTierOne" Component_="AI_ExePath"/>
+    <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"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiIconsComponent">
+    <ROW Name="ZeroTierIcon.exe" SourcePath="..\..\..\artwork\ZeroTierIcon.ico" Index="0"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiInstExSeqComponent">
+    <ROW Action="AI_DOWNGRADE" Condition="AI_NEWERPRODUCTFOUND AND (UILevel &lt;&gt; 5)" Sequence="210"/>
+    <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_PREPARE_UPGRADE" Condition="AI_UPGRADE=&quot;No&quot; AND (Not Installed)" Sequence="1397"/>
+    <ROW Action="AI_ResolveKnownFolders" Sequence="53"/>
+    <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_XmlUninstall" Condition="(REMOVE)" Sequence="3102"/>
+    <ROW Action="AI_DATA_SETTER_1" Condition="(REMOVE)" Sequence="3101"/>
+    <ROW Action="InstallFinalize" Sequence="6605" 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="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="AI_FwInstall" Condition="(VersionNT &gt;= 501) AND (REMOVE &lt;&gt; &quot;ALL&quot;)" Sequence="5802"/>
+    <ROW Action="AI_DATA_SETTER_2" Condition="(VersionNT &gt;= 501) AND (REMOVE &lt;&gt; &quot;ALL&quot;)" Sequence="5801"/>
+    <ROW Action="AI_FwUninstall" Condition="(VersionNT &gt;= 501) AND (REMOVE=&quot;ALL&quot;)" Sequence="1702"/>
+    <ROW Action="AI_DATA_SETTER_3" Condition="(VersionNT &gt;= 501) AND (REMOVE=&quot;ALL&quot;)" Sequence="1701"/>
+    <ROW Action="AI_DetectSoftware" Sequence="103"/>
+    <ROW Action="AI_TxtUpdaterInstall" Sequence="5101"/>
+    <ROW Action="AI_BACKUP_AI_SETUPEXEPATH" Sequence="99" Builds="ExeBuild"/>
+    <ROW Action="AI_RESTORE_AI_SETUPEXEPATH" Condition="AI_SETUPEXEPATH_ORIGINAL" Sequence="102" Builds="ExeBuild"/>
+    <ROW Action="AI_DeleteCadLzma" 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="199" Builds="ExeBuild"/>
+    <ROW Action="AI_DeleteRCadLzma" 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="198" Builds="ExeBuild"/>
+    <ROW Action="AI_ExtractCadLzma" 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="197" Builds="ExeBuild"/>
+    <ROW Action="AI_FindExeLzma" 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="196" Builds="ExeBuild"/>
+    <ROW Action="AI_ExtractLzma" 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="1549" Builds="ExeBuild"/>
+    <ROW Action="AI_DeleteRLzma" 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="1548" 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="AI_DATA_SETTER_6" Sequence="1601"/>
+    <ROW Action="AI_EnableDebugLog" Sequence="52"/>
+    <ROW Action="AI_AppSearchEx" Sequence="101"/>
+    <ROW Action="AI_PrepareChainers" Condition="VersionMsi &gt;= &quot;4.05&quot;" Sequence="5851"/>
+    <ROW Action="AI_ExtractFiles" Sequence="1399" Builds="ExeBuild"/>
+    <ROW Action="AI_DATA_SETTER_4" Sequence="1398"/>
+    <ROW Action="AI_GetArpIconPath" Sequence="1401"/>
+    <ROW Action="TerminateUINew" Sequence="1604"/>
+    <ROW Action="AI_DATA_SETTER_5" Sequence="1603"/>
+    <ROW Action="LaunchUI" Condition="( NOT Installed ) AND ( ZTHEADLESS = &quot;No&quot; )" Sequence="6606"/>
+    <ROW Action="AI_DETECT_MODERNWIN" Condition="(VersionNT &gt;= 603)" Sequence="55" MsiKey="AI_DETECT_MODERNWIN"/>
+    <ROW Action="AI_ResolveLocalizedCredentials" Sequence="51"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiInstallUISequenceComponent">
+    <ROW Action="AI_RESTORE_LOCATION" Condition="APPDIR=&quot;&quot;" Sequence="749"/>
+    <ROW Action="AI_ResolveKnownFolders" Sequence="54"/>
+    <ROW Action="AI_DpiContentScale" Sequence="53"/>
+    <ROW Action="AI_BACKUP_AI_SETUPEXEPATH" Sequence="99"/>
+    <ROW Action="AI_RESTORE_AI_SETUPEXEPATH" Condition="AI_SETUPEXEPATH_ORIGINAL" Sequence="103"/>
+    <ROW Action="ExecuteAction" Sequence="1299" SeqType="0" MsiKey="ExecuteAction"/>
+    <ROW Action="AI_DetectSoftware" Sequence="102"/>
+    <ROW Action="AI_EnableDebugLog" Sequence="52"/>
+    <ROW Action="AI_AppSearchEx" Sequence="101"/>
+    <ROW Action="AI_ResolveLocalizedCredentials" Sequence="51"/>
+    <ROW Action="AI_PRESERVE_INSTALL_TYPE" Sequence="199"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiLaunchConditionsComponent">
+    <ROW Condition="( Version9X OR ( NOT VersionNT64 ) OR ( VersionNT64 AND ((VersionNT64 &lt;&gt; 600) OR (MsiNTProductType &lt;&gt; 1)) AND ((VersionNT64 &lt;&gt; 600) OR (MsiNTProductType = 1)) AND ((VersionNT64 &lt;&gt; 601) OR (MsiNTProductType &lt;&gt; 1)) AND ((VersionNT64 &lt;&gt; 601) OR (MsiNTProductType = 1)) ) )" Description="[ProductName] cannot be installed on the following Windows versions: [WindowsTypeNT64Display]." DescriptionLocId="AI.LaunchCondition.NoSpecificNT64" IsPredefined="true" Builds="DefaultBuild"/>
+    <ROW Condition="( Version9X OR VersionNT64 OR ( VersionNT AND ((VersionNT &lt;&gt; 600) OR (MsiNTProductType &lt;&gt; 1)) AND ((VersionNT &lt;&gt; 600) OR (MsiNTProductType = 1)) AND (VersionNT &lt;&gt; 601) ) )" Description="[ProductName] cannot be installed on the following Windows versions: [WindowsTypeNTDisplay]." DescriptionLocId="AI.LaunchCondition.NoSpecificNT" IsPredefined="true" Builds="DefaultBuild"/>
+    <ROW Condition="((VersionNT &lt;&gt; 501) AND (VersionNT &lt;&gt; 502))" Description="[ProductName] cannot be installed on [WindowsTypeNT5XDisplay]." DescriptionLocId="AI.LaunchCondition.NoNT5X" IsPredefined="true" Builds="DefaultBuild;ExeBuild"/>
+    <ROW Condition="(VersionNT &lt;&gt; 400)" Description="[ProductName] cannot be installed on [WindowsTypeNT40Display]." DescriptionLocId="AI.LaunchCondition.NoNT40" IsPredefined="true" Builds="DefaultBuild;ExeBuild"/>
+    <ROW Condition="(VersionNT &lt;&gt; 500)" Description="[ProductName] cannot be installed on [WindowsTypeNT50Display]." DescriptionLocId="AI.LaunchCondition.NoNT50" IsPredefined="true" Builds="DefaultBuild;ExeBuild"/>
+    <ROW Condition="AI_DETECTED_DOTNET_VERSION &gt;= AI_REQUIRED_DOTNET_VERSION" Description="[ProductName] cannot be installed on systems with .NET Framework version lower than [AI_REQUIRED_DOTNET_DISPLAY]." DescriptionLocId="AI.LaunchCondition.DotNET" IsPredefined="true" Builds="DefaultBuild"/>
+    <ROW Condition="NOT AiArm64" Description="[ProductName] cannot be installed on systems running on ARM64 processors. Check for a ARM64 version of [ProductName]" DescriptionLocId="AI.LaunchCondition.ARM64" IsPredefined="true" Builds="DefaultBuild"/>
+    <ROW Condition="Privileged" Description="[ProductName] requires administrative privileges to install." DescriptionLocId="AI.LaunchCondition.Privileged" IsPredefined="true" Builds="DefaultBuild"/>
+    <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"/>
+  </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">
+    <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"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiRegsComponent">
+    <ROW Registry="AI_ExePath" Root="-1" Key="Software\Caphyon\Advanced Installer\LZMA\[ProductCode]\[ProductVersion]" Name="AI_ExePath" Value="[AI_SETUPEXEPATH]" Component_="AI_ExePath"/>
+    <ROW Registry="AdvancedInstaller" Root="-1" Key="Software\Caphyon\Advanced Installer" Name="\"/>
+    <ROW Registry="Caphyon" Root="-1" Key="Software\Caphyon" Name="\"/>
+    <ROW Registry="Comments" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="Comments" Value="[ARPCOMMENTS]" Component_="AI_CustomARPName"/>
+    <ROW Registry="Contact" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="Contact" Value="[ARPCONTACT]" Component_="AI_CustomARPName"/>
+    <ROW Registry="CurrentVersion" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion" Name="\"/>
+    <ROW Registry="DisplayIcon" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="DisplayIcon" Value="[ARP_ICON_PATH]" Component_="AI_CustomARPName"/>
+    <ROW Registry="DisplayName" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="DisplayName" Value="[AI_PRODUCTNAME_ARP]" Component_="AI_CustomARPName"/>
+    <ROW Registry="DisplayVersion" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="DisplayVersion" Value="[ProductVersion]" Component_="AI_CustomARPName"/>
+    <ROW Registry="EstimatedSize" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="EstimatedSize" Value="#[AI_ARP_SIZE]" Component_="AI_CustomARPName" VirtualValue="#"/>
+    <ROW Registry="HelpLink" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="HelpLink" Value="[ARPHELPLINK]" Component_="AI_CustomARPName"/>
+    <ROW Registry="HelpTelephone" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="HelpTelephone" Value="[ARPHELPTELEPHONE]" Component_="AI_CustomARPName"/>
+    <ROW Registry="InstallLocation" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="InstallLocation" Value="[APPDIR]" Component_="AI_CustomARPName"/>
+    <ROW Registry="LZMA" Root="-1" Key="Software\Caphyon\Advanced Installer\LZMA" Name="\"/>
+    <ROW Registry="Manufacturer" Root="-1" Key="Software\[Manufacturer]" Name="\"/>
+    <ROW Registry="Microsoft" Root="-1" Key="Software\Microsoft" Name="\"/>
+    <ROW Registry="ModifyPath" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="ModifyPath" Value="[AI_UNINSTALLER] /i [ProductCode] AI_UNINSTALLER_CTP=1" Component_="AI_CustomARPName"/>
+    <ROW Registry="NoModify" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="NoModify" Value="#1" Component_="AI_DisableModify" VirtualValue="#"/>
+    <ROW Registry="NoRepair" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="NoRepair" Value="#1" Component_="AI_CustomARPName" VirtualValue="#"/>
+    <ROW Registry="Path" Root="-1" Key="Software\[Manufacturer]\[ProductName]" Name="Path" Value="[APPDIR]" Component_="ProductInformation"/>
+    <ROW Registry="ProductCode_1" Root="-1" Key="Software\Caphyon\Advanced Installer\LZMA\[ProductCode]" Name="\"/>
+    <ROW Registry="ProductName" Root="-1" Key="Software\[Manufacturer]\[ProductName]" Name="\"/>
+    <ROW Registry="ProductNameProductVersion" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [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="Readme" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="Readme" Value="[ARPREADME]" Component_="AI_CustomARPName"/>
+    <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="URLUpdateInfo" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="URLUpdateInfo" Value="[ARPURLUPDATEINFO]" Component_="AI_CustomARPName"/>
+    <ROW Registry="Uninstall" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall" Name="\"/>
+    <ROW Registry="UninstallPath" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="UninstallPath" Value="[AI_UNINSTALLER] /x [ProductCode] AI_UNINSTALLER_CTP=1" Component_="AI_CustomARPName"/>
+    <ROW Registry="UninstallString" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="UninstallString" Value="[AI_UNINSTALLER] /x [ProductCode] AI_UNINSTALLER_CTP=1" Component_="AI_CustomARPName"/>
+    <ROW Registry="Version" Root="-1" Key="Software\[Manufacturer]\[ProductName]" Name="Version" Value="[ProductVersion]" Component_="ProductInformation"/>
+    <ROW Registry="VersionMajor" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="VersionMajor" Value="#1" Component_="AI_CustomARPName" VirtualValue="#"/>
+    <ROW Registry="VersionMinor" Root="-1" Key="Software\Microsoft\Windows\CurrentVersion\Uninstall\[ProductName] [ProductVersion]" Name="VersionMinor" Value="#6" Component_="AI_CustomARPName" VirtualValue="#"/>
+    <ROW Registry="Windows" Root="-1" Key="Software\Microsoft\Windows" Name="\"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiServCtrlComponent">
+    <ROW ServiceControl="zerotierone_x64.exe" Name="ZeroTierOneService" Event="163" Wait="1" Component_="zerotierone_x64.exe"/>
+    <ROW ServiceControl="zerotierone_x86.exe" Name="ZeroTierOneService" Event="163" Wait="1" Component_="zerotierone_x86.exe"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiServInstComponent">
+    <ROW ServiceInstall="zerotierone_x64.exe" Name="ZeroTierOneService" DisplayName="ZeroTier One" ServiceType="16" StartType="2" ErrorControl="32769" Component_="zerotierone_x64.exe" Description="Ethernet Virtualization Service"/>
+    <ROW ServiceInstall="zerotierone_x86.exe" Name="ZeroTierOneService" DisplayName="ZeroTier One" ServiceType="16" StartType="2" ErrorControl="32769" Component_="zerotierone_x86.exe" Description="Ethernet Virtualization Service"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiShortsComponent">
+    <ROW Shortcut="ZeroTier" Directory_="ProgramMenuFolder" Name="ZeroTier" Component_="zerotier_desktop_ui.exe" Target="[#zerotier_desktop_ui.exe]" Hotkey="0" Icon_="ZeroTierIcon.exe" IconIndex="0" ShowCmd="1" WkDir="APPDIR"/>
+    <ROW Shortcut="ZeroTier_1" Directory_="i686_1_Dir" Name="ZeroTier" Component_="zerotier_desktop_ui.exe_1" Target="[#zerotier_desktop_ui.exe_1]" Hotkey="0" Icon_="ZeroTierIcon.exe" IconIndex="0" ShowCmd="1" WkDir="i686_Dir"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiThemeComponent">
+    <ATTRIBUTE name="UsedTheme" value="classic"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.MsiUpgradeComponent">
+    <ROW UpgradeCode="[|UpgradeCode]" VersionMin="0.0.1" VersionMax="[|ProductVersion]" Attributes="257" ActionProperty="OLDPRODUCTS"/>
+    <ROW UpgradeCode="[|UpgradeCode]" VersionMin="[|ProductVersion]" Attributes="2" ActionProperty="AI_NEWERPRODUCTFOUND"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.PreReqSearchComponent">
+    <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"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.SoftwareIdentificationComponent">
+    <ATTRIBUTE name="LocalFile" value="regid.199509.com.example_ProductName.swidtag"/>
+    <ATTRIBUTE name="SystemFile" value="regid.199509.com.example_ProductName.swidtag_1"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.TxtUpdateComponent">
+    <ROW Name="Append/Create" TxtUpdateSet="zerotiercli.bat" FindPattern="@ECHO OFF&#13;&#10;if [\[][#zerotierone_x64.exe][\]] == [\[][\]] (&#13;&#10;&#9;[#zerotierone_x86.exe] -q %*&#13;&#10;) else (&#13;&#10;&#9;[#zerotierone_x64.exe] -q %*&#13;&#10;)&#13;&#10;" Options="160" Order="0" FileEncoding="0"/>
+    <ROW Name="Replace" TxtUpdateSet="zerotiercli.bat" FindPattern="YourFindText" ReplacePattern="YourReplaceText" Options="2" Order="1" FileEncoding="-1"/>
+    <ROW Name="Append/Create" TxtUpdateSet="zerotiercli1.bat" FindPattern="@ECHO OFF&#13;&#10;if [\[][#zerotierone_x64.exe][\]] == [\[][\]] (&#13;&#10;&#9;[#zerotierone_x86.exe] -i %*&#13;&#10;) else (&#13;&#10;&#9;[#zerotierone_x64.exe] -i %*&#13;&#10;)&#13;&#10;" Options="160" Order="0" FileEncoding="0"/>
+    <ROW Name="Replace" TxtUpdateSet="zerotiercli1.bat" FindPattern="YourFindText" ReplacePattern="YourReplaceText" Options="2" Order="1" FileEncoding="-1"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.TxtUpdateSetComponent">
+    <ROW Key="zerotiercli.bat" Component="regid.201001.com.zerotier" FileName="zerotier-cli.bat" Directory="APPDIR" Options="17"/>
+    <ROW Key="zerotiercli1.bat" Component="regid.201001.com.zerotier" FileName="zerotier-idtool.bat" Directory="APPDIR" Options="17"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.XmlAttributeComponent">
+    <ROW XmlAttribute="xmlnsds" XmlElement="swidsoftware_identification_tag" Name="xmlns:ds" Flags="14" Order="0" Value="http://www.w3.org/2000/09/xmldsig#"/>
+    <ROW XmlAttribute="xmlnsswid" XmlElement="swidsoftware_identification_tag" Name="xmlns:swid" Flags="14" Order="1" Value="http://standards.iso.org/iso/19770/-2/2008/schema.xsd"/>
+    <ROW XmlAttribute="xmlnsxsi" XmlElement="swidsoftware_identification_tag" Name="xmlns:xsi" Flags="14" Order="2" Value="http://www.w3.org/2001/XMLSchema-instance"/>
+    <ROW XmlAttribute="xsischemaLocation" XmlElement="swidsoftware_identification_tag" Name="xsi:schemaLocation" Flags="14" Order="3" Value="http://standards.iso.org/iso/19770/-2/2008/schema.xsd software_identification_tag.xsd"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.XmlElementComponent">
+    <ROW XmlElement="swidbuild" ParentElement="swidnumeric" Name="swid:build" Condition="1" Order="2" Flags="14" Text="6" 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="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_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_3" ParentElement="swidtag_creator" Name="swid:name" Condition="1" Order="0" Flags="14" Text="ZeroTier, Inc." UpdateIndexInParent="0"/>
+    <ROW XmlElement="swidnumeric" ParentElement="swidproduct_version" Name="swid:numeric" Condition="1" Order="1" Flags="14" UpdateIndexInParent="0"/>
+    <ROW XmlElement="swidproduct_title" ParentElement="swidsoftware_identification_tag" Name="swid:product_title" Condition="1" Order="1" Flags="14" Text="[ProductName]" UpdateIndexInParent="0"/>
+    <ROW XmlElement="swidproduct_version" ParentElement="swidsoftware_identification_tag" Name="swid:product_version" Condition="1" Order="2" Flags="14" UpdateIndexInParent="0"/>
+    <ROW XmlElement="swidregid" ParentElement="swidsoftware_creator" Name="swid:regid" Condition="1" Order="1" Flags="14" Text="regid.2010-01.com.zerotier" UpdateIndexInParent="0"/>
+    <ROW XmlElement="swidregid_1" ParentElement="swidsoftware_licensor" Name="swid:regid" Condition="1" Order="1" Flags="14" Text="regid.2010-01.com.zerotier" UpdateIndexInParent="0"/>
+    <ROW XmlElement="swidregid_2" ParentElement="swidtag_creator" Name="swid:regid" Condition="1" Order="1" Flags="14" Text="regid.2010-01.com.zerotier" UpdateIndexInParent="0"/>
+    <ROW XmlElement="swidreview" ParentElement="swidnumeric" Name="swid:review" Condition="1" Order="3" Flags="14" Text="0" UpdateIndexInParent="0"/>
+    <ROW XmlElement="swidsoftware_creator" ParentElement="swidsoftware_identification_tag" Name="swid:software_creator" Condition="1" Order="3" Flags="14" UpdateIndexInParent="0"/>
+    <ROW XmlElement="swidsoftware_id" ParentElement="swidsoftware_identification_tag" Name="swid:software_id" Condition="1" Order="5" Flags="14" UpdateIndexInParent="0"/>
+    <ROW XmlElement="swidsoftware_identification_tag" Name="swid:software_identification_tag" Condition="1" Order="0" Flags="14" UpdateIndexInParent="0"/>
+    <ROW XmlElement="swidsoftware_licensor" ParentElement="swidsoftware_identification_tag" Name="swid:software_licensor" Condition="1" Order="4" Flags="14" UpdateIndexInParent="0"/>
+    <ROW XmlElement="swidtag_creator" ParentElement="swidsoftware_identification_tag" Name="swid:tag_creator" Condition="1" Order="6" Flags="14" UpdateIndexInParent="0"/>
+    <ROW XmlElement="swidtag_creator_regid" ParentElement="swidsoftware_id" Name="swid:tag_creator_regid" Condition="1" Order="1" Flags="14" Text="regid.2010-01.com.zerotier" UpdateIndexInParent="0"/>
+    <ROW XmlElement="swidunique_id" ParentElement="swidsoftware_id" Name="swid:unique_id" Condition="1" Order="0" Flags="14" Text="ZeroTierOne" UpdateIndexInParent="0"/>
+  </COMPONENT>
+  <COMPONENT cid="caphyon.advinst.msicomp.XmlFileComponent">
+    <ROW XmlFile="regid.199509.com.example_ProductName.swidtag" FileName="REGID2~1.SWI|regid.2010-01.com.zerotier_ZeroTierOne.swidtag" DirProperty="APPDIR" Component="ProductInformation" RootElement="swidsoftware_identification_tag" Flags="25" Version="1.0" Encoding="UTF-8" IndentUnits="2"/>
+    <ROW XmlFile="regid.199509.com.example_ProductName.swidtag_1" FileName="REGID2~1.SWI|regid.2010-01.com.zerotier_ZeroTierOne.swidtag" DirProperty="regid.201001.com.zerotier_Dir" Component="ProductInformation" RootElement="swidsoftware_identification_tag" Flags="25" Version="1.0" Encoding="UTF-8" IndentUnits="2"/>
+  </COMPONENT>
+</DOCUMENT>

+ 329 - 369
ext/libpqxx-7.7.3/config/config.guess

@@ -1,14 +1,12 @@
 #! /bin/sh
 #! /bin/sh
 # Attempt to guess a canonical system name.
 # Attempt to guess a canonical system name.
-#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
-#   Free Software Foundation, Inc.
+#   Copyright 1992-2016 Free Software Foundation, Inc.
 
 
-timestamp='2009-12-30'
+timestamp='2016-10-02'
 
 
 # This file is free software; you can redistribute it and/or modify it
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
 # under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
+# the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 # (at your option) any later version.
 #
 #
 # This program is distributed in the hope that it will be useful, but
 # This program is distributed in the hope that it will be useful, but
@@ -17,26 +15,22 @@ timestamp='2009-12-30'
 # General Public License for more details.
 # General Public License for more details.
 #
 #
 # You should have received a copy of the GNU General Public License
 # You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-# 02110-1301, USA.
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
 #
 #
 # As a special exception to the GNU General Public License, if you
 # As a special exception to the GNU General Public License, if you
 # distribute this file as part of a program that contains a
 # distribute this file as part of a program that contains a
 # configuration script generated by Autoconf, you may include it under
 # configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-
-# Originally written by Per Bothner.  Please send patches (context
-# diff format) to <[email protected]> and include a ChangeLog
-# entry.
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
 #
 #
-# This script attempts to guess a canonical system name similar to
-# config.sub.  If it succeeds, it prints the system name on stdout, and
-# exits with 0.  Otherwise, it exits with 1.
+# Originally written by Per Bothner; maintained since 2000 by Ben Elliston.
 #
 #
 # You can get the latest version of this script from:
 # You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
+#
+# Please send patches to <[email protected]>.
+
 
 
 me=`echo "$0" | sed -e 's,.*/,,'`
 me=`echo "$0" | sed -e 's,.*/,,'`
 
 
@@ -56,9 +50,7 @@ version="\
 GNU config.guess ($timestamp)
 GNU config.guess ($timestamp)
 
 
 Originally written by Per Bothner.
 Originally written by Per Bothner.
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
-Software Foundation, Inc.
+Copyright 1992-2016 Free Software Foundation, Inc.
 
 
 This is free software; see the source for copying conditions.  There is NO
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -140,12 +132,33 @@ UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
 UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
 UNAME_SYSTEM=`(uname -s) 2>/dev/null`  || UNAME_SYSTEM=unknown
 UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
 UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
 
 
+case "${UNAME_SYSTEM}" in
+Linux|GNU|GNU/*)
+	# If the system lacks a compiler, then just pick glibc.
+	# We could probably try harder.
+	LIBC=gnu
+
+	eval $set_cc_for_build
+	cat <<-EOF > $dummy.c
+	#include <features.h>
+	#if defined(__UCLIBC__)
+	LIBC=uclibc
+	#elif defined(__dietlibc__)
+	LIBC=dietlibc
+	#else
+	LIBC=gnu
+	#endif
+	EOF
+	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+	;;
+esac
+
 # Note: order is significant - the case branches are not exclusive.
 # Note: order is significant - the case branches are not exclusive.
 
 
 case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
 case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
     *:NetBSD:*:*)
     *:NetBSD:*:*)
 	# NetBSD (nbsd) targets should (where applicable) match one or
 	# NetBSD (nbsd) targets should (where applicable) match one or
-	# more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*,
+	# more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
 	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
 	# *-*-netbsdecoff* and *-*-netbsd*.  For targets that recently
 	# switched to ELF, *-*-netbsd* would select the old
 	# switched to ELF, *-*-netbsd* would select the old
 	# object file format.  This provides both forward
 	# object file format.  This provides both forward
@@ -155,19 +168,29 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
 	# Note: NetBSD doesn't particularly care about the vendor
 	# Note: NetBSD doesn't particularly care about the vendor
 	# portion of the name.  We always set it to "unknown".
 	# portion of the name.  We always set it to "unknown".
 	sysctl="sysctl -n hw.machine_arch"
 	sysctl="sysctl -n hw.machine_arch"
-	UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
-	    /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+	UNAME_MACHINE_ARCH=`(uname -p 2>/dev/null || \
+	    /sbin/$sysctl 2>/dev/null || \
+	    /usr/sbin/$sysctl 2>/dev/null || \
+	    echo unknown)`
 	case "${UNAME_MACHINE_ARCH}" in
 	case "${UNAME_MACHINE_ARCH}" in
 	    armeb) machine=armeb-unknown ;;
 	    armeb) machine=armeb-unknown ;;
 	    arm*) machine=arm-unknown ;;
 	    arm*) machine=arm-unknown ;;
 	    sh3el) machine=shl-unknown ;;
 	    sh3el) machine=shl-unknown ;;
 	    sh3eb) machine=sh-unknown ;;
 	    sh3eb) machine=sh-unknown ;;
 	    sh5el) machine=sh5le-unknown ;;
 	    sh5el) machine=sh5le-unknown ;;
+	    earmv*)
+		arch=`echo ${UNAME_MACHINE_ARCH} | sed -e 's,^e\(armv[0-9]\).*$,\1,'`
+		endian=`echo ${UNAME_MACHINE_ARCH} | sed -ne 's,^.*\(eb\)$,\1,p'`
+		machine=${arch}${endian}-unknown
+		;;
 	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
 	    *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
 	esac
 	esac
 	# The Operating System including object format, if it has switched
 	# The Operating System including object format, if it has switched
-	# to ELF recently, or will in the future.
+	# to ELF recently (or will in the future) and ABI.
 	case "${UNAME_MACHINE_ARCH}" in
 	case "${UNAME_MACHINE_ARCH}" in
+	    earm*)
+		os=netbsdelf
+		;;
 	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
 	    arm*|i386|m68k|ns32k|sh3*|sparc|vax)
 		eval $set_cc_for_build
 		eval $set_cc_for_build
 		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
 		if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
@@ -181,7 +204,14 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
 		fi
 		fi
 		;;
 		;;
 	    *)
 	    *)
-	        os=netbsd
+		os=netbsd
+		;;
+	esac
+	# Determine ABI tags.
+	case "${UNAME_MACHINE_ARCH}" in
+	    earm*)
+		expr='s/^earmv[0-9]/-eabi/;s/eb$//'
+		abi=`echo ${UNAME_MACHINE_ARCH} | sed -e "$expr"`
 		;;
 		;;
 	esac
 	esac
 	# The OS release
 	# The OS release
@@ -194,18 +224,26 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
 		release='-gnu'
 		release='-gnu'
 		;;
 		;;
 	    *)
 	    *)
-		release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+		release=`echo ${UNAME_RELEASE} | sed -e 's/[-_].*//' | cut -d. -f1,2`
 		;;
 		;;
 	esac
 	esac
 	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
 	# Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
 	# contains redundant information, the shorter form:
 	# contains redundant information, the shorter form:
 	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
 	# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
-	echo "${machine}-${os}${release}"
+	echo "${machine}-${os}${release}${abi}"
+	exit ;;
+    *:Bitrig:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
 	exit ;;
 	exit ;;
     *:OpenBSD:*:*)
     *:OpenBSD:*:*)
 	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
 	UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
 	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
 	echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
 	exit ;;
 	exit ;;
+    *:LibertyBSD:*:*)
+	UNAME_MACHINE_ARCH=`arch | sed 's/^.*BSD\.//'`
+	echo ${UNAME_MACHINE_ARCH}-unknown-libertybsd${UNAME_RELEASE}
+	exit ;;
     *:ekkoBSD:*:*)
     *:ekkoBSD:*:*)
 	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
 	echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
 	exit ;;
 	exit ;;
@@ -218,13 +256,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
     *:MirBSD:*:*)
     *:MirBSD:*:*)
 	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
 	echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
 	exit ;;
 	exit ;;
+    *:Sortix:*:*)
+	echo ${UNAME_MACHINE}-unknown-sortix
+	exit ;;
     alpha:OSF1:*:*)
     alpha:OSF1:*:*)
 	case $UNAME_RELEASE in
 	case $UNAME_RELEASE in
 	*4.0)
 	*4.0)
 		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
 		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
 		;;
 		;;
 	*5.*)
 	*5.*)
-	        UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+		UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
 		;;
 		;;
 	esac
 	esac
 	# According to Compaq, /usr/sbin/psrinfo has been available on
 	# According to Compaq, /usr/sbin/psrinfo has been available on
@@ -234,43 +275,46 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
 	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
 	ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^  The alpha \(.*\) processor.*$/\1/p' | head -n 1`
 	case "$ALPHA_CPU_TYPE" in
 	case "$ALPHA_CPU_TYPE" in
 	    "EV4 (21064)")
 	    "EV4 (21064)")
-		UNAME_MACHINE="alpha" ;;
+		UNAME_MACHINE=alpha ;;
 	    "EV4.5 (21064)")
 	    "EV4.5 (21064)")
-		UNAME_MACHINE="alpha" ;;
+		UNAME_MACHINE=alpha ;;
 	    "LCA4 (21066/21068)")
 	    "LCA4 (21066/21068)")
-		UNAME_MACHINE="alpha" ;;
+		UNAME_MACHINE=alpha ;;
 	    "EV5 (21164)")
 	    "EV5 (21164)")
-		UNAME_MACHINE="alphaev5" ;;
+		UNAME_MACHINE=alphaev5 ;;
 	    "EV5.6 (21164A)")
 	    "EV5.6 (21164A)")
-		UNAME_MACHINE="alphaev56" ;;
+		UNAME_MACHINE=alphaev56 ;;
 	    "EV5.6 (21164PC)")
 	    "EV5.6 (21164PC)")
-		UNAME_MACHINE="alphapca56" ;;
+		UNAME_MACHINE=alphapca56 ;;
 	    "EV5.7 (21164PC)")
 	    "EV5.7 (21164PC)")
-		UNAME_MACHINE="alphapca57" ;;
+		UNAME_MACHINE=alphapca57 ;;
 	    "EV6 (21264)")
 	    "EV6 (21264)")
-		UNAME_MACHINE="alphaev6" ;;
+		UNAME_MACHINE=alphaev6 ;;
 	    "EV6.7 (21264A)")
 	    "EV6.7 (21264A)")
-		UNAME_MACHINE="alphaev67" ;;
+		UNAME_MACHINE=alphaev67 ;;
 	    "EV6.8CB (21264C)")
 	    "EV6.8CB (21264C)")
-		UNAME_MACHINE="alphaev68" ;;
+		UNAME_MACHINE=alphaev68 ;;
 	    "EV6.8AL (21264B)")
 	    "EV6.8AL (21264B)")
-		UNAME_MACHINE="alphaev68" ;;
+		UNAME_MACHINE=alphaev68 ;;
 	    "EV6.8CX (21264D)")
 	    "EV6.8CX (21264D)")
-		UNAME_MACHINE="alphaev68" ;;
+		UNAME_MACHINE=alphaev68 ;;
 	    "EV6.9A (21264/EV69A)")
 	    "EV6.9A (21264/EV69A)")
-		UNAME_MACHINE="alphaev69" ;;
+		UNAME_MACHINE=alphaev69 ;;
 	    "EV7 (21364)")
 	    "EV7 (21364)")
-		UNAME_MACHINE="alphaev7" ;;
+		UNAME_MACHINE=alphaev7 ;;
 	    "EV7.9 (21364A)")
 	    "EV7.9 (21364A)")
-		UNAME_MACHINE="alphaev79" ;;
+		UNAME_MACHINE=alphaev79 ;;
 	esac
 	esac
 	# A Pn.n version is a patched version.
 	# A Pn.n version is a patched version.
 	# A Vn.n version is a released version.
 	# A Vn.n version is a released version.
 	# A Tn.n version is a released field test version.
 	# A Tn.n version is a released field test version.
 	# A Xn.n version is an unreleased experimental baselevel.
 	# A Xn.n version is an unreleased experimental baselevel.
 	# 1.2 uses "1.2" for uname -r.
 	# 1.2 uses "1.2" for uname -r.
-	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-	exit ;;
+	echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+	# Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+	exitcode=$?
+	trap '' 0
+	exit $exitcode ;;
     Alpha\ *:Windows_NT*:*)
     Alpha\ *:Windows_NT*:*)
 	# How do we know it's Interix rather than the generic POSIX subsystem?
 	# How do we know it's Interix rather than the generic POSIX subsystem?
 	# Should we change UNAME_MACHINE based on the output of uname instead
 	# Should we change UNAME_MACHINE based on the output of uname instead
@@ -296,12 +340,12 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
 	echo s390-ibm-zvmoe
 	echo s390-ibm-zvmoe
 	exit ;;
 	exit ;;
     *:OS400:*:*)
     *:OS400:*:*)
-        echo powerpc-ibm-os400
+	echo powerpc-ibm-os400
 	exit ;;
 	exit ;;
     arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
     arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
 	echo arm-acorn-riscix${UNAME_RELEASE}
 	echo arm-acorn-riscix${UNAME_RELEASE}
 	exit ;;
 	exit ;;
-    arm:riscos:*:*|arm:RISCOS:*:*)
+    arm*:riscos:*:*|arm*:RISCOS:*:*)
 	echo arm-unknown-riscos
 	echo arm-unknown-riscos
 	exit ;;
 	exit ;;
     SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
     SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
@@ -339,16 +383,16 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
 	exit ;;
 	exit ;;
     i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
     i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
 	eval $set_cc_for_build
 	eval $set_cc_for_build
-	SUN_ARCH="i386"
+	SUN_ARCH=i386
 	# If there is a compiler, see if it is configured for 64-bit objects.
 	# If there is a compiler, see if it is configured for 64-bit objects.
 	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
 	# Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
 	# This test works for both compilers.
 	# This test works for both compilers.
-	if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+	if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
 	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
 	    if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
-		(CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+		(CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
 		grep IS_64BIT_ARCH >/dev/null
 		grep IS_64BIT_ARCH >/dev/null
 	    then
 	    then
-		SUN_ARCH="x86_64"
+		SUN_ARCH=x86_64
 	    fi
 	    fi
 	fi
 	fi
 	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
 	echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
@@ -373,7 +417,7 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
 	exit ;;
 	exit ;;
     sun*:*:4.2BSD:*)
     sun*:*:4.2BSD:*)
 	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
 	UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
-	test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+	test "x${UNAME_RELEASE}" = x && UNAME_RELEASE=3
 	case "`/bin/arch`" in
 	case "`/bin/arch`" in
 	    sun3)
 	    sun3)
 		echo m68k-sun-sunos${UNAME_RELEASE}
 		echo m68k-sun-sunos${UNAME_RELEASE}
@@ -395,23 +439,23 @@ case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
     # MiNT.  But MiNT is downward compatible to TOS, so this should
     # MiNT.  But MiNT is downward compatible to TOS, so this should
     # be no problem.
     # be no problem.
     atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
     atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
-        echo m68k-atari-mint${UNAME_RELEASE}
+	echo m68k-atari-mint${UNAME_RELEASE}
 	exit ;;
 	exit ;;
     atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
     atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
 	echo m68k-atari-mint${UNAME_RELEASE}
 	echo m68k-atari-mint${UNAME_RELEASE}
-        exit ;;
+	exit ;;
     *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
     *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
-        echo m68k-atari-mint${UNAME_RELEASE}
+	echo m68k-atari-mint${UNAME_RELEASE}
 	exit ;;
 	exit ;;
     milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
     milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
-        echo m68k-milan-mint${UNAME_RELEASE}
-        exit ;;
+	echo m68k-milan-mint${UNAME_RELEASE}
+	exit ;;
     hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
     hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
-        echo m68k-hades-mint${UNAME_RELEASE}
-        exit ;;
+	echo m68k-hades-mint${UNAME_RELEASE}
+	exit ;;
     *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
     *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
-        echo m68k-unknown-mint${UNAME_RELEASE}
-        exit ;;
+	echo m68k-unknown-mint${UNAME_RELEASE}
+	exit ;;
     m68k:machten:*:*)
     m68k:machten:*:*)
 	echo m68k-apple-machten${UNAME_RELEASE}
 	echo m68k-apple-machten${UNAME_RELEASE}
 	exit ;;
 	exit ;;
@@ -481,8 +525,8 @@ EOF
 	echo m88k-motorola-sysv3
 	echo m88k-motorola-sysv3
 	exit ;;
 	exit ;;
     AViiON:dgux:*:*)
     AViiON:dgux:*:*)
-        # DG/UX returns AViiON for all architectures
-        UNAME_PROCESSOR=`/usr/bin/uname -p`
+	# DG/UX returns AViiON for all architectures
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
 	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
 	if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
 	then
 	then
 	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
 	    if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
@@ -495,7 +539,7 @@ EOF
 	else
 	else
 	    echo i586-dg-dgux${UNAME_RELEASE}
 	    echo i586-dg-dgux${UNAME_RELEASE}
 	fi
 	fi
- 	exit ;;
+	exit ;;
     M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
     M88*:DolphinOS:*:*)	# DolphinOS (SVR3)
 	echo m88k-dolphin-sysv3
 	echo m88k-dolphin-sysv3
 	exit ;;
 	exit ;;
@@ -552,15 +596,16 @@ EOF
 		echo rs6000-ibm-aix3.2
 		echo rs6000-ibm-aix3.2
 	fi
 	fi
 	exit ;;
 	exit ;;
-    *:AIX:*:[456])
+    *:AIX:*:[4567])
 	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
 	IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
 	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
 	if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
 		IBM_ARCH=rs6000
 		IBM_ARCH=rs6000
 	else
 	else
 		IBM_ARCH=powerpc
 		IBM_ARCH=powerpc
 	fi
 	fi
-	if [ -x /usr/bin/oslevel ] ; then
-		IBM_REV=`/usr/bin/oslevel`
+	if [ -x /usr/bin/lslpp ] ; then
+		IBM_REV=`/usr/bin/lslpp -Lqc bos.rte.libc |
+			   awk -F: '{ print $3 }' | sed s/[0-9]*$/0/`
 	else
 	else
 		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
 		IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
 	fi
 	fi
@@ -595,58 +640,58 @@ EOF
 	    9000/[678][0-9][0-9])
 	    9000/[678][0-9][0-9])
 		if [ -x /usr/bin/getconf ]; then
 		if [ -x /usr/bin/getconf ]; then
 		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
 		    sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
-                    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
-                    case "${sc_cpu_version}" in
-                      523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
-                      528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
-                      532)                      # CPU_PA_RISC2_0
-                        case "${sc_kernel_bits}" in
-                          32) HP_ARCH="hppa2.0n" ;;
-                          64) HP_ARCH="hppa2.0w" ;;
-			  '') HP_ARCH="hppa2.0" ;;   # HP-UX 10.20
-                        esac ;;
-                    esac
+		    sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+		    case "${sc_cpu_version}" in
+		      523) HP_ARCH=hppa1.0 ;; # CPU_PA_RISC1_0
+		      528) HP_ARCH=hppa1.1 ;; # CPU_PA_RISC1_1
+		      532)                      # CPU_PA_RISC2_0
+			case "${sc_kernel_bits}" in
+			  32) HP_ARCH=hppa2.0n ;;
+			  64) HP_ARCH=hppa2.0w ;;
+			  '') HP_ARCH=hppa2.0 ;;   # HP-UX 10.20
+			esac ;;
+		    esac
 		fi
 		fi
 		if [ "${HP_ARCH}" = "" ]; then
 		if [ "${HP_ARCH}" = "" ]; then
 		    eval $set_cc_for_build
 		    eval $set_cc_for_build
-		    sed 's/^              //' << EOF >$dummy.c
+		    sed 's/^		//' << EOF >$dummy.c
 
 
-              #define _HPUX_SOURCE
-              #include <stdlib.h>
-              #include <unistd.h>
+		#define _HPUX_SOURCE
+		#include <stdlib.h>
+		#include <unistd.h>
 
 
-              int main ()
-              {
-              #if defined(_SC_KERNEL_BITS)
-                  long bits = sysconf(_SC_KERNEL_BITS);
-              #endif
-                  long cpu  = sysconf (_SC_CPU_VERSION);
+		int main ()
+		{
+		#if defined(_SC_KERNEL_BITS)
+		    long bits = sysconf(_SC_KERNEL_BITS);
+		#endif
+		    long cpu  = sysconf (_SC_CPU_VERSION);
 
 
-                  switch (cpu)
-              	{
-              	case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
-              	case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
-              	case CPU_PA_RISC2_0:
-              #if defined(_SC_KERNEL_BITS)
-              	    switch (bits)
-              		{
-              		case 64: puts ("hppa2.0w"); break;
-              		case 32: puts ("hppa2.0n"); break;
-              		default: puts ("hppa2.0"); break;
-              		} break;
-              #else  /* !defined(_SC_KERNEL_BITS) */
-              	    puts ("hppa2.0"); break;
-              #endif
-              	default: puts ("hppa1.0"); break;
-              	}
-                  exit (0);
-              }
+		    switch (cpu)
+			{
+			case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+			case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+			case CPU_PA_RISC2_0:
+		#if defined(_SC_KERNEL_BITS)
+			    switch (bits)
+				{
+				case 64: puts ("hppa2.0w"); break;
+				case 32: puts ("hppa2.0n"); break;
+				default: puts ("hppa2.0"); break;
+				} break;
+		#else  /* !defined(_SC_KERNEL_BITS) */
+			    puts ("hppa2.0"); break;
+		#endif
+			default: puts ("hppa1.0"); break;
+			}
+		    exit (0);
+		}
 EOF
 EOF
-		    (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+		    (CCOPTS="" $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
 		    test -z "$HP_ARCH" && HP_ARCH=hppa
 		    test -z "$HP_ARCH" && HP_ARCH=hppa
 		fi ;;
 		fi ;;
 	esac
 	esac
-	if [ ${HP_ARCH} = "hppa2.0w" ]
+	if [ ${HP_ARCH} = hppa2.0w ]
 	then
 	then
 	    eval $set_cc_for_build
 	    eval $set_cc_for_build
 
 
@@ -659,12 +704,12 @@ EOF
 	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
 	    # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
 	    # => hppa64-hp-hpux11.23
 	    # => hppa64-hp-hpux11.23
 
 
-	    if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+	    if echo __LP64__ | (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) |
 		grep -q __LP64__
 		grep -q __LP64__
 	    then
 	    then
-		HP_ARCH="hppa2.0w"
+		HP_ARCH=hppa2.0w
 	    else
 	    else
-		HP_ARCH="hppa64"
+		HP_ARCH=hppa64
 	    fi
 	    fi
 	fi
 	fi
 	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
 	echo ${HP_ARCH}-hp-hpux${HPUX_REV}
@@ -731,22 +776,22 @@ EOF
 	exit ;;
 	exit ;;
     C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
     C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
 	echo c1-convex-bsd
 	echo c1-convex-bsd
-        exit ;;
+	exit ;;
     C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
     C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
 	if getsysinfo -f scalar_acc
 	if getsysinfo -f scalar_acc
 	then echo c32-convex-bsd
 	then echo c32-convex-bsd
 	else echo c2-convex-bsd
 	else echo c2-convex-bsd
 	fi
 	fi
-        exit ;;
+	exit ;;
     C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
     C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
 	echo c34-convex-bsd
 	echo c34-convex-bsd
-        exit ;;
+	exit ;;
     C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
     C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
 	echo c38-convex-bsd
 	echo c38-convex-bsd
-        exit ;;
+	exit ;;
     C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
     C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
 	echo c4-convex-bsd
 	echo c4-convex-bsd
-        exit ;;
+	exit ;;
     CRAY*Y-MP:*:*:*)
     CRAY*Y-MP:*:*:*)
 	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
 	echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
 	exit ;;
 	exit ;;
@@ -769,15 +814,15 @@ EOF
 	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
 	echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
 	exit ;;
 	exit ;;
     F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
     F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
-	FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
-        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
-        FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
-        echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
-        exit ;;
+	FUJITSU_PROC=`uname -m | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz`
+	FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+	echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	exit ;;
     5000:UNIX_System_V:4.*:*)
     5000:UNIX_System_V:4.*:*)
-        FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
-        FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
-        echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+	FUJITSU_SYS=`uname -p | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/\///'`
+	FUJITSU_REL=`echo ${UNAME_RELEASE} | tr ABCDEFGHIJKLMNOPQRSTUVWXYZ abcdefghijklmnopqrstuvwxyz | sed -e 's/ /_/'`
+	echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
 	exit ;;
 	exit ;;
     i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
     i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
 	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
 	echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
@@ -789,30 +834,35 @@ EOF
 	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
 	echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
 	exit ;;
 	exit ;;
     *:FreeBSD:*:*)
     *:FreeBSD:*:*)
-	case ${UNAME_MACHINE} in
-	    pc98)
-		echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+	UNAME_PROCESSOR=`/usr/bin/uname -p`
+	case ${UNAME_PROCESSOR} in
 	    amd64)
 	    amd64)
 		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
 		echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
 	    *)
 	    *)
-		echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+		echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
 	esac
 	esac
 	exit ;;
 	exit ;;
     i*:CYGWIN*:*)
     i*:CYGWIN*:*)
 	echo ${UNAME_MACHINE}-pc-cygwin
 	echo ${UNAME_MACHINE}-pc-cygwin
 	exit ;;
 	exit ;;
+    *:MINGW64*:*)
+	echo ${UNAME_MACHINE}-pc-mingw64
+	exit ;;
     *:MINGW*:*)
     *:MINGW*:*)
 	echo ${UNAME_MACHINE}-pc-mingw32
 	echo ${UNAME_MACHINE}-pc-mingw32
 	exit ;;
 	exit ;;
+    *:MSYS*:*)
+	echo ${UNAME_MACHINE}-pc-msys
+	exit ;;
     i*:windows32*:*)
     i*:windows32*:*)
-    	# uname -m includes "-pc" on this system.
-    	echo ${UNAME_MACHINE}-mingw32
+	# uname -m includes "-pc" on this system.
+	echo ${UNAME_MACHINE}-mingw32
 	exit ;;
 	exit ;;
     i*:PW*:*)
     i*:PW*:*)
 	echo ${UNAME_MACHINE}-pc-pw32
 	echo ${UNAME_MACHINE}-pc-pw32
 	exit ;;
 	exit ;;
     *:Interix*:*)
     *:Interix*:*)
-    	case ${UNAME_MACHINE} in
+	case ${UNAME_MACHINE} in
 	    x86)
 	    x86)
 		echo i586-pc-interix${UNAME_RELEASE}
 		echo i586-pc-interix${UNAME_RELEASE}
 		exit ;;
 		exit ;;
@@ -849,15 +899,22 @@ EOF
 	exit ;;
 	exit ;;
     *:GNU:*:*)
     *:GNU:*:*)
 	# the GNU system
 	# the GNU system
-	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+	echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
 	exit ;;
 	exit ;;
     *:GNU/*:*:*)
     *:GNU/*:*:*)
 	# other systems with GNU libc and userland
 	# other systems with GNU libc and userland
-	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu
+	echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr "[:upper:]" "[:lower:]"``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
 	exit ;;
 	exit ;;
     i*86:Minix:*:*)
     i*86:Minix:*:*)
 	echo ${UNAME_MACHINE}-pc-minix
 	echo ${UNAME_MACHINE}-pc-minix
 	exit ;;
 	exit ;;
+    aarch64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    aarch64_be:Linux:*:*)
+	UNAME_MACHINE=aarch64_be
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
     alpha:Linux:*:*)
     alpha:Linux:*:*)
 	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
 	case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
 	  EV5)   UNAME_MACHINE=alphaev5 ;;
 	  EV5)   UNAME_MACHINE=alphaev5 ;;
@@ -867,52 +924,62 @@ EOF
 	  EV6)   UNAME_MACHINE=alphaev6 ;;
 	  EV6)   UNAME_MACHINE=alphaev6 ;;
 	  EV67)  UNAME_MACHINE=alphaev67 ;;
 	  EV67)  UNAME_MACHINE=alphaev67 ;;
 	  EV68*) UNAME_MACHINE=alphaev68 ;;
 	  EV68*) UNAME_MACHINE=alphaev68 ;;
-        esac
+	esac
 	objdump --private-headers /bin/sh | grep -q ld.so.1
 	objdump --private-headers /bin/sh | grep -q ld.so.1
-	if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi
-	echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC}
+	if test "$?" = 0 ; then LIBC=gnulibc1 ; fi
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    arc:Linux:*:* | arceb:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
 	exit ;;
     arm*:Linux:*:*)
     arm*:Linux:*:*)
 	eval $set_cc_for_build
 	eval $set_cc_for_build
 	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
 	if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
 	    | grep -q __ARM_EABI__
 	    | grep -q __ARM_EABI__
 	then
 	then
-	    echo ${UNAME_MACHINE}-unknown-linux-gnu
+	    echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	else
 	else
-	    echo ${UNAME_MACHINE}-unknown-linux-gnueabi
+	    if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+		| grep -q __ARM_PCS_VFP
+	    then
+		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+	    else
+		echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+	    fi
 	fi
 	fi
 	exit ;;
 	exit ;;
     avr32*:Linux:*:*)
     avr32*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
 	exit ;;
     cris:Linux:*:*)
     cris:Linux:*:*)
-	echo cris-axis-linux-gnu
+	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
 	exit ;;
 	exit ;;
     crisv32:Linux:*:*)
     crisv32:Linux:*:*)
-	echo crisv32-axis-linux-gnu
+	echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+	exit ;;
+    e2k:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
 	exit ;;
     frv:Linux:*:*)
     frv:Linux:*:*)
-    	echo frv-unknown-linux-gnu
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    hexagon:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
 	exit ;;
     i*86:Linux:*:*)
     i*86:Linux:*:*)
-	LIBC=gnu
-	eval $set_cc_for_build
-	sed 's/^	//' << EOF >$dummy.c
-	#ifdef __dietlibc__
-	LIBC=dietlibc
-	#endif
-EOF
-	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC'`
-	echo "${UNAME_MACHINE}-pc-linux-${LIBC}"
+	echo ${UNAME_MACHINE}-pc-linux-${LIBC}
 	exit ;;
 	exit ;;
     ia64:Linux:*:*)
     ia64:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    k1om:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
 	exit ;;
     m32r*:Linux:*:*)
     m32r*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
 	exit ;;
     m68*:Linux:*:*)
     m68*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
 	exit ;;
     mips:Linux:*:* | mips64:Linux:*:*)
     mips:Linux:*:* | mips64:Linux:*:*)
 	eval $set_cc_for_build
 	eval $set_cc_for_build
@@ -931,51 +998,69 @@ EOF
 	#endif
 	#endif
 EOF
 EOF
 	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
 	eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
-	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; }
+	test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
 	;;
 	;;
-    or32:Linux:*:*)
-	echo or32-unknown-linux-gnu
+    mips64el:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    openrisc*:Linux:*:*)
+	echo or1k-unknown-linux-${LIBC}
+	exit ;;
+    or32:Linux:*:* | or1k*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
 	exit ;;
     padre:Linux:*:*)
     padre:Linux:*:*)
-	echo sparc-unknown-linux-gnu
+	echo sparc-unknown-linux-${LIBC}
 	exit ;;
 	exit ;;
     parisc64:Linux:*:* | hppa64:Linux:*:*)
     parisc64:Linux:*:* | hppa64:Linux:*:*)
-	echo hppa64-unknown-linux-gnu
+	echo hppa64-unknown-linux-${LIBC}
 	exit ;;
 	exit ;;
     parisc:Linux:*:* | hppa:Linux:*:*)
     parisc:Linux:*:* | hppa:Linux:*:*)
 	# Look for CPU level
 	# Look for CPU level
 	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
 	case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
-	  PA7*) echo hppa1.1-unknown-linux-gnu ;;
-	  PA8*) echo hppa2.0-unknown-linux-gnu ;;
-	  *)    echo hppa-unknown-linux-gnu ;;
+	  PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
+	  PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+	  *)    echo hppa-unknown-linux-${LIBC} ;;
 	esac
 	esac
 	exit ;;
 	exit ;;
     ppc64:Linux:*:*)
     ppc64:Linux:*:*)
-	echo powerpc64-unknown-linux-gnu
+	echo powerpc64-unknown-linux-${LIBC}
 	exit ;;
 	exit ;;
     ppc:Linux:*:*)
     ppc:Linux:*:*)
-	echo powerpc-unknown-linux-gnu
+	echo powerpc-unknown-linux-${LIBC}
+	exit ;;
+    ppc64le:Linux:*:*)
+	echo powerpc64le-unknown-linux-${LIBC}
+	exit ;;
+    ppcle:Linux:*:*)
+	echo powerpcle-unknown-linux-${LIBC}
+	exit ;;
+    riscv32:Linux:*:* | riscv64:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
 	exit ;;
     s390:Linux:*:* | s390x:Linux:*:*)
     s390:Linux:*:* | s390x:Linux:*:*)
-	echo ${UNAME_MACHINE}-ibm-linux
+	echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
 	exit ;;
 	exit ;;
     sh64*:Linux:*:*)
     sh64*:Linux:*:*)
-    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
 	exit ;;
     sh*:Linux:*:*)
     sh*:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
 	exit ;;
     sparc:Linux:*:* | sparc64:Linux:*:*)
     sparc:Linux:*:* | sparc64:Linux:*:*)
-	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+	exit ;;
+    tile*:Linux:*:*)
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
 	exit ;;
     vax:Linux:*:*)
     vax:Linux:*:*)
-	echo ${UNAME_MACHINE}-dec-linux-gnu
+	echo ${UNAME_MACHINE}-dec-linux-${LIBC}
 	exit ;;
 	exit ;;
     x86_64:Linux:*:*)
     x86_64:Linux:*:*)
-	echo x86_64-unknown-linux-gnu
+	echo ${UNAME_MACHINE}-pc-linux-${LIBC}
 	exit ;;
 	exit ;;
     xtensa*:Linux:*:*)
     xtensa*:Linux:*:*)
-    	echo ${UNAME_MACHINE}-unknown-linux-gnu
+	echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
 	exit ;;
 	exit ;;
     i*86:DYNIX/ptx:4*:*)
     i*86:DYNIX/ptx:4*:*)
 	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
 	# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
@@ -984,11 +1069,11 @@ EOF
 	echo i386-sequent-sysv4
 	echo i386-sequent-sysv4
 	exit ;;
 	exit ;;
     i*86:UNIX_SV:4.2MP:2.*)
     i*86:UNIX_SV:4.2MP:2.*)
-        # Unixware is an offshoot of SVR4, but it has its own version
-        # number series starting with 2...
-        # I am not positive that other SVR4 systems won't match this,
+	# Unixware is an offshoot of SVR4, but it has its own version
+	# number series starting with 2...
+	# I am not positive that other SVR4 systems won't match this,
 	# I just have to hope.  -- rms.
 	# I just have to hope.  -- rms.
-        # Use sysv4.2uw... so that sysv4* matches it.
+	# Use sysv4.2uw... so that sysv4* matches it.
 	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
 	echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
 	exit ;;
 	exit ;;
     i*86:OS/2:*:*)
     i*86:OS/2:*:*)
@@ -1020,7 +1105,7 @@ EOF
 	fi
 	fi
 	exit ;;
 	exit ;;
     i*86:*:5:[678]*)
     i*86:*:5:[678]*)
-    	# UnixWare 7.x, OpenUNIX and OpenServer 6.
+	# UnixWare 7.x, OpenUNIX and OpenServer 6.
 	case `/bin/uname -X | grep "^Machine"` in
 	case `/bin/uname -X | grep "^Machine"` in
 	    *486*)	     UNAME_MACHINE=i486 ;;
 	    *486*)	     UNAME_MACHINE=i486 ;;
 	    *Pentium)	     UNAME_MACHINE=i586 ;;
 	    *Pentium)	     UNAME_MACHINE=i586 ;;
@@ -1048,13 +1133,13 @@ EOF
 	exit ;;
 	exit ;;
     pc:*:*:*)
     pc:*:*:*)
 	# Left here for compatibility:
 	# Left here for compatibility:
-        # uname -m prints for DJGPP always 'pc', but it prints nothing about
-        # the processor, so we play safe by assuming i586.
+	# uname -m prints for DJGPP always 'pc', but it prints nothing about
+	# the processor, so we play safe by assuming i586.
 	# Note: whatever this is, it MUST be the same as what config.sub
 	# Note: whatever this is, it MUST be the same as what config.sub
-	# prints for the "djgpp" host, or else GDB configury will decide that
+	# prints for the "djgpp" host, or else GDB configure will decide that
 	# this is a cross-build.
 	# this is a cross-build.
 	echo i586-pc-msdosdjgpp
 	echo i586-pc-msdosdjgpp
-        exit ;;
+	exit ;;
     Intel:Mach:3*:*)
     Intel:Mach:3*:*)
 	echo i386-pc-mach3
 	echo i386-pc-mach3
 	exit ;;
 	exit ;;
@@ -1089,8 +1174,8 @@ EOF
 	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
 	/bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
 	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
 	  && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
     3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
     3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
-        /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
-          && { echo i486-ncr-sysv4; exit; } ;;
+	/bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+	  && { echo i486-ncr-sysv4; exit; } ;;
     NCR*:*:4.2:* | MPRAS*:*:4.2:*)
     NCR*:*:4.2:* | MPRAS*:*:4.2:*)
 	OS_REL='.3'
 	OS_REL='.3'
 	test -r /etc/.relid \
 	test -r /etc/.relid \
@@ -1133,10 +1218,10 @@ EOF
 		echo ns32k-sni-sysv
 		echo ns32k-sni-sysv
 	fi
 	fi
 	exit ;;
 	exit ;;
-    PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
-                      # says <[email protected]>
-        echo i586-unisys-sysv4
-        exit ;;
+    PENTIUM:*:4.0*:*)	# Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+			# says <[email protected]>
+	echo i586-unisys-sysv4
+	exit ;;
     *:UNIX_System_V:4*:FTX*)
     *:UNIX_System_V:4*:FTX*)
 	# From Gerald Hewes <[email protected]>.
 	# From Gerald Hewes <[email protected]>.
 	# How about differentiating between stratus architectures? -djm
 	# How about differentiating between stratus architectures? -djm
@@ -1162,11 +1247,11 @@ EOF
 	exit ;;
 	exit ;;
     R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
     R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
 	if [ -d /usr/nec ]; then
 	if [ -d /usr/nec ]; then
-	        echo mips-nec-sysv${UNAME_RELEASE}
+		echo mips-nec-sysv${UNAME_RELEASE}
 	else
 	else
-	        echo mips-unknown-sysv${UNAME_RELEASE}
+		echo mips-unknown-sysv${UNAME_RELEASE}
 	fi
 	fi
-        exit ;;
+	exit ;;
     BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
     BeBox:BeOS:*:*)	# BeOS running on hardware made by Be, PPC only.
 	echo powerpc-be-beos
 	echo powerpc-be-beos
 	exit ;;
 	exit ;;
@@ -1179,6 +1264,9 @@ EOF
     BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
     BePC:Haiku:*:*)	# Haiku running on Intel PC compatible.
 	echo i586-pc-haiku
 	echo i586-pc-haiku
 	exit ;;
 	exit ;;
+    x86_64:Haiku:*:*)
+	echo x86_64-unknown-haiku
+	exit ;;
     SX-4:SUPER-UX:*:*)
     SX-4:SUPER-UX:*:*)
 	echo sx4-nec-superux${UNAME_RELEASE}
 	echo sx4-nec-superux${UNAME_RELEASE}
 	exit ;;
 	exit ;;
@@ -1197,6 +1285,9 @@ EOF
     SX-8R:SUPER-UX:*:*)
     SX-8R:SUPER-UX:*:*)
 	echo sx8r-nec-superux${UNAME_RELEASE}
 	echo sx8r-nec-superux${UNAME_RELEASE}
 	exit ;;
 	exit ;;
+    SX-ACE:SUPER-UX:*:*)
+	echo sxace-nec-superux${UNAME_RELEASE}
+	exit ;;
     Power*:Rhapsody:*:*)
     Power*:Rhapsody:*:*)
 	echo powerpc-apple-rhapsody${UNAME_RELEASE}
 	echo powerpc-apple-rhapsody${UNAME_RELEASE}
 	exit ;;
 	exit ;;
@@ -1205,24 +1296,36 @@ EOF
 	exit ;;
 	exit ;;
     *:Darwin:*:*)
     *:Darwin:*:*)
 	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
 	UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
-	case $UNAME_PROCESSOR in
-	    i386)
-		eval $set_cc_for_build
-		if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
-		  if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
-		      (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
-		      grep IS_64BIT_ARCH >/dev/null
-		  then
-		      UNAME_PROCESSOR="x86_64"
-		  fi
-		fi ;;
-	    unknown) UNAME_PROCESSOR=powerpc ;;
-	esac
+	eval $set_cc_for_build
+	if test "$UNAME_PROCESSOR" = unknown ; then
+	    UNAME_PROCESSOR=powerpc
+	fi
+	if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
+	    if [ "$CC_FOR_BUILD" != no_compiler_found ]; then
+		if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+		    (CCOPTS="" $CC_FOR_BUILD -E - 2>/dev/null) | \
+		    grep IS_64BIT_ARCH >/dev/null
+		then
+		    case $UNAME_PROCESSOR in
+			i386) UNAME_PROCESSOR=x86_64 ;;
+			powerpc) UNAME_PROCESSOR=powerpc64 ;;
+		    esac
+		fi
+	    fi
+	elif test "$UNAME_PROCESSOR" = i386 ; then
+	    # Avoid executing cc on OS X 10.9, as it ships with a stub
+	    # that puts up a graphical alert prompting to install
+	    # developer tools.  Any system running Mac OS X 10.7 or
+	    # later (Darwin 11 and later) is required to have a 64-bit
+	    # processor. This is not true of the ARM version of Darwin
+	    # that Apple uses in portable devices.
+	    UNAME_PROCESSOR=x86_64
+	fi
 	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
 	echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
 	exit ;;
 	exit ;;
     *:procnto*:*:* | *:QNX:[0123456789]*:*)
     *:procnto*:*:* | *:QNX:[0123456789]*:*)
 	UNAME_PROCESSOR=`uname -p`
 	UNAME_PROCESSOR=`uname -p`
-	if test "$UNAME_PROCESSOR" = "x86"; then
+	if test "$UNAME_PROCESSOR" = x86; then
 		UNAME_PROCESSOR=i386
 		UNAME_PROCESSOR=i386
 		UNAME_MACHINE=pc
 		UNAME_MACHINE=pc
 	fi
 	fi
@@ -1231,7 +1334,10 @@ EOF
     *:QNX:*:4*)
     *:QNX:*:4*)
 	echo i386-pc-qnx
 	echo i386-pc-qnx
 	exit ;;
 	exit ;;
-    NSE-?:NONSTOP_KERNEL:*:*)
+    NEO-?:NONSTOP_KERNEL:*:*)
+	echo neo-tandem-nsk${UNAME_RELEASE}
+	exit ;;
+    NSE-*:NONSTOP_KERNEL:*:*)
 	echo nse-tandem-nsk${UNAME_RELEASE}
 	echo nse-tandem-nsk${UNAME_RELEASE}
 	exit ;;
 	exit ;;
     NSR-?:NONSTOP_KERNEL:*:*)
     NSR-?:NONSTOP_KERNEL:*:*)
@@ -1250,7 +1356,7 @@ EOF
 	# "uname -m" is not consistent, so use $cputype instead. 386
 	# "uname -m" is not consistent, so use $cputype instead. 386
 	# is converted to i386 for consistency with other x86
 	# is converted to i386 for consistency with other x86
 	# operating systems.
 	# operating systems.
-	if test "$cputype" = "386"; then
+	if test "$cputype" = 386; then
 	    UNAME_MACHINE=i386
 	    UNAME_MACHINE=i386
 	else
 	else
 	    UNAME_MACHINE="$cputype"
 	    UNAME_MACHINE="$cputype"
@@ -1276,13 +1382,13 @@ EOF
 	echo pdp10-unknown-its
 	echo pdp10-unknown-its
 	exit ;;
 	exit ;;
     SEI:*:*:SEIUX)
     SEI:*:*:SEIUX)
-        echo mips-sei-seiux${UNAME_RELEASE}
+	echo mips-sei-seiux${UNAME_RELEASE}
 	exit ;;
 	exit ;;
     *:DragonFly:*:*)
     *:DragonFly:*:*)
 	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
 	echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
 	exit ;;
 	exit ;;
     *:*VMS:*:*)
     *:*VMS:*:*)
-    	UNAME_MACHINE=`(uname -p) 2>/dev/null`
+	UNAME_MACHINE=`(uname -p) 2>/dev/null`
 	case "${UNAME_MACHINE}" in
 	case "${UNAME_MACHINE}" in
 	    A*) echo alpha-dec-vms ; exit ;;
 	    A*) echo alpha-dec-vms ; exit ;;
 	    I*) echo ia64-dec-vms ; exit ;;
 	    I*) echo ia64-dec-vms ; exit ;;
@@ -1292,7 +1398,7 @@ EOF
 	echo i386-pc-xenix
 	echo i386-pc-xenix
 	exit ;;
 	exit ;;
     i*86:skyos:*:*)
     i*86:skyos:*:*)
-	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+	echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE} | sed -e 's/ .*$//'`
 	exit ;;
 	exit ;;
     i*86:rdos:*:*)
     i*86:rdos:*:*)
 	echo ${UNAME_MACHINE}-pc-rdos
 	echo ${UNAME_MACHINE}-pc-rdos
@@ -1300,174 +1406,28 @@ EOF
     i*86:AROS:*:*)
     i*86:AROS:*:*)
 	echo ${UNAME_MACHINE}-pc-aros
 	echo ${UNAME_MACHINE}-pc-aros
 	exit ;;
 	exit ;;
-esac
-
-#echo '(No uname command or uname output not recognized.)' 1>&2
-#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
-
-eval $set_cc_for_build
-cat >$dummy.c <<EOF
-#ifdef _SEQUENT_
-# include <sys/types.h>
-# include <sys/utsname.h>
-#endif
-main ()
-{
-#if defined (sony)
-#if defined (MIPSEB)
-  /* BFD wants "bsd" instead of "newsos".  Perhaps BFD should be changed,
-     I don't know....  */
-  printf ("mips-sony-bsd\n"); exit (0);
-#else
-#include <sys/param.h>
-  printf ("m68k-sony-newsos%s\n",
-#ifdef NEWSOS4
-          "4"
-#else
-	  ""
-#endif
-         ); exit (0);
-#endif
-#endif
-
-#if defined (__arm) && defined (__acorn) && defined (__unix)
-  printf ("arm-acorn-riscix\n"); exit (0);
-#endif
-
-#if defined (hp300) && !defined (hpux)
-  printf ("m68k-hp-bsd\n"); exit (0);
-#endif
-
-#if defined (NeXT)
-#if !defined (__ARCHITECTURE__)
-#define __ARCHITECTURE__ "m68k"
-#endif
-  int version;
-  version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
-  if (version < 4)
-    printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version);
-  else
-    printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version);
-  exit (0);
-#endif
-
-#if defined (MULTIMAX) || defined (n16)
-#if defined (UMAXV)
-  printf ("ns32k-encore-sysv\n"); exit (0);
-#else
-#if defined (CMU)
-  printf ("ns32k-encore-mach\n"); exit (0);
-#else
-  printf ("ns32k-encore-bsd\n"); exit (0);
-#endif
-#endif
-#endif
-
-#if defined (__386BSD__)
-  printf ("i386-pc-bsd\n"); exit (0);
-#endif
-
-#if defined (sequent)
-#if defined (i386)
-  printf ("i386-sequent-dynix\n"); exit (0);
-#endif
-#if defined (ns32000)
-  printf ("ns32k-sequent-dynix\n"); exit (0);
-#endif
-#endif
-
-#if defined (_SEQUENT_)
-    struct utsname un;
-
-    uname(&un);
-
-    if (strncmp(un.version, "V2", 2) == 0) {
-	printf ("i386-sequent-ptx2\n"); exit (0);
-    }
-    if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
-	printf ("i386-sequent-ptx1\n"); exit (0);
-    }
-    printf ("i386-sequent-ptx\n"); exit (0);
-
-#endif
-
-#if defined (vax)
-# if !defined (ultrix)
-#  include <sys/param.h>
-#  if defined (BSD)
-#   if BSD == 43
-      printf ("vax-dec-bsd4.3\n"); exit (0);
-#   else
-#    if BSD == 199006
-      printf ("vax-dec-bsd4.3reno\n"); exit (0);
-#    else
-      printf ("vax-dec-bsd\n"); exit (0);
-#    endif
-#   endif
-#  else
-    printf ("vax-dec-bsd\n"); exit (0);
-#  endif
-# else
-    printf ("vax-dec-ultrix\n"); exit (0);
-# endif
-#endif
-
-#if defined (alliant) && defined (i860)
-  printf ("i860-alliant-bsd\n"); exit (0);
-#endif
-
-  exit (1);
-}
-EOF
-
-$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` &&
-	{ echo "$SYSTEM_NAME"; exit; }
-
-# Apollos put the system type in the environment.
-
-test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; }
-
-# Convex versions that predate uname can use getsysinfo(1)
-
-if [ -x /usr/convex/getsysinfo ]
-then
-    case `getsysinfo -f cpu_type` in
-    c1*)
-	echo c1-convex-bsd
-	exit ;;
-    c2*)
-	if getsysinfo -f scalar_acc
-	then echo c32-convex-bsd
-	else echo c2-convex-bsd
-	fi
-	exit ;;
-    c34*)
-	echo c34-convex-bsd
-	exit ;;
-    c38*)
-	echo c38-convex-bsd
+    x86_64:VMkernel:*:*)
+	echo ${UNAME_MACHINE}-unknown-esx
 	exit ;;
 	exit ;;
-    c4*)
-	echo c4-convex-bsd
+    amd64:Isilon\ OneFS:*:*)
+	echo x86_64-unknown-onefs
 	exit ;;
 	exit ;;
-    esac
-fi
+esac
 
 
 cat >&2 <<EOF
 cat >&2 <<EOF
 $0: unable to guess system type
 $0: unable to guess system type
 
 
-This script, last modified $timestamp, has failed to recognize
-the operating system you are using. It is advised that you
-download the most up to date version of the config scripts from
+This script (version $timestamp), has failed to recognize the
+operating system you are using. If your script is old, overwrite
+config.guess and config.sub with the latest versions from:
 
 
-  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess
 and
 and
-  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+  http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
 
 
-If the version you run ($0) is already up to date, please
-send the following data and any information you think might be
-pertinent to <[email protected]> in order to provide the needed
-information to handle your system.
+If $0 has already been updated, send the following data and any
+information you think might be pertinent to [email protected] to
+provide the necessary information to handle your system.
 
 
 config.guess timestamp = $timestamp
 config.guess timestamp = $timestamp
 
 

+ 231 - 120
ext/libpqxx-7.7.3/config/config.sub

@@ -1,38 +1,31 @@
 #! /bin/sh
 #! /bin/sh
 # Configuration validation subroutine script.
 # Configuration validation subroutine script.
-#   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-#   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010
-#   Free Software Foundation, Inc.
+#   Copyright 1992-2016 Free Software Foundation, Inc.
 
 
-timestamp='2010-01-22'
+timestamp='2016-11-04'
 
 
-# This file is (in principle) common to ALL GNU software.
-# The presence of a machine in this file suggests that SOME GNU software
-# can handle that machine.  It does not imply ALL GNU software can.
-#
-# This file is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2 of the License, or
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
 # (at your option) any later version.
 # (at your option) any later version.
 #
 #
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
 #
 #
 # You should have received a copy of the GNU General Public License
 # You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA
-# 02110-1301, USA.
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
 #
 #
 # As a special exception to the GNU General Public License, if you
 # As a special exception to the GNU General Public License, if you
 # distribute this file as part of a program that contains a
 # distribute this file as part of a program that contains a
 # configuration script generated by Autoconf, you may include it under
 # configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
+# the same distribution terms that you use for the rest of that
+# program.  This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
 
 
 
 
-# Please send patches to <[email protected]>.  Submit a context
-# diff and a properly formatted GNU ChangeLog entry.
+# Please send patches to <[email protected]>.
 #
 #
 # Configuration subroutine to validate and canonicalize a configuration type.
 # Configuration subroutine to validate and canonicalize a configuration type.
 # Supply the specified configuration type as an argument.
 # Supply the specified configuration type as an argument.
@@ -40,7 +33,7 @@ timestamp='2010-01-22'
 # Otherwise, we print the canonical config type on stdout and succeed.
 # Otherwise, we print the canonical config type on stdout and succeed.
 
 
 # You can get the latest version of this script from:
 # You can get the latest version of this script from:
-# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub
 
 
 # This file is supposed to be the same for all GNU packages
 # This file is supposed to be the same for all GNU packages
 # and recognize all the CPU types, system types and aliases
 # and recognize all the CPU types, system types and aliases
@@ -60,8 +53,7 @@ timestamp='2010-01-22'
 me=`echo "$0" | sed -e 's,.*/,,'`
 me=`echo "$0" | sed -e 's,.*/,,'`
 
 
 usage="\
 usage="\
-Usage: $0 [OPTION] CPU-MFR-OPSYS
-       $0 [OPTION] ALIAS
+Usage: $0 [OPTION] CPU-MFR-OPSYS or ALIAS
 
 
 Canonicalize a configuration name.
 Canonicalize a configuration name.
 
 
@@ -75,9 +67,7 @@ Report bugs and patches to <[email protected]>."
 version="\
 version="\
 GNU config.sub ($timestamp)
 GNU config.sub ($timestamp)
 
 
-Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free
-Software Foundation, Inc.
+Copyright 1992-2016 Free Software Foundation, Inc.
 
 
 This is free software; see the source for copying conditions.  There is NO
 This is free software; see the source for copying conditions.  There is NO
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
@@ -124,13 +114,18 @@ esac
 # Here we must recognize all the valid KERNEL-OS combinations.
 # Here we must recognize all the valid KERNEL-OS combinations.
 maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
 maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
 case $maybe_os in
 case $maybe_os in
-  nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \
-  uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \
-  kopensolaris*-gnu* | \
+  nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+  linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+  knetbsd*-gnu* | netbsd*-gnu* | netbsd*-eabi* | \
+  kopensolaris*-gnu* | cloudabi*-eabi* | \
   storm-chaos* | os2-emx* | rtmk-nova*)
   storm-chaos* | os2-emx* | rtmk-nova*)
     os=-$maybe_os
     os=-$maybe_os
     basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
     basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
     ;;
     ;;
+  android-linux)
+    os=-linux-android
+    basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+    ;;
   *)
   *)
     basic_machine=`echo $1 | sed 's/-[^-]*$//'`
     basic_machine=`echo $1 | sed 's/-[^-]*$//'`
     if [ $basic_machine != $1 ]
     if [ $basic_machine != $1 ]
@@ -153,12 +148,12 @@ case $os in
 	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
 	-convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
 	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
 	-c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
 	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
 	-harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
-	-apple | -axis | -knuth | -cray | -microblaze)
+	-apple | -axis | -knuth | -cray | -microblaze*)
 		os=
 		os=
 		basic_machine=$1
 		basic_machine=$1
 		;;
 		;;
-        -bluegene*)
-	        os=-cnk
+	-bluegene*)
+		os=-cnk
 		;;
 		;;
 	-sim | -cisco | -oki | -wec | -winbond)
 	-sim | -cisco | -oki | -wec | -winbond)
 		os=
 		os=
@@ -174,10 +169,10 @@ case $os in
 		os=-chorusos
 		os=-chorusos
 		basic_machine=$1
 		basic_machine=$1
 		;;
 		;;
- 	-chorusrdb)
- 		os=-chorusrdb
+	-chorusrdb)
+		os=-chorusrdb
 		basic_machine=$1
 		basic_machine=$1
- 		;;
+		;;
 	-hiux*)
 	-hiux*)
 		os=-hiuxwe2
 		os=-hiuxwe2
 		;;
 		;;
@@ -222,6 +217,12 @@ case $os in
 	-isc*)
 	-isc*)
 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
 		basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
 		;;
 		;;
+	-lynx*178)
+		os=-lynxos178
+		;;
+	-lynx*5)
+		os=-lynxos5
+		;;
 	-lynx*)
 	-lynx*)
 		os=-lynxos
 		os=-lynxos
 		;;
 		;;
@@ -246,20 +247,29 @@ case $basic_machine in
 	# Some are omitted here because they have special meanings below.
 	# Some are omitted here because they have special meanings below.
 	1750a | 580 \
 	1750a | 580 \
 	| a29k \
 	| a29k \
+	| aarch64 | aarch64_be \
 	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
 	| alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
 	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
 	| alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
 	| am33_2.0 \
 	| am33_2.0 \
-	| arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \
+	| arc | arceb \
+	| arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+	| avr | avr32 \
+	| ba \
+	| be32 | be64 \
 	| bfin \
 	| bfin \
-	| c4x | clipper \
+	| c4x | c8051 | clipper \
 	| d10v | d30v | dlx | dsp16xx \
 	| d10v | d30v | dlx | dsp16xx \
-	| fido | fr30 | frv \
+	| e2k | epiphany \
+	| fido | fr30 | frv | ft32 \
 	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
 	| h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+	| hexagon \
 	| i370 | i860 | i960 | ia64 \
 	| i370 | i860 | i960 | ia64 \
 	| ip2k | iq2000 \
 	| ip2k | iq2000 \
+	| k1om \
+	| le32 | le64 \
 	| lm32 \
 	| lm32 \
 	| m32c | m32r | m32rle | m68000 | m68k | m88k \
 	| m32c | m32r | m32rle | m68000 | m68k | m88k \
-	| maxq | mb | microblaze | mcore | mep | metag \
+	| maxq | mb | microblaze | microblazeel | mcore | mep | metag \
 	| mips | mipsbe | mipseb | mipsel | mipsle \
 	| mips | mipsbe | mipseb | mipsel | mipsle \
 	| mips16 \
 	| mips16 \
 	| mips64 | mips64el \
 	| mips64 | mips64el \
@@ -273,38 +283,56 @@ case $basic_machine in
 	| mips64vr5900 | mips64vr5900el \
 	| mips64vr5900 | mips64vr5900el \
 	| mipsisa32 | mipsisa32el \
 	| mipsisa32 | mipsisa32el \
 	| mipsisa32r2 | mipsisa32r2el \
 	| mipsisa32r2 | mipsisa32r2el \
+	| mipsisa32r6 | mipsisa32r6el \
 	| mipsisa64 | mipsisa64el \
 	| mipsisa64 | mipsisa64el \
 	| mipsisa64r2 | mipsisa64r2el \
 	| mipsisa64r2 | mipsisa64r2el \
+	| mipsisa64r6 | mipsisa64r6el \
 	| mipsisa64sb1 | mipsisa64sb1el \
 	| mipsisa64sb1 | mipsisa64sb1el \
 	| mipsisa64sr71k | mipsisa64sr71kel \
 	| mipsisa64sr71k | mipsisa64sr71kel \
+	| mipsr5900 | mipsr5900el \
 	| mipstx39 | mipstx39el \
 	| mipstx39 | mipstx39el \
 	| mn10200 | mn10300 \
 	| mn10200 | mn10300 \
 	| moxie \
 	| moxie \
 	| mt \
 	| mt \
 	| msp430 \
 	| msp430 \
-	| nios | nios2 \
+	| nds32 | nds32le | nds32be \
+	| nios | nios2 | nios2eb | nios2el \
 	| ns16k | ns32k \
 	| ns16k | ns32k \
-	| or32 \
+	| open8 | or1k | or1knd | or32 \
 	| pdp10 | pdp11 | pj | pjl \
 	| pdp10 | pdp11 | pj | pjl \
-	| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
+	| powerpc | powerpc64 | powerpc64le | powerpcle \
+	| pru \
 	| pyramid \
 	| pyramid \
-	| rx \
+	| riscv32 | riscv64 \
+	| rl78 | rx \
 	| score \
 	| score \
-	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+	| sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[234]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
 	| sh64 | sh64le \
 	| sh64 | sh64le \
 	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
 	| sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
 	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
 	| sparcv8 | sparcv9 | sparcv9b | sparcv9v \
-	| spu | strongarm \
-	| tahoe | thumb | tic4x | tic80 | tron \
+	| spu \
+	| tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
 	| ubicom32 \
 	| ubicom32 \
-	| v850 | v850e \
+	| v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+	| visium \
 	| we32k \
 	| we32k \
-	| x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \
+	| x86 | xc16x | xstormy16 | xtensa \
 	| z8k | z80)
 	| z8k | z80)
 		basic_machine=$basic_machine-unknown
 		basic_machine=$basic_machine-unknown
 		;;
 		;;
-	m6811 | m68hc11 | m6812 | m68hc12 | picochip)
-		# Motorola 68HC11/12.
+	c54x)
+		basic_machine=tic54x-unknown
+		;;
+	c55x)
+		basic_machine=tic55x-unknown
+		;;
+	c6x)
+		basic_machine=tic6x-unknown
+		;;
+	leon|leon[3-9])
+		basic_machine=sparc-$basic_machine
+		;;
+	m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
 		basic_machine=$basic_machine-unknown
 		basic_machine=$basic_machine-unknown
 		os=-none
 		os=-none
 		;;
 		;;
@@ -314,6 +342,21 @@ case $basic_machine in
 		basic_machine=mt-unknown
 		basic_machine=mt-unknown
 		;;
 		;;
 
 
+	strongarm | thumb | xscale)
+		basic_machine=arm-unknown
+		;;
+	xgate)
+		basic_machine=$basic_machine-unknown
+		os=-none
+		;;
+	xscaleeb)
+		basic_machine=armeb-unknown
+		;;
+
+	xscaleel)
+		basic_machine=armel-unknown
+		;;
+
 	# We use `pc' rather than `unknown'
 	# We use `pc' rather than `unknown'
 	# because (1) that's what they normally are, and
 	# because (1) that's what they normally are, and
 	# (2) the word "unknown" tends to confuse beginning users.
 	# (2) the word "unknown" tends to confuse beginning users.
@@ -328,25 +371,32 @@ case $basic_machine in
 	# Recognize the basic CPU types with company name.
 	# Recognize the basic CPU types with company name.
 	580-* \
 	580-* \
 	| a29k-* \
 	| a29k-* \
+	| aarch64-* | aarch64_be-* \
 	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
 	| alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
 	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
 	| alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
-	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* \
+	| alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
 	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
 	| arm-*  | armbe-* | armle-* | armeb-* | armv*-* \
 	| avr-* | avr32-* \
 	| avr-* | avr32-* \
+	| ba-* \
+	| be32-* | be64-* \
 	| bfin-* | bs2000-* \
 	| bfin-* | bs2000-* \
-	| c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \
-	| clipper-* | craynv-* | cydra-* \
+	| c[123]* | c30-* | [cjt]90-* | c4x-* \
+	| c8051-* | clipper-* | craynv-* | cydra-* \
 	| d10v-* | d30v-* | dlx-* \
 	| d10v-* | d30v-* | dlx-* \
-	| elxsi-* \
+	| e2k-* | elxsi-* \
 	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
 	| f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
 	| h8300-* | h8500-* \
 	| h8300-* | h8500-* \
 	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
 	| hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+	| hexagon-* \
 	| i*86-* | i860-* | i960-* | ia64-* \
 	| i*86-* | i860-* | i960-* | ia64-* \
 	| ip2k-* | iq2000-* \
 	| ip2k-* | iq2000-* \
+	| k1om-* \
+	| le32-* | le64-* \
 	| lm32-* \
 	| lm32-* \
 	| m32c-* | m32r-* | m32rle-* \
 	| m32c-* | m32r-* | m32rle-* \
 	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
 	| m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
-	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* | microblaze-* \
+	| m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+	| microblaze-* | microblazeel-* \
 	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
 	| mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
 	| mips16-* \
 	| mips16-* \
 	| mips64-* | mips64el-* \
 	| mips64-* | mips64el-* \
@@ -360,34 +410,44 @@ case $basic_machine in
 	| mips64vr5900-* | mips64vr5900el-* \
 	| mips64vr5900-* | mips64vr5900el-* \
 	| mipsisa32-* | mipsisa32el-* \
 	| mipsisa32-* | mipsisa32el-* \
 	| mipsisa32r2-* | mipsisa32r2el-* \
 	| mipsisa32r2-* | mipsisa32r2el-* \
+	| mipsisa32r6-* | mipsisa32r6el-* \
 	| mipsisa64-* | mipsisa64el-* \
 	| mipsisa64-* | mipsisa64el-* \
 	| mipsisa64r2-* | mipsisa64r2el-* \
 	| mipsisa64r2-* | mipsisa64r2el-* \
+	| mipsisa64r6-* | mipsisa64r6el-* \
 	| mipsisa64sb1-* | mipsisa64sb1el-* \
 	| mipsisa64sb1-* | mipsisa64sb1el-* \
 	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
 	| mipsisa64sr71k-* | mipsisa64sr71kel-* \
+	| mipsr5900-* | mipsr5900el-* \
 	| mipstx39-* | mipstx39el-* \
 	| mipstx39-* | mipstx39el-* \
 	| mmix-* \
 	| mmix-* \
 	| mt-* \
 	| mt-* \
 	| msp430-* \
 	| msp430-* \
-	| nios-* | nios2-* \
+	| nds32-* | nds32le-* | nds32be-* \
+	| nios-* | nios2-* | nios2eb-* | nios2el-* \
 	| none-* | np1-* | ns16k-* | ns32k-* \
 	| none-* | np1-* | ns16k-* | ns32k-* \
+	| open8-* \
+	| or1k*-* \
 	| orion-* \
 	| orion-* \
 	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
 	| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
-	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
+	| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+	| pru-* \
 	| pyramid-* \
 	| pyramid-* \
-	| romp-* | rs6000-* | rx-* \
+	| riscv32-* | riscv64-* \
+	| rl78-* | romp-* | rs6000-* | rx-* \
 	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
 	| sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
 	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
 	| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
 	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
 	| sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
 	| sparclite-* \
 	| sparclite-* \
-	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \
-	| tahoe-* | thumb-* \
+	| sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx*-* \
+	| tahoe-* \
 	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
 	| tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
-	| tile-* | tilegx-* \
+	| tile*-* \
 	| tron-* \
 	| tron-* \
 	| ubicom32-* \
 	| ubicom32-* \
-	| v850-* | v850e-* | vax-* \
+	| v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+	| vax-* \
+	| visium-* \
 	| we32k-* \
 	| we32k-* \
-	| x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \
+	| x86-* | x86_64-* | xc16x-* | xps100-* \
 	| xstormy16-* | xtensa*-* \
 	| xstormy16-* | xtensa*-* \
 	| ymp-* \
 	| ymp-* \
 	| z8k-* | z80-*)
 	| z8k-* | z80-*)
@@ -412,7 +472,7 @@ case $basic_machine in
 		basic_machine=a29k-amd
 		basic_machine=a29k-amd
 		os=-udi
 		os=-udi
 		;;
 		;;
-    	abacus)
+	abacus)
 		basic_machine=abacus-unknown
 		basic_machine=abacus-unknown
 		;;
 		;;
 	adobe68k)
 	adobe68k)
@@ -462,6 +522,9 @@ case $basic_machine in
 		basic_machine=i386-pc
 		basic_machine=i386-pc
 		os=-aros
 		os=-aros
 		;;
 		;;
+	asmjs)
+		basic_machine=asmjs-unknown
+		;;
 	aux)
 	aux)
 		basic_machine=m68k-apple
 		basic_machine=m68k-apple
 		os=-aux
 		os=-aux
@@ -482,11 +545,20 @@ case $basic_machine in
 		basic_machine=powerpc-ibm
 		basic_machine=powerpc-ibm
 		os=-cnk
 		os=-cnk
 		;;
 		;;
+	c54x-*)
+		basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c55x-*)
+		basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
+	c6x-*)
+		basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
 	c90)
 	c90)
 		basic_machine=c90-cray
 		basic_machine=c90-cray
 		os=-unicos
 		os=-unicos
 		;;
 		;;
-        cegcc)
+	cegcc)
 		basic_machine=arm-unknown
 		basic_machine=arm-unknown
 		os=-cegcc
 		os=-cegcc
 		;;
 		;;
@@ -518,7 +590,7 @@ case $basic_machine in
 		basic_machine=craynv-cray
 		basic_machine=craynv-cray
 		os=-unicosmp
 		os=-unicosmp
 		;;
 		;;
-	cr16)
+	cr16 | cr16-*)
 		basic_machine=cr16-unknown
 		basic_machine=cr16-unknown
 		os=-elf
 		os=-elf
 		;;
 		;;
@@ -573,6 +645,14 @@ case $basic_machine in
 		basic_machine=m68k-bull
 		basic_machine=m68k-bull
 		os=-sysv3
 		os=-sysv3
 		;;
 		;;
+	e500v[12])
+		basic_machine=powerpc-unknown
+		os=$os"spe"
+		;;
+	e500v[12]-*)
+		basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+		os=$os"spe"
+		;;
 	ebmon29k)
 	ebmon29k)
 		basic_machine=a29k-amd
 		basic_machine=a29k-amd
 		os=-ebmon
 		os=-ebmon
@@ -676,7 +756,6 @@ case $basic_machine in
 	i370-ibm* | ibm*)
 	i370-ibm* | ibm*)
 		basic_machine=i370-ibm
 		basic_machine=i370-ibm
 		;;
 		;;
-# I'm not sure what "Sysv32" means.  Should this be sysv3.2?
 	i*86v32)
 	i*86v32)
 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
 		basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
 		os=-sysv32
 		os=-sysv32
@@ -715,6 +794,9 @@ case $basic_machine in
 		basic_machine=m68k-isi
 		basic_machine=m68k-isi
 		os=-sysv
 		os=-sysv
 		;;
 		;;
+	leon-*|leon[3-9]-*)
+		basic_machine=sparc-`echo $basic_machine | sed 's/-.*//'`
+		;;
 	m68knommu)
 	m68knommu)
 		basic_machine=m68k-unknown
 		basic_machine=m68k-unknown
 		os=-linux
 		os=-linux
@@ -734,11 +816,15 @@ case $basic_machine in
 		basic_machine=ns32k-utek
 		basic_machine=ns32k-utek
 		os=-sysv
 		os=-sysv
 		;;
 		;;
-        microblaze)
+	microblaze*)
 		basic_machine=microblaze-xilinx
 		basic_machine=microblaze-xilinx
 		;;
 		;;
+	mingw64)
+		basic_machine=x86_64-pc
+		os=-mingw64
+		;;
 	mingw32)
 	mingw32)
-		basic_machine=i386-pc
+		basic_machine=i686-pc
 		os=-mingw32
 		os=-mingw32
 		;;
 		;;
 	mingw32ce)
 	mingw32ce)
@@ -766,6 +852,10 @@ case $basic_machine in
 		basic_machine=powerpc-unknown
 		basic_machine=powerpc-unknown
 		os=-morphos
 		os=-morphos
 		;;
 		;;
+	moxiebox)
+		basic_machine=moxie-unknown
+		os=-moxiebox
+		;;
 	msdos)
 	msdos)
 		basic_machine=i386-pc
 		basic_machine=i386-pc
 		os=-msdos
 		os=-msdos
@@ -773,10 +863,18 @@ case $basic_machine in
 	ms1-*)
 	ms1-*)
 		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
 		basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
 		;;
 		;;
+	msys)
+		basic_machine=i686-pc
+		os=-msys
+		;;
 	mvs)
 	mvs)
 		basic_machine=i370-ibm
 		basic_machine=i370-ibm
 		os=-mvs
 		os=-mvs
 		;;
 		;;
+	nacl)
+		basic_machine=le32-unknown
+		os=-nacl
+		;;
 	ncr3000)
 	ncr3000)
 		basic_machine=i486-ncr
 		basic_machine=i486-ncr
 		os=-sysv4
 		os=-sysv4
@@ -841,6 +939,12 @@ case $basic_machine in
 	np1)
 	np1)
 		basic_machine=np1-gould
 		basic_machine=np1-gould
 		;;
 		;;
+	neo-tandem)
+		basic_machine=neo-tandem
+		;;
+	nse-tandem)
+		basic_machine=nse-tandem
+		;;
 	nsr-tandem)
 	nsr-tandem)
 		basic_machine=nsr-tandem
 		basic_machine=nsr-tandem
 		;;
 		;;
@@ -923,11 +1027,12 @@ case $basic_machine in
 		;;
 		;;
 	power)	basic_machine=power-ibm
 	power)	basic_machine=power-ibm
 		;;
 		;;
-	ppc)	basic_machine=powerpc-unknown
+	ppc | ppcbe)	basic_machine=powerpc-unknown
 		;;
 		;;
-	ppc-*)	basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+	ppc-* | ppcbe-*)
+		basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
 		;;
 		;;
-	ppcle | powerpclittle | ppc-le | powerpc-little)
+	ppcle | powerpclittle)
 		basic_machine=powerpcle-unknown
 		basic_machine=powerpcle-unknown
 		;;
 		;;
 	ppcle-* | powerpclittle-*)
 	ppcle-* | powerpclittle-*)
@@ -937,7 +1042,7 @@ case $basic_machine in
 		;;
 		;;
 	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
 	ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
 		;;
 		;;
-	ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+	ppc64le | powerpc64little)
 		basic_machine=powerpc64le-unknown
 		basic_machine=powerpc64le-unknown
 		;;
 		;;
 	ppc64le-* | powerpc64little-*)
 	ppc64le-* | powerpc64little-*)
@@ -950,7 +1055,11 @@ case $basic_machine in
 		basic_machine=i586-unknown
 		basic_machine=i586-unknown
 		os=-pw32
 		os=-pw32
 		;;
 		;;
-	rdos)
+	rdos | rdos64)
+		basic_machine=x86_64-pc
+		os=-rdos
+		;;
+	rdos32)
 		basic_machine=i386-pc
 		basic_machine=i386-pc
 		os=-rdos
 		os=-rdos
 		;;
 		;;
@@ -1019,6 +1128,9 @@ case $basic_machine in
 		basic_machine=i860-stratus
 		basic_machine=i860-stratus
 		os=-sysv4
 		os=-sysv4
 		;;
 		;;
+	strongarm-* | thumb-*)
+		basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+		;;
 	sun2)
 	sun2)
 		basic_machine=m68000-sun
 		basic_machine=m68000-sun
 		;;
 		;;
@@ -1075,25 +1187,8 @@ case $basic_machine in
 		basic_machine=t90-cray
 		basic_machine=t90-cray
 		os=-unicos
 		os=-unicos
 		;;
 		;;
-	tic54x | c54x*)
-		basic_machine=tic54x-unknown
-		os=-coff
-		;;
-	tic55x | c55x*)
-		basic_machine=tic55x-unknown
-		os=-coff
-		;;
-	tic6x | c6x*)
-		basic_machine=tic6x-unknown
-		os=-coff
-		;;
-        # This must be matched before tile*.
-        tilegx*)
-		basic_machine=tilegx-unknown
-		os=-linux-gnu
-		;;
 	tile*)
 	tile*)
-		basic_machine=tile-unknown
+		basic_machine=$basic_machine-unknown
 		os=-linux-gnu
 		os=-linux-gnu
 		;;
 		;;
 	tx39)
 	tx39)
@@ -1163,6 +1258,9 @@ case $basic_machine in
 	xps | xps100)
 	xps | xps100)
 		basic_machine=xps100-honeywell
 		basic_machine=xps100-honeywell
 		;;
 		;;
+	xscale-* | xscalee[bl]-*)
+		basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+		;;
 	ymp)
 	ymp)
 		basic_machine=ymp-cray
 		basic_machine=ymp-cray
 		os=-unicos
 		os=-unicos
@@ -1260,11 +1358,11 @@ esac
 if [ x"$os" != x"" ]
 if [ x"$os" != x"" ]
 then
 then
 case $os in
 case $os in
-        # First match some system type aliases
-        # that might get confused with valid system types.
+	# First match some system type aliases
+	# that might get confused with valid system types.
 	# -solaris* is a basic system type, with this one exception.
 	# -solaris* is a basic system type, with this one exception.
-        -auroraux)
-	        os=-auroraux
+	-auroraux)
+		os=-auroraux
 		;;
 		;;
 	-solaris1 | -solaris1.*)
 	-solaris1 | -solaris1.*)
 		os=`echo $os | sed -e 's|solaris1|sunos4|'`
 		os=`echo $os | sed -e 's|solaris1|sunos4|'`
@@ -1288,28 +1386,30 @@ case $os in
 	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
 	-gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
 	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
 	      | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
 	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
 	      | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
-	      | -sym* | -kopensolaris* \
+	      | -sym* | -kopensolaris* | -plan9* \
 	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
 	      | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
-	      | -aos* | -aros* \
+	      | -aos* | -aros* | -cloudabi* | -sortix* \
 	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
 	      | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
 	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
 	      | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
 	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
 	      | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
-	      | -openbsd* | -solidbsd* \
+	      | -bitrig* | -openbsd* | -solidbsd* | -libertybsd* \
 	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
 	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
 	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
 	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
 	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
 	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
 	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
 	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
 	      | -chorusos* | -chorusrdb* | -cegcc* \
 	      | -chorusos* | -chorusrdb* | -cegcc* \
-	      | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
-	      | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \
-	      | -uxpv* | -beos* | -mpeix* | -udk* \
+	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+	      | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+	      | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+	      | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
 	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
 	      | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
 	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
 	      | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
 	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
 	      | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
 	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
 	      | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
 	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
 	      | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
 	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
 	      | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
-	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es*)
+	      | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* \
+	      | -onefs* | -tirtos* | -phoenix* | -fuchsia*)
 	# Remember, each alternative MUST END IN *, to match a version number.
 	# Remember, each alternative MUST END IN *, to match a version number.
 		;;
 		;;
 	-qnx*)
 	-qnx*)
@@ -1348,7 +1448,7 @@ case $os in
 	-opened*)
 	-opened*)
 		os=-openedition
 		os=-openedition
 		;;
 		;;
-        -os400*)
+	-os400*)
 		os=-os400
 		os=-os400
 		;;
 		;;
 	-wince*)
 	-wince*)
@@ -1397,7 +1497,7 @@ case $os in
 	-sinix*)
 	-sinix*)
 		os=-sysv4
 		os=-sysv4
 		;;
 		;;
-        -tpf*)
+	-tpf*)
 		os=-tpf
 		os=-tpf
 		;;
 		;;
 	-triton*)
 	-triton*)
@@ -1433,17 +1533,16 @@ case $os in
 	-aros*)
 	-aros*)
 		os=-aros
 		os=-aros
 		;;
 		;;
-	-kaos*)
-		os=-kaos
-		;;
 	-zvmoe)
 	-zvmoe)
 		os=-zvmoe
 		os=-zvmoe
 		;;
 		;;
 	-dicos*)
 	-dicos*)
 		os=-dicos
 		os=-dicos
 		;;
 		;;
-        -nacl*)
-	        ;;
+	-nacl*)
+		;;
+	-ios)
+		;;
 	-none)
 	-none)
 		;;
 		;;
 	*)
 	*)
@@ -1466,10 +1565,10 @@ else
 # system, and we'll never get to this point.
 # system, and we'll never get to this point.
 
 
 case $basic_machine in
 case $basic_machine in
-        score-*)
+	score-*)
 		os=-elf
 		os=-elf
 		;;
 		;;
-        spu-*)
+	spu-*)
 		os=-elf
 		os=-elf
 		;;
 		;;
 	*-acorn)
 	*-acorn)
@@ -1481,8 +1580,23 @@ case $basic_machine in
 	arm*-semi)
 	arm*-semi)
 		os=-aout
 		os=-aout
 		;;
 		;;
-        c4x-* | tic4x-*)
-        	os=-coff
+	c4x-* | tic4x-*)
+		os=-coff
+		;;
+	c8051-*)
+		os=-elf
+		;;
+	hexagon-*)
+		os=-elf
+		;;
+	tic54x-*)
+		os=-coff
+		;;
+	tic55x-*)
+		os=-coff
+		;;
+	tic6x-*)
+		os=-coff
 		;;
 		;;
 	# This must come before the *-dec entry.
 	# This must come before the *-dec entry.
 	pdp10-*)
 	pdp10-*)
@@ -1502,14 +1616,11 @@ case $basic_machine in
 		;;
 		;;
 	m68000-sun)
 	m68000-sun)
 		os=-sunos3
 		os=-sunos3
-		# This also exists in the configure program, but was not the
-		# default.
-		# os=-sunos4
 		;;
 		;;
 	m68*-cisco)
 	m68*-cisco)
 		os=-aout
 		os=-aout
 		;;
 		;;
-        mep-*)
+	mep-*)
 		os=-elf
 		os=-elf
 		;;
 		;;
 	mips*-cisco)
 	mips*-cisco)
@@ -1536,7 +1647,7 @@ case $basic_machine in
 	*-ibm)
 	*-ibm)
 		os=-aix
 		os=-aix
 		;;
 		;;
-    	*-knuth)
+	*-knuth)
 		os=-mmixware
 		os=-mmixware
 		;;
 		;;
 	*-wec)
 	*-wec)

+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/array → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/array


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/array.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/array.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/binarystring → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/binarystring


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/binarystring.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/binarystring.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/blob → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/blob


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/blob.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/blob.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/composite → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/composite


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/composite.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/composite.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/config-public-compiler.h → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/config-public-compiler.h


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/connection → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/connection


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/connection.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/connection.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/cursor → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/cursor


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/cursor.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/cursor.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/dbtransaction → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/dbtransaction


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/dbtransaction.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/dbtransaction.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/errorhandler → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/errorhandler


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/errorhandler.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/errorhandler.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/except → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/except


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/except.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/except.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/field → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/field


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/field.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/field.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/internal/array-composite.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/array-composite.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/internal/callgate.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/callgate.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/internal/concat.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/concat.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/internal/conversions.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/conversions.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/internal/encoding_group.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/encoding_group.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/internal/encodings.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/encodings.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/internal/gates/connection-errorhandler.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/gates/connection-errorhandler.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/internal/gates/connection-largeobject.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/gates/connection-largeobject.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/internal/gates/connection-notification_receiver.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/gates/connection-notification_receiver.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/internal/gates/connection-pipeline.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/gates/connection-pipeline.hxx


+ 0 - 0
ext/libpqxx-7.7.3/install/ubuntu22.04/include/pqxx/internal/gates/connection-sql_cursor.hxx → ext/libpqxx-7.7.3/install/ubuntu22.04/amd64/include/pqxx/internal/gates/connection-sql_cursor.hxx


Некоторые файлы не были показаны из-за большого количества измененных файлов