- Remove testcontainers/testcontainers-modules dev-dependencies, orphaned
since the rust-based pubsub removal (0f6378359). This drops tokio-tar
0.3.1 (CVE-2025-62518, PAX header desynchronization) and the rest of
the bollard/docker graph from the lockfile. Resolves alert #67.
- Update serde_with 3.20.0 -> 3.21.0 (KeyValueMap serialization panic
on empty sequence/map entries). Resolves alert #68.
Template was looking for {{networkId}} but that hadn't been populated
yet in the case where the IdP returned an error. This caused the
template parsing to crash and return its own error, disguising the error
from the IdP
* Brewfile for homebrew dependencies on macos
* Pull & build google-cloud-cpp/otel via bootstrap script rather than
keeping it all in the ext/ subfolder.
* Update controller CI build with new steps
writePending() did a synchronous ReadRow per queued node to avoid
rewriting unchanged os/arch/version. With thousands of check-ins per
cycle that's thousands of sequential round-trips every 10s, and the read
was nearly pointless since last_seen and the IP cell are written every
cycle anyway.
Replace it with an in-process cache of the last-written node_info per
row (keyed by a 64-bit hash of the row key). node_info is emitted only
when changed, new, or past its refresh window; check_in is still written
every cycle. Failed rows are dropped from the cache so they're rewritten
next cycle, and stale entries are evicted (24h TTL). Net result: one
BulkApply per cycle, no read RPCs.
- Default enableBroadcast to true on load (initializeNetworks and _getNetwork) to match DB::initNetwork. Networks whose JSONB lacks the field now get broadcast on instead of off, which is the documented ZeroTier default.
- Stop overwriting networks_ctl.frontend on every UPDATE. It should remain whatever was set at INSERT. The early-exit guard already prevents cross-frontend writes from applying, so dropping the SET preserves correctness. Members are unaffected — they source frontend from the network row, not the change payload.
- Add enableBroadcast, creationTime, and revision to PubSubListener's network toJson. The protobuf carries them, but the listener was dropping them on inbound, which caused revision to reset on every PubSub-delivered network update.
- Rename member version keys to vMajor/vMinor/vRev/vProto in both PubSubListener (incoming) and PubSubWriter (outgoing). CentralDB, EmbeddedNetworkController, and the rest of the codebase already use these names; the listener/writer were the only sites using versionMajor/Minor/Rev/Protocol, so member version info was being silently dropped through PubSub in both directions.
- Pass newMember by const reference in ControllerChangeNotifier::notifyMemberChange to match notifyNetworkChange. Avoids a full JSON copy on every member notify.
- Remove duplicate nlohmann::json::parse call in RedisNetworkListener.
ssoConfig checked wrong variable
DNS missing-branch wrote to input not output
SSO fields renamed to sso* and nested under ssoConfig (across CentralDB, DB defaults, migration_models)
Member identity populated into the right field; address = memberId
noAutoAssignIPs → noAutoAssignIps casing
Member version columns now SELECTed + populated (both sites)
removeTraceLevel typo in DB.cpp defaults
8. eraseMember uninitialized tmp2 — member deletes now actually delete
9. Connection leak on continue in both commit branches
10. Unsafe (uint64_t)config["revision"] cast → OSUtils::jsonInt
11. target = "NULL" literal text → std::optional<std::string> for real SQL NULL
~13 unsafe direct json→string casts → OSUtils::jsonString; dead vars removed from save(); change_source blocks use is_string() checks.
Heartbeat zadd literal "controllerId" → variable
Network revision double-increment removed
PubSub notifier now sees actual old state (DB query moved before INSERT in both branches)
_delete_network reads config["id"] instead of config["nwid"]
ip_assignments empty-string guards added at both sites (also closes G)
ensure last_modified is set on every write to networks & members
The 10-second session.cancel() loop raced with in-flight acks — when
cancel fired while the GCP client was processing messages, acks were
lost before reaching the server. With message ordering enabled, an
unacked message blocks all subsequent messages on that ordering key,
causing silent stalls with no error output.
Two fixes:
- Replace the cancel/reconnect timer with a blocking session.get(),
storing the session future so the destructor can cancel on shutdown.
- Always ack messages even when onNotification fails — permanent errors
(bad protobuf, missing fields) will never succeed on retry and would
otherwise poison the ordering key indefinitely.
Allow controllers to advertise which central version (cv1, cv2, or all)
they are assigned to handle via a new configurable field. The value is
persisted to the database on each heartbeat and validated at startup
against the DB CHECK constraint.
Publish CTL_NONCE_UPDATE to PubSub when nonces are created or reused in
getSSOAuthInfo(), with the network's frontend as a message attribute so
only the correct CV frontend receives it. Listen for ZT1_AUTH_UPDATE
messages and update sso_expiry.authentication_expiry_time accordingly,
with a network existence check before applying.
- Add sso_send_topic/sso_recv_topic to PubSubConfig
- Add PubSubWriter::publishSSONonceUpdate() with frontend param
- Add PubSubSSOListener class for inbound auth updates
- Rename CV1_AUTH_UPDATE to ZT1_AUTH_UPDATE in sso.proto
- Fix pre-existing connection pool leak in getSSOAuthInfo() catch block
Required to get the list of configs for a particular org that the controller has. Named it `linked_id` rather than `org_id` since we don't know what it will be linked to in CV2
Also for pubsub trips back to CV1/CV2, rather than having 2 queues for each service (networks & members), theres now only a single queue for each change type, and `frontend = (cv1|cv2)` attribute is set on the message for filtering.
Muuuuch easier to use external dependencies now
Also tried out conan and vcpkg. Ran into dependency issues when solving for packages to install with conan.
vcpkg is just obtuse as all hell to install and not easy to integrate
PubSub allows us to do schema validation, however it only allows one top level message at a time. Move other sub-message declarations under the main message declaration so that we can enable schema validation in the pubsub stream directly
{"name":"linux-controller-release","inherits":"linux-base","displayName":"Linux Central Controller (Release)","cacheVariables":{"ZT1_CENTRAL_CONTROLLER":"ON"}},
{"name":"linux-controller-debug","inherits":"linux-base","displayName":"Linux Central Controller (Debug)","cacheVariables":{"ZT1_CENTRAL_CONTROLLER":"ON","CMAKE_BUILD_TYPE":"Debug"}},
{"name":"linux-free-release","inherits":"linux-base","displayName":"Linux daemon, free / no controller (Release)","cacheVariables":{"ZT_NONFREE":"OFF"}},
{"name":"linux-free-debug","inherits":"linux-base","displayName":"Linux daemon, free / no controller (Debug)","cacheVariables":{"ZT_NONFREE":"OFF","CMAKE_BUILD_TYPE":"Debug"}},
{"name":"macos-controller-release","inherits":"macos-base","displayName":"macOS Central Controller (Release)","cacheVariables":{"ZT1_CENTRAL_CONTROLLER":"ON"}},
{"name":"macos-controller-debug","inherits":"macos-base","displayName":"macOS Central Controller (Debug)","cacheVariables":{"ZT1_CENTRAL_CONTROLLER":"ON","CMAKE_BUILD_TYPE":"Debug"}},
{"name":"macos-free-release","inherits":"macos-base","displayName":"macOS daemon, free / no controller (Release)","cacheVariables":{"ZT_NONFREE":"OFF"}},
{"name":"macos-free-debug","inherits":"macos-base","displayName":"macOS daemon, free / no controller (Debug)","cacheVariables":{"ZT_NONFREE":"OFF","CMAKE_BUILD_TYPE":"Debug"}},
* Fixed line endings for the zttap300.inf for the Windows ARM x64 install.
* Internal updates to the central controller (CV1) including schema changes and a multi-architecture Docker build pipeline.
* Increased `ZT_MAX_NETWORK_SPECIALISTS` from 256 to 512 to accommodate users with large networks that exceeded the previous limit. The network config dictionary capacity was raised correspondingly.
* Resolved intermittent multi-minute delays when leaving one network and joining another under Windows.
* Compiler warning cleanup across the codebase, covering GCC 14, Clang 18, and Clang 21.
## 2025-12-22 -- Version 1.16.1
* Metrics collection is now disabled by default. It can be enabled via the `enableMetrics` setting in `local.conf`.
* Fix for an issue where metrics were not being recorded while running in daemon mode.
* Fix debug dumpfile being written to the root directory.
The binary is `build/zerotier-one`. (On macOS, append the Homebrew prefixes to
`CMAKE_PREFIX_PATH` if your dependencies come from Homebrew, as the presets do.)
### Testing
Typing `make selftest` will build a *zerotier-selftest* binary which unit tests various internals and reports on a few aspects of the build environment. It's a good idea to try this on novel platforms or architectures.
# Dockerfile for building ZeroTier Central Controllers
FROMdebian:bookworm
RUN apt update && apt upgrade -y
RUN apt -y install \
build-essential \
pkg-config \
bash \
clang \
libjemalloc2 \
libjemalloc-dev \
libpq5 \
libpq-dev \
openssl \
libssl-dev \
postgresql-client \
postgresql-client-common \
curl \
libcurl4-openssl-dev \
google-perftools \
libgoogle-perftools-dev \
protobuf-compiler \
protobuf-compiler-grpc \
protobuf-c-compiler \
grpc-proto \
libgrpc++1.51 \
libgrpc++-dev \
libgrpc-dev \
libgrpc29 \
cmake \
git
RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
Loaded 20 of 1425 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.