From 5ce3d1e7a1bf8d8fadc4fc56c4ec46be0a9e1bbe Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Fri, 13 Sep 2024 09:46:36 -0700 Subject: [PATCH 01/13] Fix for low-bandwidth mode --- service/OneService.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/service/OneService.cpp b/service/OneService.cpp index d9f63334..594ff02d 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -2599,6 +2599,7 @@ public: fprintf(stderr,"WARNING: using manually-specified secondary and/or tertiary ports. This can cause NAT issues." ZT_EOL_S); } _portMappingEnabled = OSUtils::jsonBool(settings["portMappingEnabled"],true); + _node->setLowBandwidthMode(OSUtils::jsonBool(settings["lowBandwidthMode"],false)); #if defined(__LINUX__) || defined(__FreeBSD__) _multicoreEnabled = OSUtils::jsonBool(settings["multicoreEnabled"],false); _concurrency = OSUtils::jsonInt(settings["concurrency"],1); From d34481d8303e50688e5943df407df58221e6781c Mon Sep 17 00:00:00 2001 From: Joseph Henry Date: Tue, 17 Sep 2024 11:04:01 -0700 Subject: [PATCH 02/13] Fix build error for BSD tap driver --- osdep/BSDEthernetTap.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osdep/BSDEthernetTap.cpp b/osdep/BSDEthernetTap.cpp index 1a240c1a..d4dbf7f6 100644 --- a/osdep/BSDEthernetTap.cpp +++ b/osdep/BSDEthernetTap.cpp @@ -431,10 +431,12 @@ void BSDEthernetTap::threadMain() // constructing itself. Thread::sleep(500); - for (unsigned int i = 0; i < _concurrency; ++i) { - _rxThreads.push_back(std::thread([this, i, _pinning] { + bool pinning = _pinning; - if (_pinning) { + for (unsigned int i = 0; i < _concurrency; ++i) { + _rxThreads.push_back(std::thread([this, i, pinning] { + + if (pinning) { int pinCore = i % _concurrency; fprintf(stderr, "Pinning thread %d to core %d\n", i, pinCore); pthread_t self = pthread_self(); From 5799d9a15b216eb7b1e9e47dbf5bf5a55de3ac1e Mon Sep 17 00:00:00 2001 From: sh1ve <63954557+sh1ve@users.noreply.github.com> Date: Sun, 29 Sep 2024 23:49:38 +0800 Subject: [PATCH 03/13] Fix build error under certain character sets Add some padding after non-ASCII comment --- .../core/include/prometheus/client_metric.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ext/prometheus-cpp-lite-1.0/core/include/prometheus/client_metric.h b/ext/prometheus-cpp-lite-1.0/core/include/prometheus/client_metric.h index 39acff78..10e12ff7 100644 --- a/ext/prometheus-cpp-lite-1.0/core/include/prometheus/client_metric.h +++ b/ext/prometheus-cpp-lite-1.0/core/include/prometheus/client_metric.h @@ -8,6 +8,7 @@ namespace prometheus { // , + struct ClientMetric { // Label From e1c72e6d516627f1fa342290382768ff47594860 Mon Sep 17 00:00:00 2001 From: Grant Limberg Date: Wed, 2 Oct 2024 12:59:21 -0700 Subject: [PATCH 04/13] add `make docker-release` command & update dockerfile --- Dockerfile.release | 6 +++--- make-mac.mk | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Dockerfile.release b/Dockerfile.release index 87ef6534..2a289cea 100644 --- a/Dockerfile.release +++ b/Dockerfile.release @@ -1,6 +1,6 @@ # vim: ft=dockerfile -FROM debian:bullseye +FROM debian:bookworm ARG VERSION @@ -9,9 +9,9 @@ RUN mkdir -p /usr/share/zerotier && \ curl -o /usr/share/zerotier/tmp.asc "https://download.zerotier.com/contact%40zerotier.com.gpg" && \ gpg --no-default-keyring --keyring /usr/share/zerotier/zerotier.gpg --import /usr/share/zerotier/tmp.asc && \ rm -f /usr/share/zerotier/tmp.asc && \ - echo "deb [signed-by=/usr/share/zerotier/zerotier.gpg] http://download.zerotier.com/debian/bullseye bullseye main" > /etc/apt/sources.list.d/zerotier.list + echo "deb [signed-by=/usr/share/zerotier/zerotier.gpg] http://download.zerotier.com/debian/bookworm bookworm main" > /etc/apt/sources.list.d/zerotier.list -RUN apt-get update -qq && apt-get install zerotier-one=${VERSION} curl iproute2 net-tools iputils-ping openssl libssl1.1 -y +RUN apt-get update -qq && apt-get install zerotier-one=${VERSION} curl iproute2 net-tools iputils-ping openssl libssl3 -y RUN rm -rf /var/lib/zerotier-one COPY entrypoint.sh.release /entrypoint.sh diff --git a/make-mac.mk b/make-mac.mk index 7af200ad..e10f9622 100644 --- a/make-mac.mk +++ b/make-mac.mk @@ -194,6 +194,9 @@ controller-run: _buildx FORCE central-controller-docker: _buildx FORCE docker buildx build --platform linux/arm64,linux/amd64 --no-cache -t registry.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} -f ext/central-controller-docker/Dockerfile --build-arg git_branch=$(shell git name-rev --name-only HEAD) . --push @echo Image: registry.zerotier.com/zerotier-central/ztcentral-controller:${TIMESTAMP} + +docker-release: _buildx + docker buildx build --platform linux/386,linux/amd64,linux/arm/v7,linux/arm64,linux/mips64le,linux/ppc64le,linux/s390x -t zerotier/zerotier:${RELEASE_DOCKER_TAG} -t zerotier/zerotier:latest --build-arg VERSION=${RELEASE_VERSION} -f Dockerfile.release . --push clean: rm -rf MacEthernetTapAgent *.dSYM build-* *.a *.pkg *.dmg *.o node/*.o controller/*.o service/*.o osdep/*.o ext/http-parser/*.o $(CORE_OBJS) $(ONE_OBJS) zerotier-one zerotier-idtool zerotier-selftest zerotier-cli zerotier doc/node_modules zt1_update_$(ZT_BUILD_PLATFORM)_$(ZT_BUILD_ARCHITECTURE)_* rustybits/target/ From 7dca7fac112522029c6f50cbf820a687dcc58f81 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Oct 2024 11:03:18 -0400 Subject: [PATCH 05/13] Bump Rust library versions. --- rustybits/Cargo.lock | 503 +++++++++++++++++++++---------------------- 1 file changed, 251 insertions(+), 252 deletions(-) diff --git a/rustybits/Cargo.lock b/rustybits/Cargo.lock index 8ad2b56c..dc5cb17f 100644 --- a/rustybits/Cargo.lock +++ b/rustybits/Cargo.lock @@ -4,9 +4,9 @@ version = 3 [[package]] name = "addr2line" -version = "0.24.1" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5fb1d8e4442bd405fdfd1dacb42792696b0cf9cb15882e5d097b742a676d375" +checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" dependencies = [ "gimli", ] @@ -17,18 +17,6 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627" -[[package]] -name = "ahash" -version = "0.8.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" -dependencies = [ - "cfg-if", - "once_cell", - "version_check", - "zerocopy", -] - [[package]] name = "aho-corasick" version = "1.1.3" @@ -76,15 +64,15 @@ checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" [[package]] name = "anyhow" -version = "1.0.87" +version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f00e1f6e58a40e807377c75c6a7f97bf9044fab57816f2414e6f5f4499d7b8" +checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" [[package]] name = "async-stream" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" dependencies = [ "async-stream-impl", "futures-core", @@ -93,24 +81,24 @@ dependencies = [ [[package]] name = "async-stream-impl" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] name = "async-trait" -version = "0.1.82" +version = "0.1.83" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27b8a3a6e1a44fa4c8baf1f653e4172e81486d4941f2237e20dc2d0cf4ddff1" +checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -132,15 +120,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.3.0" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" -version = "0.7.5" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a6c9af12842a67734c9a2e355436e5d03b22383ed60cf13cd0c18fbfe3dcbcf" +checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" dependencies = [ "async-trait", "axum-core", @@ -158,16 +146,16 @@ dependencies = [ "rustversion", "serde", "sync_wrapper 1.0.1", - "tower 0.4.13", + "tower 0.5.1", "tower-layer", "tower-service", ] [[package]] name = "axum-core" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +checksum = "09f2bd6146b97ae3359fa0cc6d6b376d9539582c7b4220f041a33ec24c226199" dependencies = [ "async-trait", "bytes", @@ -178,7 +166,7 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 0.1.2", + "sync_wrapper 1.0.1", "tower-layer", "tower-service", ] @@ -274,9 +262,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8318a53db07bb3f8dca91a600466bdb3f2eaadeedfdbcf02e1accbad9271ba50" +checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" [[package]] name = "cbindgen" @@ -299,9 +287,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.1.18" +version = "1.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62ac837cdb5cb22e10a256099b4fc502b1dfe560cb282963a974d7abd80e476" +checksum = "c2e7962b54006dcfcc61cb72735f4d89bb97061dd6a7ed882ec6b8ee53714c6f" dependencies = [ "shlex", ] @@ -443,7 +431,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -467,7 +455,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -478,7 +466,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -531,33 +519,33 @@ dependencies = [ [[package]] name = "derive_builder" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd33f37ee6a119146a1781d3356a7c26028f83d779b2e04ecd45fdc75c76877b" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" dependencies = [ "derive_builder_macro", ] [[package]] name = "derive_builder_core" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7431fa049613920234f22c47fdc33e6cf3ee83067091ea4277a3f8c4587aae38" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] name = "derive_builder_macro" -version = "0.20.1" +version = "0.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4abae7035bf79b9877b779505d8cf3749285b80c43941eda66604841889451dc" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" dependencies = [ "derive_builder_core", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -577,7 +565,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", "unicode-xid", ] @@ -696,7 +684,7 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -708,7 +696,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -771,6 +759,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81ec6369c545a7d40e4589b5597581fa1c441fe1cce96dd1de43159910a36a2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -803,9 +797,9 @@ checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" [[package]] name = "futures" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" dependencies = [ "futures-channel", "futures-core", @@ -818,9 +812,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" dependencies = [ "futures-core", "futures-sink", @@ -828,15 +822,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" dependencies = [ "futures-core", "futures-task", @@ -845,19 +839,19 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -873,15 +867,15 @@ dependencies = [ [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" [[package]] name = "futures-timer" @@ -891,9 +885,9 @@ checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" dependencies = [ "futures-channel", "futures-core", @@ -933,9 +927,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.31.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32085ea23f3234fc7846555e85283ba4de91e21016dc0455a16286d87a292d64" +checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" [[package]] name = "governor" @@ -980,7 +974,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.5.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -999,7 +993,7 @@ dependencies = [ "futures-core", "futures-sink", "http 1.1.0", - "indexmap 2.5.0", + "indexmap 2.6.0", "slab", "tokio", "tokio-util", @@ -1017,9 +1011,16 @@ name = "hashbrown" version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e087f84d4f86bf4b218b927129862374b72199ae7d8657835f1e89000eea4fb" dependencies = [ - "ahash", "allocator-api2", + "equivalent", + "foldhash", ] [[package]] @@ -1134,9 +1135,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.4" +version = "1.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcc0b4a115bf80b728eb8ea024ad5bd707b615bfed49e0665b6e0f86fd082d9" +checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" [[package]] name = "httpdate" @@ -1146,9 +1147,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "0.14.30" +version = "0.14.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a152ddd61dfaec7273fe8419ab357f33aee0d914c5f4efbf0d96fa749eea5ec9" +checksum = "8c08302e8fa335b151b788c775ff56e7a03ae64ff85c548ee820fecb70356e85" dependencies = [ "bytes", "futures-channel", @@ -1170,9 +1171,9 @@ dependencies = [ [[package]] name = "hyper" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50dfd22e0e76d0f662d429a5f80fcaf3855009297eab6a0a9f8543834744ba05" +checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" dependencies = [ "bytes", "futures-channel", @@ -1195,7 +1196,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3203a961e5c83b6f5498933e78b6b263e208c197b63e9c6c53cc82ffd3f63793" dependencies = [ - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", "pin-project-lite", "tokio", @@ -1209,7 +1210,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905" dependencies = [ "bytes", - "hyper 0.14.30", + "hyper 0.14.31", "native-tls", "tokio", "tokio-native-tls", @@ -1217,29 +1218,28 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da62f120a8a37763efb0cf8fdf264b884c7b8b9ac8660b900c8661030c00e6ba" +checksum = "41296eb09f183ac68eec06e03cdbea2e759633d4067b2f6552fc2e009bcad08b" dependencies = [ "bytes", "futures-channel", "futures-util", "http 1.1.0", "http-body 1.0.1", - "hyper 1.4.1", + "hyper 1.5.0", "pin-project-lite", "socket2", "tokio", - "tower 0.4.13", "tower-service", "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.60" +version = "0.1.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +checksum = "235e081f3925a06703c2d0117ea8b91f042756fd6e7a6e5d901e8ca1a996b220" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -1287,12 +1287,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68b900aa2f7301e21c36462b170ee99994de34dff39a4a6a528e80e7376d07e5" +checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.14.5", + "hashbrown 0.15.0", "serde", ] @@ -1313,9 +1313,9 @@ checksum = "f958d3d68f4167080a18141e10381e7634563984a537f2a49a30fd8e53ac5767" [[package]] name = "ipnet" -version = "2.10.0" +version = "2.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "187674a687eed5fe42285b40c6291f9a01517d415fad1c3cbc6a9f778af7fcd4" +checksum = "ddc24109865250148c2e0f3d25d4f0f479571723792d3802153c60922a4fb708" [[package]] name = "itertools" @@ -1343,9 +1343,9 @@ checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "js-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" dependencies = [ "wasm-bindgen", ] @@ -1375,9 +1375,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.158" +version = "0.2.161" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" [[package]] name = "libm" @@ -1409,11 +1409,11 @@ checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37ee39891760e7d94734f6f63fedc29a2e4a152f836120753a72503f09fcf904" +checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.14.5", + "hashbrown 0.15.0", ] [[package]] @@ -1487,7 +1487,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -1619,18 +1619,18 @@ dependencies = [ [[package]] name = "object" -version = "0.36.4" +version = "0.36.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "084f1a5821ac4c651660a94a7153d27ac9d8a53736203f58b31945ded098070a" +checksum = "aedf0a2d09c573ed1d8d85b30c119153926a2b36dce0ab28322c09a117a4683e" dependencies = [ "memchr", ] [[package]] name = "once_cell" -version = "1.19.0" +version = "1.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" [[package]] name = "openidconnect" @@ -1666,9 +1666,9 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.66" +version = "0.10.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9529f4786b70a3e8c61e11179af17ab6188ad8d0ded78c5529441ed39d4bd9c1" +checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" dependencies = [ "bitflags 2.6.0", "cfg-if", @@ -1687,7 +1687,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -1698,9 +1698,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-sys" -version = "0.9.103" +version = "0.9.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f9e8deee91df40a943c71b917e5874b951d32a802526c85721ce3b776c929d6" +checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" dependencies = [ "cc", "libc", @@ -1806,7 +1806,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b4c5cc86750666a3ed20bdaf5ca2a0344f9c67674cae0515bec2da16fbaa47db" dependencies = [ "fixedbitset", - "indexmap 2.5.0", + "indexmap 2.6.0", ] [[package]] @@ -1820,22 +1820,22 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" +checksum = "baf123a161dde1e524adf36f90bc5d8d3462824a9c43553ad07a8183161189ec" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.5" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" +checksum = "a4502d8515ca9f32f1fb543d987f63d95a14934883db45bdb48060b6b69257f8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -1873,15 +1873,15 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.30" +version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" +checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" [[package]] name = "portable-atomic" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da544ee218f0d287a911e9c99a39a8c9bc8fcad3cb8db5959940044ecfc67265" +checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" [[package]] name = "powerfmt" @@ -1926,12 +1926,12 @@ dependencies = [ [[package]] name = "prettyplease" -version = "0.2.22" +version = "0.2.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479cf940fbbb3426c32c5d5176f62ad57549a0bb84773423ba8be9d089f5faba" +checksum = "910d41a655dac3b764f1ade94821093d3610248694320cd072303a8eedcf221d" dependencies = [ "proc-macro2", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -1945,9 +1945,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.86" +version = "1.0.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" dependencies = [ "unicode-ident", ] @@ -1969,9 +1969,9 @@ dependencies = [ [[package]] name = "prost" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b2ecbe40f08db5c006b5764a2645f7f3f141ce756412ac9e1dd6087e6d32995" +checksum = "7b0487d90e047de87f984913713b85c601c05609aad5b0df4b4573fbf69aa13f" dependencies = [ "bytes", "prost-derive", @@ -1979,9 +1979,9 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8650aabb6c35b860610e9cff5dc1af886c9e25073b7b1712a68972af4281302" +checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" dependencies = [ "bytes", "heck 0.5.0", @@ -1994,28 +1994,28 @@ dependencies = [ "prost", "prost-types", "regex", - "syn 2.0.77", + "syn 2.0.82", "tempfile", ] [[package]] name = "prost-derive" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf0c195eebb4af52c752bec4f52f645da98b6e92077a04110c7f349477ae5ac" +checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] name = "prost-types" -version = "0.13.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60caa6738c7369b940c3d49246a8d1749323674c65cb13010134f5c9bad5b519" +checksum = "4759aa0d3a6232fb8dbdb97b61de2c20047c68aca932c7ed76da9d788508d670" dependencies = [ "prost", ] @@ -2128,32 +2128,32 @@ dependencies = [ [[package]] name = "raw-cpuid" -version = "11.1.0" +version = "11.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb9ee317cfe3fbd54b36a511efc1edd42e216903c9cd575e686dd68a2ba90d8d" +checksum = "1ab240315c661615f2ee9f0f2cd32d5a7343a84d5ebcccb99d46e6637565e7b0" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "redox_syscall" -version = "0.5.3" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" +checksum = "9b6dfecf2c74bce2466cabf93f6664d6998a69eb21e39f4207930065b27b771f" dependencies = [ "bitflags 2.6.0", ] [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -2167,13 +2167,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -2184,9 +2184,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reqwest" @@ -2202,7 +2202,7 @@ dependencies = [ "h2 0.3.26", "http 0.2.12", "http-body 0.4.6", - "hyper 0.14.30", + "hyper 0.14.31", "hyper-tls", "ipnet", "js-sys", @@ -2255,11 +2255,12 @@ dependencies = [ [[package]] name = "ringbuf" -version = "0.4.4" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46f7f1b88601a8ee13cabf203611ccdf64345dc1c5d24de8b11e1a678ee619b6" +checksum = "726bb493fe9cac765e8f96a144c3a8396bdf766dedad22e504b70b908dcbceb4" dependencies = [ "crossbeam-utils", + "portable-atomic", ] [[package]] @@ -2300,7 +2301,7 @@ dependencies = [ [[package]] name = "rustfsm" version = "0.1.0" -source = "git+https://github.com/temporalio/sdk-core?branch=master#a8150d5c7c3fc1bfd5a941fd315abff1556cd9dc" +source = "git+https://github.com/temporalio/sdk-core?branch=master#730aadcc02767ae630e88f8f8c788a85d6bc81e6" dependencies = [ "rustfsm_procmacro", "rustfsm_trait", @@ -2309,25 +2310,25 @@ dependencies = [ [[package]] name = "rustfsm_procmacro" version = "0.1.0" -source = "git+https://github.com/temporalio/sdk-core?branch=master#a8150d5c7c3fc1bfd5a941fd315abff1556cd9dc" +source = "git+https://github.com/temporalio/sdk-core?branch=master#730aadcc02767ae630e88f8f8c788a85d6bc81e6" dependencies = [ "derive_more", "proc-macro2", "quote", "rustfsm_trait", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] name = "rustfsm_trait" version = "0.1.0" -source = "git+https://github.com/temporalio/sdk-core?branch=master#a8150d5c7c3fc1bfd5a941fd315abff1556cd9dc" +source = "git+https://github.com/temporalio/sdk-core?branch=master#730aadcc02767ae630e88f8f8c788a85d6bc81e6" [[package]] name = "rustix" -version = "0.38.36" +version = "0.38.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f55e80d50763938498dd5ebb18647174e0c76dc38c5505294bb224624f30f36" +checksum = "8acb788b847c24f28525660c4d7758620a7210875711f79e7f663cc152726811" dependencies = [ "bitflags 2.6.0", "errno", @@ -2338,9 +2339,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.13" +version = "0.23.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dabaac7466917e566adb06783a81ca48944c6898a1b08b9374106dd671f4c8" +checksum = "5fbb44d7acc4e873d613422379f69f237a1b141928c02f6bc6ccfddddc2d7993" dependencies = [ "log", "once_cell", @@ -2353,12 +2354,12 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5bfb394eeed242e909609f56089eecfe5fda225042e8b171791b9c95f5931e5" +checksum = "fcaf18a4f2be7326cd874a5fa579fae794320a0f388d365dca7e480e55f83f8a" dependencies = [ "openssl-probe", - "rustls-pemfile 2.1.3", + "rustls-pemfile 2.2.0", "rustls-pki-types", "schannel", "security-framework", @@ -2375,19 +2376,18 @@ dependencies = [ [[package]] name = "rustls-pemfile" -version = "2.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "196fe16b00e106300d3e45ecfcb764fa292a535d7326a29a5875c579c7417425" +checksum = "dce314e5fee3f39953d46bb63bb8a46d40c2f8fb7cc5a3b6cab2bde9721d6e50" dependencies = [ - "base64 0.22.1", "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0a2ce646f8655401bb81e7927b812614bd5d91dbc968696be50603510fcaf0" +checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" [[package]] name = "rustls-webpki" @@ -2402,9 +2402,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.17" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" +checksum = "0e819f2bc632f285be6d7cd36e25940d45b2391dd6d9b939e79de557f7014248" [[package]] name = "ryu" @@ -2414,9 +2414,9 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "schannel" -version = "0.1.24" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9aaafd5a2b6e3d657ff009d82fbd630b6bd54dd4eb06f21693925cdf80f9b8b" +checksum = "01227be5826fa0690321a2ba6c5cd57a19cf3f6a09e76973b58e61de6ab9d1c1" dependencies = [ "windows-sys 0.59.0", ] @@ -2456,9 +2456,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.11.1" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75da29fe9b9b08fe9d6b22b5b4bcbc75d8db3aa31e639aa56bb62e9d46bfceaf" +checksum = "ea4a292869320c0272d7bc55a5a6aafaff59b4f63404a003887b679a2e05b4b6" dependencies = [ "core-foundation-sys", "libc", @@ -2472,9 +2472,9 @@ checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.213" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "3ea7893ff5e2466df8d720bb615088341b295f849602c6956047f8f80f0e9bc1" dependencies = [ "serde_derive", ] @@ -2491,20 +2491,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.213" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "7e85ad2009c50b58e87caa8cd6dac16bdf511bbfb7af6c33df902396aa480fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] name = "serde_json" -version = "1.0.128" +version = "1.0.132" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ff5456707a1de34e7e37f2a6fd3d3f808c318259cbd01ab6377795054b483d8" +checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" dependencies = [ "itoa", "memchr", @@ -2545,15 +2545,15 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69cecfa94848272156ea67b2b1a53f20fc7bc638c4a46d2f8abde08f05f4b857" +checksum = "8e28bdad6db2b8340e449f7108f020b3b092e8583a9e3fb82713e1d4e71fe817" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.5.0", + "indexmap 2.6.0", "serde", "serde_derive", "serde_json", @@ -2563,14 +2563,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.9.0" +version = "3.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8fee4991ef4f274617a51ad4af30519438dacb2f56ac773b08a1922ff743350" +checksum = "9d846214a9854ef724f3da161b426242d8de7c1fc7de2f89bb1efcb154dca79d" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -2728,9 +2728,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.77" +version = "2.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f35bcdf61fd8e7be6caf75f429fdca8beb3ed76584befb503b1569faee373ed" +checksum = "83540f837a8afc019423a8edb95b52a8effe46957ee402287f4292fae35be021" dependencies = [ "proc-macro2", "quote", @@ -2751,9 +2751,9 @@ checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" [[package]] name = "sysinfo" -version = "0.31.4" +version = "0.32.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "355dbe4f8799b304b05e1b0f05fc59b2a18d36645cf169607da45bde2f69a1be" +checksum = "e3b5ae3f4f7d64646c46c4cae4e3f01d1c5d255c7406fdd7c7f999a94e488791" dependencies = [ "core-foundation-sys", "libc", @@ -2785,9 +2785,9 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.12.0" +version = "3.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04cbcdd0c794ebb0d4cf35e88edd2f7d2c4c3e9a5a6dab322839b321c6a87a64" +checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" dependencies = [ "cfg-if", "fastrand", @@ -2799,7 +2799,7 @@ dependencies = [ [[package]] name = "temporal-client" version = "0.1.0" -source = "git+https://github.com/temporalio/sdk-core?branch=master#a8150d5c7c3fc1bfd5a941fd315abff1556cd9dc" +source = "git+https://github.com/temporalio/sdk-core?branch=master#730aadcc02767ae630e88f8f8c788a85d6bc81e6" dependencies = [ "anyhow", "async-trait", @@ -2807,13 +2807,12 @@ dependencies = [ "base64 0.22.1", "derive_builder", "derive_more", - "futures", "futures-retry", + "futures-util", "http 1.1.0", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-util", - "once_cell", "opentelemetry", "parking_lot", "prost-types", @@ -2832,13 +2831,12 @@ dependencies = [ [[package]] name = "temporal-sdk" version = "0.1.0-alpha.1" -source = "git+https://github.com/temporalio/sdk-core?branch=master#a8150d5c7c3fc1bfd5a941fd315abff1556cd9dc" +source = "git+https://github.com/temporalio/sdk-core?branch=master#730aadcc02767ae630e88f8f8c788a85d6bc81e6" dependencies = [ "anyhow", "async-trait", - "crossbeam-channel", "derive_more", - "futures", + "futures-util", "parking_lot", "prost-wkt-types", "serde", @@ -2856,7 +2854,7 @@ dependencies = [ [[package]] name = "temporal-sdk-core" version = "0.1.0" -source = "git+https://github.com/temporalio/sdk-core?branch=master#a8150d5c7c3fc1bfd5a941fd315abff1556cd9dc" +source = "git+https://github.com/temporalio/sdk-core?branch=master#730aadcc02767ae630e88f8f8c788a85d6bc81e6" dependencies = [ "anyhow", "async-trait", @@ -2868,13 +2866,12 @@ dependencies = [ "derive_more", "enum-iterator", "enum_dispatch", - "futures", + "futures-channel", "futures-util", "governor", "itertools 0.13.0", "lru", "mockall", - "once_cell", "parking_lot", "pid", "pin-project", @@ -2907,7 +2904,7 @@ dependencies = [ [[package]] name = "temporal-sdk-core-api" version = "0.1.0" -source = "git+https://github.com/temporalio/sdk-core?branch=master#a8150d5c7c3fc1bfd5a941fd315abff1556cd9dc" +source = "git+https://github.com/temporalio/sdk-core?branch=master#730aadcc02767ae630e88f8f8c788a85d6bc81e6" dependencies = [ "async-trait", "derive_builder", @@ -2925,12 +2922,13 @@ dependencies = [ [[package]] name = "temporal-sdk-core-protos" version = "0.1.0" -source = "git+https://github.com/temporalio/sdk-core?branch=master#a8150d5c7c3fc1bfd5a941fd315abff1556cd9dc" +source = "git+https://github.com/temporalio/sdk-core?branch=master#730aadcc02767ae630e88f8f8c788a85d6bc81e6" dependencies = [ "anyhow", "base64 0.22.1", "derive_more", "prost", + "prost-build", "prost-wkt", "prost-wkt-build", "prost-wkt-types", @@ -2960,22 +2958,22 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.63" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" +checksum = "5d11abd9594d9b38965ef50805c5e469ca9cc6f197f883f717e0269a3057b3d5" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.63" +version = "1.0.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" +checksum = "ae71770322cbd277e69d762a16c444af02aa0575ac0d174f0b9562d3b37f8602" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -3036,9 +3034,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.40.0" +version = "1.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998" +checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" dependencies = [ "backtrace", "bytes", @@ -3060,7 +3058,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -3119,9 +3117,9 @@ dependencies = [ [[package]] name = "tonic" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f6ba989e4b2c58ae83d862d3a3e27690b6e3ae630d0deb59f3697f32aa88ad" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" dependencies = [ "async-stream", "async-trait", @@ -3132,14 +3130,14 @@ dependencies = [ "http 1.1.0", "http-body 1.0.1", "http-body-util", - "hyper 1.4.1", + "hyper 1.5.0", "hyper-timeout", "hyper-util", "percent-encoding", "pin-project", "prost", "rustls-native-certs", - "rustls-pemfile 2.1.3", + "rustls-pemfile 2.2.0", "socket2", "tokio", "tokio-rustls", @@ -3152,15 +3150,16 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4ee8877250136bd7e3d2331632810a4df4ea5e004656990d8d66d2f5ee8a67" +checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" dependencies = [ "prettyplease", "proc-macro2", "prost-build", + "prost-types", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -3228,7 +3227,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -3310,14 +3309,14 @@ checksum = "70b20a22c42c8f1cd23ce5e34f165d4d37038f5b663ad20fb6adbdf029172483" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] name = "unicode-bidi" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "5ab17db44d7388991a428b2ee655ce0c212e862eff1768a455c58f9aad6e7893" [[package]] name = "unicode-ident" @@ -3327,30 +3326,30 @@ checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" [[package]] name = "unicode-normalization" -version = "0.1.23" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +checksum = "5033c97c4262335cded6d6fc3e5c18ab755e1a3dc96376350f3d8e9f009ad956" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.1.13" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0336d538f7abc86d282a4189614dfaa90810dfc2c6f6427eaf88e16311dd225d" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" [[package]] name = "unicode-xid" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229730647fbc343e3a80e463c1db7f78f3855d3f3739bee0dda773c9a037c90a" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "untrusted" @@ -3372,9 +3371,9 @@ dependencies = [ [[package]] name = "uuid" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" dependencies = [ "getrandom", ] @@ -3420,9 +3419,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" dependencies = [ "cfg-if", "once_cell", @@ -3431,24 +3430,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.43" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61e9300f63a621e96ed275155c108eb6f843b6a26d053f122ab69724559dc8ed" +checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" dependencies = [ "cfg-if", "js-sys", @@ -3458,9 +3457,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3468,28 +3467,28 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.93" +version = "0.2.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" +checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" [[package]] name = "web-sys" -version = "0.3.70" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26fdeaafd9bd129f65e7c031593c24d62186301e0c72c8978fa1678be7d532c0" +checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" dependencies = [ "js-sys", "wasm-bindgen", @@ -3556,7 +3555,7 @@ checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -3567,7 +3566,7 @@ checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] @@ -3755,7 +3754,7 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.77", + "syn 2.0.82", ] [[package]] From b7a6e106fd6dc762383d653c5c35efb44366e5ae Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Wed, 23 Oct 2024 14:08:57 -0400 Subject: [PATCH 06/13] Version increments. --- RELEASE-NOTES.md | 7 +++++++ debian/changelog | 6 ++++++ ext/installfiles/mac/ZeroTier One.pkgproj | 2 +- version.h | 2 +- zerotier-one.spec | 5 ++++- 5 files changed, 19 insertions(+), 3 deletions(-) diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 72ca1f3b..e6582207 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,6 +1,13 @@ ZeroTier Release Notes ====== +# 2024-10-23 -- Version 1.14.2 + + * Fix for missing entitlement on macOS Sequoia. + * Fix for a problem correctly parsing local.conf to enable low bandwidth mode. + * Increment versions of some dependent libraries. + * Other fixes. + # 2024-09-12 -- Version 1.14.1 * Multithreaded packet I/O support! Currently this is just for Linux and must diff --git a/debian/changelog b/debian/changelog index 660562f9..fdc85f86 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,9 @@ +zerotier-one (1.14.2) unstable; urgency=medium + + * See RELEASE-NOTES.md for release notes. + + -- Adam Ierymenko Wed, 23 Oct 2024 01:00:00 -0700 + zerotier-one (1.14.1) unstable; urgency=medium * See RELEASE-NOTES.md for release notes. diff --git a/ext/installfiles/mac/ZeroTier One.pkgproj b/ext/installfiles/mac/ZeroTier One.pkgproj index cf6af8e7..70cedf9f 100755 --- a/ext/installfiles/mac/ZeroTier One.pkgproj +++ b/ext/installfiles/mac/ZeroTier One.pkgproj @@ -701,7 +701,7 @@ USE_HFS+_COMPRESSION VERSION - 1.14.1 + 1.14.2 TYPE 0 diff --git a/version.h b/version.h index 8fff820a..6027e70e 100644 --- a/version.h +++ b/version.h @@ -27,7 +27,7 @@ /** * Revision */ -#define ZEROTIER_ONE_VERSION_REVISION 1 +#define ZEROTIER_ONE_VERSION_REVISION 2 /** * Build version diff --git a/zerotier-one.spec b/zerotier-one.spec index 414b0b62..655068bf 100644 --- a/zerotier-one.spec +++ b/zerotier-one.spec @@ -1,5 +1,5 @@ Name: zerotier-one -Version: 1.14.1 +Version: 1.14.2 Release: 1%{?dist} Summary: ZeroTier network virtualization service @@ -155,6 +155,9 @@ chmod 0755 $RPM_BUILD_ROOT/etc/init.d/zerotier-one %endif %changelog +* Wed Oct 23 2024 Adam Ierymenko - 1.14.2 +- see https://github.com/zerotier/ZeroTierOne for release notes + * Tue Mar 19 2024 Adam Ierymenko - 1.14.0 - see https://github.com/zerotier/ZeroTierOne for release notes From 3fcef51137ac9d32af951cb856279dcee7f1ce03 Mon Sep 17 00:00:00 2001 From: Adam Ierymenko Date: Fri, 25 Oct 2024 14:14:01 -0400 Subject: [PATCH 07/13] Windows installer version bump. --- ext/installfiles/windows/ZeroTier One.aip | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ext/installfiles/windows/ZeroTier One.aip b/ext/installfiles/windows/ZeroTier One.aip index 0870201e..43b3223f 100644 --- a/ext/installfiles/windows/ZeroTier One.aip +++ b/ext/installfiles/windows/ZeroTier One.aip @@ -24,10 +24,10 @@ - + - + @@ -62,7 +62,7 @@ - + @@ -498,7 +498,7 @@ - + From 826fcca1c9c1a981e111d456d94d14e6562aa838 Mon Sep 17 00:00:00 2001 From: Eugenia Agibalova Date: Thu, 10 Apr 2025 23:52:50 +0400 Subject: [PATCH 08/13] added nix tooling --- .gitignore | 7 ++++++ flake.lock | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++ flake.nix | 35 +++++++++++++++++++++++++++++ package.nix | 18 +++++++++++++++ shell.nix | 16 ++++++++++++++ 5 files changed, 140 insertions(+) create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 package.nix create mode 100644 shell.nix diff --git a/.gitignore b/.gitignore index ba8b4afc..8d0cb04b 100755 --- a/.gitignore +++ b/.gitignore @@ -140,3 +140,10 @@ __pycache__ snap/.snapcraft tcp-proxy/tcp-proxy rustybits/target + +#direnv +.envrc + +#nix stuff +result +result-man diff --git a/flake.lock b/flake.lock new file mode 100644 index 00000000..80d833b4 --- /dev/null +++ b/flake.lock @@ -0,0 +1,64 @@ +{ + "nodes": { + "flake-utils": { + "inputs": { + "systems": "systems" + }, + "locked": { + "lastModified": 1731533236, + "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1744157173, + "narHash": "sha256-bWSjxDwq7iVePrhmA7tY2dyMWHuNJo8knkO4y+q4ZkY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "6a39c6e495eefabc935d8ddf66aa45d85b85fa3f", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "flake-utils": "flake-utils", + "nixpkgs": "nixpkgs", + "nixpkgs-zerotier-base": [ + "nixpkgs" + ] + } + }, + "systems": { + "locked": { + "lastModified": 1681028828, + "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", + "owner": "nix-systems", + "repo": "default", + "rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 00000000..dd025679 --- /dev/null +++ b/flake.nix @@ -0,0 +1,35 @@ +{ + description = "Custom ZeroTierOne build with private patches"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + + # Pin to specific nixpkgs version for zerotierone base package + nixpkgs-zerotier-base = { + url = "github:NixOS/nixpkgs/d9d87c51960050e89c79e4025082ed965e770d68"; + follows = "nixpkgs"; + }; + + flake-utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, nixpkgs-zerotier-base, flake-utils }: + flake-utils.lib.eachDefaultSystem (system: + let + pkgs = import nixpkgs { inherit system; }; + in + { + packages = { + zerotierone-tspu = pkgs.callPackage ./package.nix { + zerotierone = (import nixpkgs-zerotier-base { inherit system; }).zerotierone; + }; + + default = self.packages.${system}.zerotierone-tspu; + }; + + devShells.default = import ./shell.nix { + inherit pkgs; + }; + } + ); +} diff --git a/package.nix b/package.nix new file mode 100644 index 00000000..f1e8333e --- /dev/null +++ b/package.nix @@ -0,0 +1,18 @@ +{ zerotierone, lib }: + +zerotierone.overrideAttrs (oldAttrs: { + pname = "zerotierone-tspu"; + version = "1.14.2-tspu"; + + src = builtins.fetchGit { + url = "git@git.dltech.ge:global-it/infra/zerotiertspu.git"; + ref = "1.14.2"; + }; + + patches = []; + nativeBuildInputs = oldAttrs.nativeBuildInputs ++ [ ]; + + meta = oldAttrs.meta // { + description = "Custom ZeroTierOne build with private patches"; + }; +}) diff --git a/shell.nix b/shell.nix new file mode 100644 index 00000000..93119a0d --- /dev/null +++ b/shell.nix @@ -0,0 +1,16 @@ +{ pkgs ? import { } }: + +let + zerotieroneCustom = pkgs.callPackage ./package.nix {}; +in +pkgs.mkShell { + packages = [ ] + ++ zerotieroneCustom.buildInputs + ++ zerotieroneCustom.nativeBuildInputs; + + SSH_AUTH_SOCK = builtins.getEnv "SSH_AUTH_SOCK"; + NIXPKGS_ALLOW_UNFREE = "1"; + + shellHook = '' + ''; +} From cdaf5e54689473490eec08e02f845812793197e0 Mon Sep 17 00:00:00 2001 From: Eugenia Agibalova Date: Mon, 14 Apr 2025 16:04:52 +0400 Subject: [PATCH 09/13] fixed nix tooling --- .gitignore | 4 ++++ package.nix | 2 +- shell.nix | 11 ++++++++--- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 8d0cb04b..f7ef2551 100755 --- a/.gitignore +++ b/.gitignore @@ -147,3 +147,7 @@ rustybits/target #nix stuff result result-man + +#zerotier devs seem to forgot those +rustybits/zerotier-cli +rustybits/zerotier-idtool diff --git a/package.nix b/package.nix index f1e8333e..563e2a0a 100644 --- a/package.nix +++ b/package.nix @@ -6,7 +6,7 @@ zerotierone.overrideAttrs (oldAttrs: { src = builtins.fetchGit { url = "git@git.dltech.ge:global-it/infra/zerotiertspu.git"; - ref = "1.14.2"; + ref = "tspu"; }; patches = []; diff --git a/shell.nix b/shell.nix index 93119a0d..f0c8131a 100644 --- a/shell.nix +++ b/shell.nix @@ -4,9 +4,14 @@ let zerotieroneCustom = pkgs.callPackage ./package.nix {}; in pkgs.mkShell { - packages = [ ] - ++ zerotieroneCustom.buildInputs - ++ zerotieroneCustom.nativeBuildInputs; + packages = with pkgs; [ + bear + cmake + cmake-language-server + clang-tools + ] + ++ zerotieroneCustom.buildInputs + ++ zerotieroneCustom.nativeBuildInputs; SSH_AUTH_SOCK = builtins.getEnv "SSH_AUTH_SOCK"; NIXPKGS_ALLOW_UNFREE = "1"; From 083b833bf8fd42c3cc1937193142ee39807ff77b Mon Sep 17 00:00:00 2001 From: eerieaerial <205630019+eerieaerial@users.noreply.github.com> Date: Wed, 30 Apr 2025 17:40:54 +0400 Subject: [PATCH 10/13] added camouflaging functionality and instrumentation --- .gitignore | 1 + node/Buffer.hpp | 5 + node/CamoPattern.cpp | 168 +++++++++++++++++++++++++ node/CamoPattern.hpp | 262 +++++++++++++++++++++++++++++++++++++++ node/IncomingPacket.cpp | 12 ++ node/IncomingPacket.hpp | 32 +++++ node/Multicaster.cpp | 7 +- node/Multicaster.hpp | 3 +- node/Network.cpp | 2 +- node/Network.hpp | 3 +- node/Packet.hpp | 22 ++-- node/Peer.cpp | 5 + node/Peer.hpp | 2 + node/Switch.cpp | 266 ++++++++++++++++++++++++++++++++++++---- objects.mk | 1 + service/OneService.cpp | 156 +++++++++++++++++++++++ 16 files changed, 904 insertions(+), 43 deletions(-) create mode 100644 node/CamoPattern.cpp create mode 100644 node/CamoPattern.hpp diff --git a/.gitignore b/.gitignore index f7ef2551..5ef9f5d9 100755 --- a/.gitignore +++ b/.gitignore @@ -151,3 +151,4 @@ result-man #zerotier devs seem to forgot those rustybits/zerotier-cli rustybits/zerotier-idtool +.aider* diff --git a/node/Buffer.hpp b/node/Buffer.hpp index 8dbc51ef..559e9468 100644 --- a/node/Buffer.hpp +++ b/node/Buffer.hpp @@ -445,6 +445,11 @@ public: */ inline unsigned int capacity() const { return C; } + /** + * Dump buffer contents to stdout in hex format + */ + void dump() const; + template inline bool operator==(const Buffer &b) const { diff --git a/node/CamoPattern.cpp b/node/CamoPattern.cpp new file mode 100644 index 00000000..d06d4e66 --- /dev/null +++ b/node/CamoPattern.cpp @@ -0,0 +1,168 @@ +/* + * Copyright (c)2013-2020 ZeroTier, Inc. + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. + * + * Change Date: 2026-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. + */ +/****/ + +#include "CamoPattern.hpp" +#include +#include "Topology.hpp" + +namespace ZeroTier { + +// Initialize static members of CamoPattern +bool CamoPattern::isInitialized = false; +CamoLevel CamoPattern::camoLevel; +uint32_t CamoPattern::camoWord; +CamoRelayRule CamoPattern::relayRule; +std::array, PATTERN_COUNT> CamoPattern::camoValues; +std::unordered_map, size_t> CamoPattern::camoIndices; +std::mutex CamoPattern::camoMutex; +std::unordered_map CamoPattern::knownHosts; + + +// Implementation of getCamoLevel +CamoLevel CamoPattern::getCamoLevel(const Address host, const RuntimeEnvironment * const RR) +{ + CamoLevel result = CamoLevel::INAPPLICABLE; + // First check if we already know this host's camo level + if (isInitialized) + { + char buf[64]; + host.toString(buf); + CT("GETTING CAMO LEVEL FOR HOST %s", buf); + auto it = knownHosts.find(host); + if (it != knownHosts.end()) { + result = it->second; + CT("HOST IS KNOWN, LEVEL: %u", result); + } + else + { + // Host not found in known hosts, run mutex-protected section + std::lock_guard lock(camoMutex); + + // Check again in case another thread added it while we were waiting + it = knownHosts.find(host); + if (it != knownHosts.end()) { + result = it->second; + CT("HOST IS KNOWN AFTER LOCK WAITING"); + } + else + { + CT("HOST IS NOT KNOWN"); + if (!RR->topology->isProhibitedEndpoint(host, InetAddress())) + { + switch(RR->topology->role(host)) + { + case ZT_PEER_ROLE_PLANET: + CT("HOST IS A PLANET"); + result = CamoLevel::PLANET; + break; + case ZT_PEER_ROLE_MOON: + CT("HOST IS A MOON"); + result = CamoLevel::MOON; + break; + default: + result = CamoLevel::NODE; + Mutex::Lock _l(RR->node->_networks_m); + Hashtable>::Iterator i(RR->node->_networks); + uint64_t * k = (uint64_t *)0; + SharedPtr *v = (SharedPtr *)0; + while(i.next(k, v)) + { + if (host == ((*v)->controller())) + { + CT("HOST IS A CONTROLLER"); + result = CamoLevel::CONTROLLER; + break; + } + } + if (result == CamoLevel::NODE) + { + CT("HOST IS A SIMPLE NODE"); + } + break; + } + } + else + { + CT("HOST IS A ZT GLOBAL ROOT"); + } + knownHosts[host] = result; + } + } + } + return result; +} + +// Implementation of isCamoRequired +bool CamoPattern::isCamoRequired(const Address host, const RuntimeEnvironment * const RR, const bool hadCamo, const bool isRelay) +{ + bool result = false; + if (isInitialized && isRelay) + { + switch(relayRule) + { + case CamoRelayRule::LEAVE: + CT("IS RELAY, APPLYING LEAVE RULE"); + result = hadCamo; + break; + case CamoRelayRule::KNOWNHOSTS: + CT("IS RELAY, APPLYING KNOWNHOSTS RULE"); + result = getCamoLevel(host, RR) <= camoLevel; + break; + case CamoRelayRule::STRIP: + CT("IS RELAY, APPLYING STRIP RULE"); + result = false; + break; + case CamoRelayRule::APPLY: + CT("IS RELAY, APPLYING APPLY RULE"); + result = true; + break; + } + } + else if (isInitialized) + { + result = getCamoLevel(host, RR) <= camoLevel; + CT("IS CAMO REQUIRED: %b", result); + } + return result; +} + + +// Implementation of init +void CamoPattern::init(CamoLevel level, uint32_t word, std::unordered_map hosts, CamoRelayRule rule) +{ + std::lock_guard lock(camoMutex); + if (!isInitialized) + { + camoLevel = level; + camoWord = word; + knownHosts = hosts; + relayRule = rule; + CT("CAMO LEVEL: %u, WORD: %08x, KNOWN HOSTS COUNT: %lu, RELAY RULE: %u", level, word, hosts.size(), rule); + std::mt19937 rng(camoWord); + for (size_t i = 0; i < PATTERN_COUNT; i++) + { + uint32_t random = rng(); + CT("CAMO INDEX: %lu, VALUE: %08x", i, random); + for (size_t j = 0; j < BYTES_IN_WORD; j++) + { + camoValues[i][j] = (random >> (j * 8)) & 0xff; + } + camoIndices[camoValues[i]] = i; + } + isInitialized = true; + } +} + + + +} // namespace ZeroTier diff --git a/node/CamoPattern.hpp b/node/CamoPattern.hpp new file mode 100644 index 00000000..ff361b55 --- /dev/null +++ b/node/CamoPattern.hpp @@ -0,0 +1,262 @@ +/* + * Copyright (c)2013-2020 ZeroTier, Inc. + * + * Use of this software is governed by the Business Source License included + * in the LICENSE.TXT file in the project's root directory. + * + * Change Date: 2026-01-01 + * + * On the date above, in accordance with the Business Source License, use + * of this software will be governed by version 2.0 of the Apache License. + */ +/****/ + +#ifndef ZT_N_CAMOPATTERN_HPP +#define ZT_N_CAMOPATTERN_HPP + +#define CAMO_TRACE + +#include +#include +#include +#include +#include + +#include "Address.hpp" +#include "Buffer.hpp" +#include "RuntimeEnvironment.hpp" + +#define BYTES_IN_WORD 4 +#define PATTERN_COUNT 16 +#define PATTERN_INDEX_MASK 0xf +#define NO_CAMO PATTERN_COUNT + +#define ZT_CAMO_DEFAULT_WORDSTR "DLGE" + +namespace std { + template + struct hash> { + size_t operator()(const std::array& array) const { + size_t hash = 0; + for (const auto& element : array) { + hash = hash * 31 + std::hash{}(element); + } + return hash; + } + }; + + template<> + struct hash { + size_t operator()(const ZeroTier::Address& address) const { + return std::hash{}(address.toInt()); + } + }; +} + +/** + * Camo functions debug trace macro +*/ +#ifdef CAMO_TRACE + #define CT(...) do { \ + printf("%s:%d %s: ", __FILE__, __LINE__, __PRETTY_FUNCTION__); \ + printf(__VA_ARGS__); \ + printf("\n"); \ + } while(0) +#else + #define CT(...) ((void)0) +#endif + +namespace ZeroTier { + +/** + * Camouflage level enum + */ +enum class CamoLevel { + NONE, + NODE, + CONTROLLER, + MOON, + PLANET, + INAPPLICABLE +}; + +enum class CamoRelayRule { + LEAVE, + KNOWNHOSTS, + STRIP, + APPLY +}; + +/** + * Helper class for packet camouflage operations + */ +class CamoPattern +{ + /** + * Check if buffer has camouflage applied + * + * @param buffer Buffer to check + * @return True if buffer has camouflage + */ + template + static size_t getCamoIndex(const Buffer &buffer) + { + size_t result = NO_CAMO; + std::array camo; + if (buffer.size() > BYTES_IN_WORD * 2) + { + for (size_t i = 0; i < BYTES_IN_WORD; i++) + { + camo[i] = buffer[i] ^ buffer[i + BYTES_IN_WORD]; + } + auto it = camoIndices.find(camo); + if (it != camoIndices.end()) + { + result = it->second; + CT("CAMO DETECTED, INDEX: %u", result); + } + else + { + CT("CAMO NOT DETECTED"); + } + } + return result; + } + + /** + * Check the host camo level + * + * @param host Destination address + * @param RR RuntimeEnvironment pointer + * @return Camo Level for this host + */ + static CamoLevel getCamoLevel(const Address host, const RuntimeEnvironment * const RR); + +public: + /** + * + * @param host Destination address + * @param RR RuntimeEnvironment pointer + * @return True if host requires camo + */ + static bool isCamoRequired(const Address host, const RuntimeEnvironment * const RR, const bool hadCamo = false, const bool isRelay = false); + + /** + * Apply camouflage to buffer + * + * @param buffer Buffer to apply camouflage to + */ + template + static void applyCamo(Buffer &buffer) + { + size_t camoIndex = getCamoIndex(buffer); + if (isInitialized && (camoIndex == NO_CAMO)) { // Only apply if not already applied + CT("PACKET CONTENTS BEFORE APPLYING CAMO:"); + buffer.dump(); + camoIndex = std::minstd_rand(std::time(nullptr))() & PATTERN_INDEX_MASK; + std::array camo = camoValues[camoIndex]; + + // Increase buffer size first to avoid overflow + size_t originalSize = buffer.size(); + buffer.setSize(originalSize + BYTES_IN_WORD); + uint8_t * const data = reinterpret_cast(buffer.unsafeData()); + + // Copy the second word to the end + for (size_t i = 0; i < BYTES_IN_WORD; i++) { + data[i + originalSize] = data[i + BYTES_IN_WORD]; + } + + // Apply XOR to the rest of the buffer + for (size_t i = BYTES_IN_WORD * 2; i < buffer.size(); i++) { + data[i] ^= camo[i % BYTES_IN_WORD]; + } + + // Apply XOR to create the camouflage pattern in the second word + for (size_t i = 0; i < BYTES_IN_WORD; i++) { + data[i + BYTES_IN_WORD] = data[i] ^ camo[i]; + } + CT("PACKET CONTENTS AFTER APPLYING CAMO:"); + buffer.dump(); + } + } + + /** + * Remove camouflage from buffer + * + * This decreases buffer length by removing 'CAMO' from the end + * + * @param buffer Buffer to remove camouflage from + */ + template + static bool stripCamo(Buffer &buffer) + { + bool result = false; + size_t camoIndex = NO_CAMO; + if (isInitialized) + { + camoIndex = getCamoIndex(buffer); + } + if (camoIndex != NO_CAMO) { + CT("PACKET CONTENTS BEFORE STRIPPING CAMO:"); + buffer.dump(); + uint8_t * const data = reinterpret_cast(buffer.unsafeData()); + std::array camo = camoValues[camoIndex]; + for (size_t i = BYTES_IN_WORD * 2; i < buffer.size(); i++) + { + data[i] ^= camo[i % BYTES_IN_WORD]; + } + size_t storedWordIndex = buffer.size() - BYTES_IN_WORD; + for (size_t i = 0; i < BYTES_IN_WORD; i++) + { + data[i + BYTES_IN_WORD] = data[i + storedWordIndex]; + } + buffer.setSize(buffer.size() - BYTES_IN_WORD); + result = true; + CT("PACKET CONTENTS AFTER STRIPPING CAMO:"); + buffer.dump(); + } + return result; + } + + static void init(CamoLevel level, uint32_t word, std::unordered_map hosts, CamoRelayRule rule); + + +private: + static bool isInitialized; + static CamoLevel camoLevel; + static uint32_t camoWord; + static CamoRelayRule relayRule; + static std::array, PATTERN_COUNT> camoValues; + static std::unordered_map, size_t> camoIndices; + static std::mutex camoMutex; + static std::unordered_map knownHosts; +}; + +} // namespace ZeroTier + +// Implementation of Buffer::dump() method +template +void ZeroTier::Buffer::dump() const +{ +#ifdef CAMO_TRACE + const unsigned char *bytes = reinterpret_cast(data()); + const unsigned int size = this->size(); + + for (unsigned int i = 0; i < size; i++) { + printf("%02x", bytes[i]); + + if ((i + 1) % 16 == 0) { + printf("\n"); + } else if (i < size - 1) { + printf(" "); + } + } + + // Add newline if last line wasn't complete + if (size % 16 != 0) { + printf("\n"); + } +#endif +} + +#endif // ZT_CAMOPATTERN_HPP diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 2537c0fb..71fb0f5e 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -39,6 +39,7 @@ #include "Bond.hpp" #include "Metrics.hpp" #include "PacketMultiplexer.hpp" +#include "CamoPattern.hpp" namespace ZeroTier { @@ -407,6 +408,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool outp.armor(key,true,peer->aesKeysIfSupported()); Metrics::pkt_error_out++; Metrics::pkt_error_identity_collision_out++; + CT("UNPROCESSED"); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } else { RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC"); @@ -565,6 +567,7 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool outp.armor(peer->key(),true,peer->aesKeysIfSupported()); peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); Metrics::pkt_ok_out++; + CT("UNPROCESSED, packetId: %lx", outp.packetId()); _path->send(RR,tPtr,outp.data(),outp.size(),now); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version @@ -725,6 +728,7 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar if (count > 0) { Metrics::pkt_ok_out++; outp.armor(peer->key(),true,peer->aesKeysIfSupported()); + CT("UNPROCESSED"); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } @@ -955,6 +959,7 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const outp.armor(peer->key(),true,peer->aesKeysIfSupported()); peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); Metrics::pkt_ok_out++; + CT("UNPROCESSED"); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } @@ -984,6 +989,7 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const Share outp.armor(peer->key(),true,peer->aesKeysIfSupported()); peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); Metrics::pkt_ok_out++; + CT("UNPROCESSED, packetID: %lx", outp.packetId()); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); peer->received(tPtr,_path,hops(),pid,payloadLength(),Packet::VERB_ECHO,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW); @@ -1180,6 +1186,7 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void outp.armor(peer->key(),true,peer->aesKeysIfSupported()); Metrics::pkt_error_out++; Metrics::pkt_error_unsupported_op_out++; + CT("UNPROCESSED"); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } @@ -1204,6 +1211,7 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,c outp.armor(peer->key(),true,peer->aesKeysIfSupported()); peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); Metrics::pkt_ok_out++; + CT("UNPROCESSED"); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } @@ -1247,6 +1255,7 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr outp.armor(peer->key(),true,peer->aesKeysIfSupported()); peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); Metrics::pkt_ok_out++; + CT("UNPROCESSED"); _path->send(RR,tPtr,outp.data(),outp.size(),now); } } @@ -1320,6 +1329,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); if ((flags & 0x08)&&(network->config().isMulticastReplicator(RR->identity.address()))) { + CT("UNPROCESSED"); RR->mc->send(tPtr,RR->node->now(),network,peer->address(),to,from,etherType,frameData,frameLen); } @@ -1351,6 +1361,7 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, outp.armor(peer->key(),true,peer->aesKeysIfSupported()); peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); Metrics::pkt_ok_out++; + CT("UNPROCESSED"); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } @@ -1493,6 +1504,7 @@ void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void outp.armor(peer->key(),true,peer->aesKeysIfSupported()); Metrics::pkt_error_out++; Metrics::pkt_error_need_membership_cert_out++; + CT("UNPROCESSED"); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } diff --git a/node/IncomingPacket.hpp b/node/IncomingPacket.hpp index aa5936ff..cf80e339 100644 --- a/node/IncomingPacket.hpp +++ b/node/IncomingPacket.hpp @@ -74,6 +74,22 @@ public: { } + /** + * Create a new packet-in-decode from an existing packet + * + * @param packet Source packet + * @param path Path over which packet arrived + * @param now Current time + * @throws std::out_of_range Range error processing packet + */ + IncomingPacket(const Packet &packet, const SharedPtr &path, int64_t now) : + Packet(packet), + _receiveTime(now), + _path(path), + _authenticated(false) + { + } + /** * Init packet-in-decode in place * @@ -91,6 +107,22 @@ public: _authenticated = false; } + /** + * Init packet-in-decode in place from an existing packet + * + * @param packet Source packet + * @param path Path over which packet arrived + * @param now Current time + * @throws std::out_of_range Range error processing packet + */ + inline void init(const Packet &packet, const SharedPtr &path, int64_t now) + { + copyFrom(packet.data(), packet.size()); + _receiveTime = now; + _path = path; + _authenticated = false; + } + /** * Attempt to decode this packet * diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 3a771972..8b9e572b 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -63,11 +63,11 @@ void Multicaster::remove(uint64_t nwid,const MulticastGroup &mg,const Address &m } } -unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer &appendTo,unsigned int limit) const +unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer &appendTo,unsigned int limit) const { unsigned char *p; unsigned int added = 0,i,k,rptr,totalKnown = 0; - uint64_t a,picked[(ZT_PROTO_MAX_PACKET_LENGTH / 5) + 2]; + uint64_t a,picked[((ZT_PROTO_MAX_PACKET_LENGTH + ZT_PROTO_ADDITIONAL_CAMO_LENGTH) / 5) + 2]; if (!limit) { return 0; @@ -98,7 +98,7 @@ unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const // Members are returned in random order so that repeated gather queries // will return different subsets of a large multicast group. k = 0; - while ((added < limit)&&(k < s->members.size())&&((appendTo.size() + ZT_ADDRESS_LENGTH) <= ZT_PROTO_MAX_PACKET_LENGTH)) { + while ((added < limit)&&(k < s->members.size())&&((appendTo.size() + ZT_ADDRESS_LENGTH) <= (ZT_PROTO_MAX_PACKET_LENGTH + ZT_PROTO_ADDITIONAL_CAMO_LENGTH))) { rptr = (unsigned int)RR->node->prng(); restart_member_scan: @@ -201,6 +201,7 @@ void Multicaster::send( } outp.armor(bestMulticastReplicator->key(),true,bestMulticastReplicator->aesKeysIfSupported()); Metrics::pkt_multicast_frame_out++; + CT("UNPROCESSED"); bestMulticastReplicatorPath->send(RR,tPtr,outp.data(),outp.size(),now); return; } diff --git a/node/Multicaster.hpp b/node/Multicaster.hpp index 38117144..34802594 100644 --- a/node/Multicaster.hpp +++ b/node/Multicaster.hpp @@ -27,6 +27,7 @@ #include "MAC.hpp" #include "MulticastGroup.hpp" #include "OutboundMulticast.hpp" +#include "Packet.hpp" #include "Utils.hpp" #include "Mutex.hpp" #include "SharedPtr.hpp" @@ -103,7 +104,7 @@ public: * @return Number of addresses appended * @throws std::out_of_range Buffer overflow writing to packet */ - unsigned int gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer &appendTo,unsigned int limit) const; + unsigned int gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer &appendTo,unsigned int limit) const; /** * Get subscribers to a multicast group diff --git a/node/Network.cpp b/node/Network.cpp index 1643487f..c66409b3 100644 --- a/node/Network.cpp +++ b/node/Network.cpp @@ -961,7 +961,7 @@ void Network::multicastUnsubscribe(const MulticastGroup &mg) } } -uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr) +uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr) { if (_destroyed) { return 0; diff --git a/node/Network.hpp b/node/Network.hpp index cc85b7d1..74df940a 100644 --- a/node/Network.hpp +++ b/node/Network.hpp @@ -28,6 +28,7 @@ #include "Hashtable.hpp" #include "Address.hpp" #include "Mutex.hpp" +#include "Packet.hpp" #include "SharedPtr.hpp" #include "AtomicCounter.hpp" #include "MulticastGroup.hpp" @@ -191,7 +192,7 @@ public: * @param ptr Index of chunk and related fields in packet * @return Update ID if update was fully assembled and accepted or 0 otherwise */ - uint64_t handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr); + uint64_t handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer &chunk,unsigned int ptr); /** * Set network configuration diff --git a/node/Packet.hpp b/node/Packet.hpp index f607d1f5..0f5bd3ab 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -232,6 +232,8 @@ /** * Packet buffer size (can be changed) */ +#define ZT_PROTO_ADDITIONAL_CAMO_LENGTH 4 + #define ZT_PROTO_MAX_PACKET_LENGTH (ZT_MAX_PACKET_FRAGMENTS * ZT_DEFAULT_PHYSMTU) /** @@ -388,7 +390,7 @@ namespace ZeroTier { * For unencrypted packets, MAC is computed on plaintext. Only HELLO is ever * sent in the clear, as it's the "here is my public key" message. */ -class Packet : public Buffer +class Packet : public Buffer { public: /** @@ -417,22 +419,22 @@ public: * receipt to authenticate and decrypt; there is no per-fragment MAC. (But if * fragments are corrupt, the MAC will fail for the whole assembled packet.) */ - class Fragment : public Buffer + class Fragment : public Buffer { public: Fragment() : - Buffer() + Buffer() { } template Fragment(const Buffer &b) : - Buffer(b) + Buffer(b) { } Fragment(const void *data,unsigned int len) : - Buffer(data,len) + Buffer(data,len) { } @@ -1091,12 +1093,12 @@ public: template Packet(const Buffer &b) : - Buffer(b) + Buffer(b) { } Packet(const void *data,unsigned int len) : - Buffer(data,len) + Buffer(data,len) { } @@ -1108,7 +1110,7 @@ public: * the header. Payload should be appended; initial size is header size. */ Packet() : - Buffer(ZT_PROTO_MIN_PACKET_LENGTH) + Buffer(ZT_PROTO_MIN_PACKET_LENGTH) { Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); (*this)[ZT_PACKET_IDX_FLAGS] = 0; // zero flags, cipher ID, and hops @@ -1124,7 +1126,7 @@ public: * @param dest Destination ZeroTier address for new packet */ Packet(const Packet &prototype,const Address &dest) : - Buffer(prototype) + Buffer(prototype) { Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); setDestination(dest); @@ -1138,7 +1140,7 @@ public: * @param v Verb */ Packet(const Address &dest,const Address &source,const Verb v) : - Buffer(ZT_PROTO_MIN_PACKET_LENGTH) + Buffer(ZT_PROTO_MIN_PACKET_LENGTH) { Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8); setDestination(dest); diff --git a/node/Peer.cpp b/node/Peer.cpp index f77b4e6f..fb6f4147 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -23,6 +23,7 @@ #include "RingBuffer.hpp" #include "Utils.hpp" #include "Metrics.hpp" +#include "Buffer.hpp" namespace ZeroTier { @@ -247,6 +248,7 @@ void Peer::received( outp->compress(); outp->armor(_key,true,aesKeysIfSupported()); Metrics::pkt_push_direct_paths_out++; + CT("UNPROCESSED, packetId: %lx", outp->packetId()); path->send(RR,tPtr,outp->data(),outp->size(),now); } delete outp; @@ -393,6 +395,7 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o } outp.armor(_key,true,aesKeysIfSupported()); Metrics::pkt_rendezvous_out++; + CT("UNPROCESSED"); _paths[mine].p->send(RR,tPtr,outp.data(),outp.size(),now); } else { Packet outp(other->_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); @@ -408,6 +411,7 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o } outp.armor(other->_key,true,other->aesKeysIfSupported()); Metrics::pkt_rendezvous_out++; + CT("UNPROCESSED"); other->_paths[theirs].p->send(RR,tPtr,outp.data(),outp.size(),now); } ++alt; @@ -456,6 +460,7 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA RR->node->putPacket(tPtr,RR->node->lowBandwidthModeEnabled() ? localSocket : -1,atAddress,outp.data(),outp.size()); } else { RR->node->expectReplyTo(outp.packetId()); + CT("UNPROCESSED"); RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC } } diff --git a/node/Peer.hpp b/node/Peer.hpp index 777a1e96..aeca75b1 100644 --- a/node/Peer.hpp +++ b/node/Peer.hpp @@ -35,6 +35,7 @@ #include "Bond.hpp" #include "AES.hpp" #include "Metrics.hpp" +#include "CamoPattern.hpp" #define ZT_PEER_MAX_SERIALIZED_STATE_SIZE (sizeof(Peer) + 32 + (sizeof(Path) * 2)) @@ -143,6 +144,7 @@ public: { SharedPtr bp(getAppropriatePath(now,force)); if (bp) { + CT("UNPROCESSED"); return bp->send(RR,tPtr,data,len,now); } return false; diff --git a/node/Switch.cpp b/node/Switch.cpp index 7664f7a4..9f93d781 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -22,6 +22,7 @@ #include "../include/ZeroTierOne.h" #include "Constants.hpp" +#include "Hashtable.hpp" #include "RuntimeEnvironment.hpp" #include "Switch.hpp" #include "Node.hpp" @@ -33,6 +34,8 @@ #include "Trace.hpp" #include "Metrics.hpp" +#include "CamoPattern.hpp" + namespace ZeroTier { Switch::Switch(const RuntimeEnvironment *renv) : @@ -78,18 +81,32 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre { int32_t flowId = ZT_QOS_NO_FLOW; try { + char buf[64]; + fromAddr.toIpString(buf); + CT("INCOMING PACKET localSocket: %ld, IP: %s:%u, isDefaultRoute: %u", localSocket, buf, fromAddr.port(), fromAddr.isDefaultRoute()); + + Packet remotePacket(data, len); + CT("PACKET CONTENTS:"); + remotePacket.dump(); + bool hadCamo = CamoPattern::stripCamo(remotePacket); + if (hadCamo) + { + CT("PACKET HAS CAMO. CONTENTS WITHOUT CAMO:"); + remotePacket.dump(); + } + const int64_t now = RR->node->now(); const SharedPtr path(RR->topology->getPath(localSocket,fromAddr)); path->received(now); - if (len == 13) { + if (remotePacket.size() == 13) { /* LEGACY: before VERB_PUSH_DIRECT_PATHS, peers used broadcast * announcements on the LAN to solve the 'same network problem.' We * no longer send these, but we'll listen for them for a while to * locate peers with versions <1.0.4. */ - const Address beaconAddr(reinterpret_cast(data) + 8,5); + const Address beaconAddr(remotePacket.destination()); if (beaconAddr == RR->identity.address()) { return; } @@ -103,15 +120,19 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre Packet outp(peer->address(),RR->identity.address(),Packet::VERB_NOP); outp.armor(peer->key(),true,peer->aesKeysIfSupported()); Metrics::pkt_nop_out++; + if (CamoPattern::isCamoRequired(beaconAddr, RR, hadCamo, true)) + { + CamoPattern::applyCamo(outp); + } path->send(RR,tPtr,outp.data(),outp.size(),now); } } } else if (len > ZT_PROTO_MIN_FRAGMENT_LENGTH) { // SECURITY: min length check is important since we do some C-style stuff below! - if (reinterpret_cast(data)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR) { + if (reinterpret_cast(remotePacket[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR]) == ZT_PACKET_FRAGMENT_INDICATOR) { // Handle fragment ---------------------------------------------------- - Packet::Fragment fragment(data,len); + Packet::Fragment fragment(remotePacket); const Address destination(fragment.destination()); if (destination != RR->identity.address()) { @@ -128,6 +149,10 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre if ((!relayTo)||(!relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,false))) { // Don't know peer or no direct path -- so relay via someone upstream relayTo = RR->topology->getUpstreamPeer(); + if (CamoPattern::isCamoRequired(destination, RR, hadCamo, true)) + { + CamoPattern::applyCamo(fragment); + } if (relayTo) { relayTo->sendDirect(tPtr,fragment.data(),fragment.size(),now,true); } @@ -184,8 +209,8 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre } else if (len >= ZT_PROTO_MIN_PACKET_LENGTH) { // min length check is important! // Handle packet head ------------------------------------------------- - const Address destination(reinterpret_cast(data) + 8,ZT_ADDRESS_LENGTH); - const Address source(reinterpret_cast(data) + 13,ZT_ADDRESS_LENGTH); + const Address destination(remotePacket.destination()); + const Address source(remotePacket.source()); if (source == RR->identity.address()) { return; @@ -196,12 +221,14 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre return; } - Packet packet(data,len); - - if (packet.hops() < ZT_RELAY_MAX_HOPS) { - packet.incrementHops(); + if (remotePacket.hops() < ZT_RELAY_MAX_HOPS) { + remotePacket.incrementHops(); SharedPtr relayTo = RR->topology->getPeer(tPtr,destination); - if ((relayTo)&&(relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,false))) { + if (CamoPattern::isCamoRequired(destination, RR, hadCamo, true)) + { + CamoPattern::applyCamo(remotePacket); + } + if ((relayTo)&&(relayTo->sendDirect(tPtr,remotePacket.data(),remotePacket.size(),now,false))) { if ((source != RR->identity.address())&&(_shouldUnite(now,source,destination))) { const SharedPtr sourcePeer(RR->topology->getPeer(tPtr,source)); if (sourcePeer) { @@ -211,7 +238,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre } else { relayTo = RR->topology->getUpstreamPeer(); if ((relayTo)&&(relayTo->address() != source)) { - if (relayTo->sendDirect(tPtr,packet.data(),packet.size(),now,true)) { + if (relayTo->sendDirect(tPtr,remotePacket.data(),remotePacket.size(),now,true)) { const SharedPtr sourcePeer(RR->topology->getPeer(tPtr,source)); if (sourcePeer) { relayTo->introduce(tPtr,now,sourcePeer); @@ -220,19 +247,10 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre } } } - } else if ((reinterpret_cast(data)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0) { + } else if ((reinterpret_cast(remotePacket[ZT_PACKET_IDX_FLAGS]) & ZT_PROTO_FLAG_FRAGMENTED) != 0) { // Packet is the head of a fragmented packet series - const uint64_t packetId = ( - (((uint64_t)reinterpret_cast(data)[0]) << 56) | - (((uint64_t)reinterpret_cast(data)[1]) << 48) | - (((uint64_t)reinterpret_cast(data)[2]) << 40) | - (((uint64_t)reinterpret_cast(data)[3]) << 32) | - (((uint64_t)reinterpret_cast(data)[4]) << 24) | - (((uint64_t)reinterpret_cast(data)[5]) << 16) | - (((uint64_t)reinterpret_cast(data)[6]) << 8) | - ((uint64_t)reinterpret_cast(data)[7]) - ); + const uint64_t packetId = remotePacket.packetId(); RXQueueEntry *const rq = _findRXQueueEntry(packetId); Mutex::Lock rql(rq->lock); @@ -242,7 +260,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre rq->flowId = flowId; rq->timestamp = now; rq->packetId = packetId; - rq->frag0.init(data,len,path,now); + rq->frag0.init(remotePacket,path,now); rq->totalFragments = 0; rq->haveFragments = 1; rq->complete = false; @@ -252,7 +270,7 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre if ((rq->totalFragments > 1)&&(Utils::countBits(rq->haveFragments |= 1) == rq->totalFragments)) { // We have all fragments -- assemble and process full Packet - rq->frag0.init(data,len,path,now); + rq->frag0.init(remotePacket,path,now); for(unsigned int f=1;ftotalFragments;++f) { rq->frag0.append(rq->frags[f - 1].payload(),rq->frags[f - 1].payloadLength()); } @@ -264,12 +282,12 @@ void Switch::onRemotePacket(void *tPtr,const int64_t localSocket,const InetAddre } } else { // Still waiting on more fragments, but keep the head - rq->frag0.init(data,len,path,now); + rq->frag0.init(remotePacket,path,now); } } // else this is a duplicate head, ignore } else { // Packet is unfragmented, so just process it - IncomingPacket packet(data,len,path,now); + IncomingPacket packet(remotePacket,path,now); if (!packet.tryDecode(RR,tPtr,flowId)) { RXQueueEntry *const rq = _nextRXQueueEntry(); Mutex::Lock rql(rq->lock); @@ -1127,6 +1145,199 @@ bool Switch::_trySend(void *tPtr,Packet &packet,bool encrypt,int32_t flowId) return false; } +#define NEWOUT +#ifdef NEWOUT +void Switch::_sendViaSpecificPath(void *tPtr,SharedPtr peer,SharedPtr viaPath,uint16_t userSpecifiedMtu, int64_t now,Packet &packet,bool encrypt,int32_t flowId) +{ + unsigned int mtu = ZT_DEFAULT_PHYSMTU; + uint64_t trustedPathId = 0; + RR->topology->getOutboundPathInfo(viaPath->address(),mtu,trustedPathId); + + char buf[64]; + + Address destination = packet.destination(); + destination.toString(buf); + + Identity destinationIdentity; + + RR->topology->getIdentity(&destinationIdentity, destination); + CT("OUTGOING PACKET ZT ADDRESS: %s, isUpstream: %b, isProhibitedEndpoint: %b", buf, RR->topology->isUpstream(destinationIdentity), RR->topology->isProhibitedEndpoint(destination, InetAddress())); + + + ZT_PeerRole role = RR->topology->role(destination); + + switch(role) + { + case ZT_PEER_ROLE_PLANET: + strcpy(buf, "PLANET"); + break; + case ZT_PEER_ROLE_MOON: + strcpy(buf, "MOON"); + break; + case ZT_PEER_ROLE_LEAF: + strcpy(buf, "LEAF"); + break; + default: + strcpy(buf, "UNKNOWN"); + break; + } + + CT("DESTINATION ROLE: %s", buf); + + switch(packet.verb()) + { + case Packet::VERB_NOP: + strcpy(buf, "NOP"); + break; + case Packet::VERB_HELLO: + strcpy(buf, "HELLO"); + break; + case Packet::VERB_ERROR: + strcpy(buf, "ERROR"); + break; + case Packet::VERB_OK: + strcpy(buf, "OK"); + break; + case Packet::VERB_WHOIS: + strcpy(buf, "WHOIS"); + break; + case Packet::VERB_RENDEZVOUS: + strcpy(buf, "RENDEZVOUS"); + break; + case Packet::VERB_FRAME: + strcpy(buf, "FRAME"); + break; + case Packet::VERB_EXT_FRAME: + strcpy(buf, "EXT_FRAME"); + break; + case Packet::VERB_ECHO: + strcpy(buf, "ECHO"); + break; + case Packet::VERB_MULTICAST_LIKE: + strcpy(buf, "MULTICAST_LIKE"); + break; + case Packet::VERB_NETWORK_CREDENTIALS: + strcpy(buf, "NETWORK_CREDENTIALS"); + break; + case Packet::VERB_NETWORK_CONFIG_REQUEST: + strcpy(buf, "NETWORK_CONFIG_REQUEST"); + break; + case Packet::VERB_NETWORK_CONFIG: + strcpy(buf, "NETWORK_CONFIG"); + break; + case Packet::VERB_MULTICAST_GATHER: + strcpy(buf, "MULTICAST_GATHER"); + break; + case Packet::VERB_MULTICAST_FRAME: + strcpy(buf, "MULTICAST_FRAME"); + break; + case Packet::VERB_PUSH_DIRECT_PATHS: + strcpy(buf, "PUSH_DIRECT_PATHS"); + break; + case Packet::VERB_ACK: + strcpy(buf, "ACK"); + break; + case Packet::VERB_QOS_MEASUREMENT: + strcpy(buf, "QOS_MEASUREMENT"); + break; + case Packet::VERB_USER_MESSAGE: + strcpy(buf, "USER_MESSAGE"); + break; + case Packet::VERB_REMOTE_TRACE: + strcpy(buf, "REMOTE_TRACE"); + break; + case Packet::VERB_PATH_NEGOTIATION_REQUEST: + strcpy(buf, "PATH_NEGOTIATION_REQUEST"); + break; + default: + strcpy(buf, "UNKNOWN"); + break; + }; + + CT("PACKET VERB: %s", buf); + + bool isController = false; + { + Mutex::Lock _l(RR->node->_networks_m); + Hashtable>::Iterator i(RR->node->_networks); + uint64_t * k = (uint64_t *)0; + SharedPtr *v = (SharedPtr *)0; + while(i.next(k, v)) + { + if (destination == ((*v)->controller())) + { + isController = true; + break; + } + } + } + + CT("isController: %b", isController); + + if (userSpecifiedMtu > 0) { + mtu = userSpecifiedMtu; + } + + bool isCamoRequired = CamoPattern::isCamoRequired(destination, RR); + + unsigned int camoSize = isCamoRequired ? ZT_PROTO_ADDITIONAL_CAMO_LENGTH : 0; + unsigned int packetSizeCamo = packet.size() + camoSize; + unsigned int chunkSize = std::min(packetSizeCamo, mtu); + bool isFragmented = chunkSize < (packetSizeCamo); + packet.setFragmented(isFragmented); + + CT("PACKET CONTENTS:"); + packet.dump(); + if (trustedPathId) { + packet.setTrusted(trustedPathId); + } else { + if (!packet.isEncrypted()) { + packet.armor(peer->key(),encrypt,peer->aesKeysIfSupported()); + } + RR->node->expectReplyTo(packet.packetId()); + } + CT("PACKET CONTENTS AFTER ENCRYPTION:"); + packet.dump(); + + peer->recordOutgoingPacket(viaPath, packet.packetId(), packet.payloadLength(), packet.verb(), flowId, now); + + if (!isFragmented) + { + CT("UNFRAGMENTED BRANCH"); + if (isCamoRequired) + { + CamoPattern::applyCamo(packet); + } + viaPath->send(RR,tPtr,packet.data(),chunkSize,now); + } + else + { + CT("FRAGMENTED BRANCH"); + // Too big for one packet, fragment it + unsigned int minFragmentSize = ZT_PROTO_MIN_FRAGMENT_LENGTH + camoSize; + unsigned int fragStart = 0; + unsigned int remaining = packet.size(); + unsigned int fragSize = mtu - minFragmentSize; + unsigned int fragsRemaining = (remaining / (fragSize)); + if ((fragsRemaining * fragSize) < remaining) { + ++fragsRemaining; + } + const unsigned int totalFragments = fragsRemaining; + + for(unsigned int fno=0;fnosend(RR,tPtr,frag.data(),frag.size(),now); + fragStart += chunkSize; + remaining -= chunkSize; + } + } +} +#else void Switch::_sendViaSpecificPath(void *tPtr,SharedPtr peer,SharedPtr viaPath,uint16_t userSpecifiedMtu, int64_t now,Packet &packet,bool encrypt,int32_t flowId) { unsigned int mtu = ZT_DEFAULT_PHYSMTU; @@ -1171,6 +1382,7 @@ void Switch::_sendViaSpecificPath(void *tPtr,SharedPtr peer,SharedPtr knownHosts; + json &settings = lc["settings"]; if (settings.is_object()) { // Allow controller DB path to be put somewhere else @@ -1487,7 +1500,150 @@ public: } } } + + // Camo settings + json &camo = settings["camo"]; + if (camo.is_object()) + { + CT("CAMO CONFIG SECTION FOUND"); + std::string camoLevelStr = OSUtils::jsonString(camo["level"], "none"); + std::transform(camoLevelStr.begin(), camoLevelStr.end(), camoLevelStr.begin(), [](unsigned char c) + { + return std::tolower(c); + }); + CT("CAMO LEVEL SETTING: %s", camoLevelStr.c_str()); + + if (camoLevelStr == "node") + { + camoLevel = CamoLevel::NODE; + } + else if (camoLevelStr == "controller") + { + camoLevel = CamoLevel::CONTROLLER; + } + else if (camoLevelStr == "moon") + { + camoLevel = CamoLevel::MOON; + } + else if (camoLevelStr == "planet") + { + camoLevel = CamoLevel::PLANET; + } + + if (camo.contains("word")) + { + std::string temp = OSUtils::jsonString(camo["word"], ZT_CAMO_DEFAULT_WORDSTR); + if (temp.substr(0, 2) == "0x") + { + try + { + camoWord = std::stoul(temp.substr(2), nullptr, 16); + } + catch (...) + { + } + } + else + { + for (size_t i = 0; i < BYTES_IN_WORD; i++) + { + char c = ' '; + if (i < temp.size()) + { + c = temp[i]; + } + camoWord |= c; + camoWord <<= 8; + } + } + } + CT("CAMO WORD SETTING: %x", camoWord); + + std::string relayRuleStr = OSUtils::jsonString(camo["relayRule"], "leave"); + std::transform(relayRuleStr.begin(), relayRuleStr.end(), relayRuleStr.begin(), [](unsigned char c) + { + return std::tolower(c); + }); + if (relayRuleStr == "knownhosts") + { + relayRule = CamoRelayRule::KNOWNHOSTS; + } + else if (relayRuleStr == "strip") + { + relayRule = CamoRelayRule::STRIP; + } + else if (relayRuleStr == "apply") + { + relayRule = CamoRelayRule::APPLY; + } + CT("CAMO RELAY RULE SETTING: %s", relayRuleStr.c_str()); + + json &knownHostsSection = camo["knownHosts"]; + if (knownHostsSection.is_object()) + { + CT("KNOWN HOSTS SECTION FOUND"); + auto processLevelSection = [&knownHosts](const json §ion, CamoLevel level) + { + if (section.is_array()) + { + for (const auto &addrStr: section) + { + std::string addr = OSUtils::jsonString(addrStr, ""); + if (!addr.empty()) + { + Address host (Utils::hexStrToU64(addr.c_str())); + if (host) + { + CT("VALID HOST FOUND: %s", addr.c_str()); + knownHosts[host] = level; + } + } + } + } + }; + + for (auto it = knownHostsSection.begin(); it != knownHostsSection.end(); it++) + { + std::string levelKey = it.key(); + std::transform(levelKey.begin(), levelKey.end(), levelKey.begin(), [](unsigned char c) + { + return std::tolower(c); + }); + + CT("FOUND CAMO LEVEL: %s", levelKey.c_str()); + if (levelKey == "none") + { + processLevelSection(it.value(), CamoLevel::NONE); + } + else if (levelKey == "node") + { + processLevelSection(it.value(), CamoLevel::NODE); + } + else if (levelKey == "controller") + { + processLevelSection(it.value(), CamoLevel::CONTROLLER); + } + else if (levelKey == "moon") + { + processLevelSection(it.value(), CamoLevel::MOON); + } + else if (levelKey == "planet") + { + processLevelSection(it.value(), CamoLevel::PLANET); + } + else + { + processLevelSection(it.value(), CamoLevel::INAPPLICABLE); + } + } + } + } + else + { + CT("CAMO CONFIG SECTION NOT FOUND"); + } } + CamoPattern::init(camoLevel, camoWord, knownHosts, relayRule); // Set trusted paths if there are any if (!ppc.empty()) { From 5fb3f5c22870f023710ef465bf46146a305c6016 Mon Sep 17 00:00:00 2001 From: eerieaerial <205630019+eerieaerial@users.noreply.github.com> Date: Thu, 1 May 2025 20:39:24 +0400 Subject: [PATCH 11/13] instrumentation improvement --- node/IncomingPacket.cpp | 79 ++++++++++++++++++++++++++++++++++------- node/Multicaster.cpp | 4 ++- node/Peer.cpp | 16 ++++++--- node/Switch.cpp | 18 ++++++++++ 4 files changed, 100 insertions(+), 17 deletions(-) diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 71fb0f5e..071c7236 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -19,6 +19,7 @@ #include "../include/ZeroTierOne.h" #include "Constants.hpp" +#include "Identity.hpp" #include "RuntimeEnvironment.hpp" #include "IncomingPacket.hpp" #include "Topology.hpp" @@ -62,6 +63,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr,int32_t f return true; } } else if ((c == ZT_PROTO_CIPHER_SUITE__C25519_POLY1305_NONE)&&(verb() == Packet::VERB_HELLO)) { + CT("INCOMING CLEARTEXT HELLO"); // Only HELLO is allowed in the clear, but will still have a MAC return _doHELLO(RR,tPtr,false); } @@ -89,66 +91,87 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr,int32_t f //case Packet::VERB_NOP: default: // ignore unknown verbs, but if they pass auth check they are "received" Metrics::pkt_nop_in++; + CT("UNKNOWN VERB"); peer->received(tPtr,_path,hops(),packetId(),payloadLength(),v,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW); break; case Packet::VERB_HELLO: + CT("INCOMING HELLO"); r = _doHELLO(RR, tPtr, true); break; case Packet::VERB_ACK: + CT("INCOMING VERB_ACK"); r = _doACK(RR, tPtr, peer); break; case Packet::VERB_QOS_MEASUREMENT: + CT("INCOMING QOS_MEASUREMENT"); r = _doQOS_MEASUREMENT(RR, tPtr, peer); break; case Packet::VERB_ERROR: + CT("INCOMING ERROR"); r = _doERROR(RR, tPtr, peer); break; case Packet::VERB_OK: + CT("INCOMING OK"); r = _doOK(RR, tPtr, peer); break; case Packet::VERB_WHOIS: + CT("INCOMING WHOIS"); r = _doWHOIS(RR, tPtr, peer); break; case Packet::VERB_RENDEZVOUS: + CT("INCOMING RENDEZVOUS"); r = _doRENDEZVOUS(RR, tPtr, peer); break; case Packet::VERB_FRAME: + CT("INCOMING FRAME"); r = _doFRAME(RR, tPtr, peer, flowId); break; case Packet::VERB_EXT_FRAME: + CT("INCOMING EXT_FRAME"); r = _doEXT_FRAME(RR, tPtr, peer, flowId); break; case Packet::VERB_ECHO: + CT("INCOMING ECHO"); r = _doECHO(RR, tPtr, peer); break; case Packet::VERB_MULTICAST_LIKE: + CT("INCOMING MULTICAST_LIKE"); r = _doMULTICAST_LIKE(RR, tPtr, peer); break; case Packet::VERB_NETWORK_CREDENTIALS: + CT("INCOMING NETWORK_CREDENTIALS"); r = _doNETWORK_CREDENTIALS(RR, tPtr, peer); break; case Packet::VERB_NETWORK_CONFIG_REQUEST: + CT("INCOMING CONFIG_REQUEST"); r = _doNETWORK_CONFIG_REQUEST(RR, tPtr, peer); break; case Packet::VERB_NETWORK_CONFIG: + CT("INCOMING NETWORK_CONFIG"); r = _doNETWORK_CONFIG(RR, tPtr, peer); break; case Packet::VERB_MULTICAST_GATHER: + CT("INCOMING MULTICAST_GATHER"); r = _doMULTICAST_GATHER(RR, tPtr, peer); break; case Packet::VERB_MULTICAST_FRAME: + CT("INCOMING MULTICAST_FRAME"); r = _doMULTICAST_FRAME(RR, tPtr, peer); break; case Packet::VERB_PUSH_DIRECT_PATHS: + CT("INCOMING PUSH_DIRECT_PATHS"); r = _doPUSH_DIRECT_PATHS(RR, tPtr, peer); break; case Packet::VERB_USER_MESSAGE: + CT("INCOMING USER_MESSAGE"); r = _doUSER_MESSAGE(RR, tPtr, peer); break; case Packet::VERB_REMOTE_TRACE: + CT("INCOMING REMOTE_TRACE"); r = _doREMOTE_TRACE(RR, tPtr, peer); break; case Packet::VERB_PATH_NEGOTIATION_REQUEST: + CT("INCOMING PATH_NEGOTIATION_REQUEST"); r = _doPATH_NEGOTIATION_REQUEST(RR, tPtr, peer); break; } @@ -158,6 +181,7 @@ bool IncomingPacket::tryDecode(const RuntimeEnvironment *RR,void *tPtr,int32_t f } return false; } else { + CT("REQUESTING WHOIS"); RR->sw->requestWhois(tPtr,RR->node->now(),sourceAddress); return false; } @@ -375,7 +399,9 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool const int64_t timestamp = at(ZT_PROTO_VERB_HELLO_IDX_TIMESTAMP); Identity id; unsigned int ptr = ZT_PROTO_VERB_HELLO_IDX_IDENTITY + id.deserialize(*this,ZT_PROTO_VERB_HELLO_IDX_IDENTITY); - + char buf[64]; + id.address().toString(buf); + CT("HELLO FROM %s", buf); if (protoVersion < ZT_PROTO_VERSION_MIN) { RR->t->incomingPacketDroppedHELLO(tPtr,_path,pid,fromAddress,"protocol version too old"); return true; @@ -408,7 +434,8 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool outp.armor(key,true,peer->aesKeysIfSupported()); Metrics::pkt_error_out++; Metrics::pkt_error_identity_collision_out++; - CT("UNPROCESSED"); + outp.destination().toString(buf); + CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } else { RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC"); @@ -567,7 +594,8 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool outp.armor(peer->key(),true,peer->aesKeysIfSupported()); peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); Metrics::pkt_ok_out++; - CT("UNPROCESSED, packetId: %lx", outp.packetId()); + outp.destination().toString(buf); + CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); _path->send(RR,tPtr,outp.data(),outp.size(),now); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version @@ -638,10 +666,14 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP if (RR->topology->isUpstream(peer->identity())) { const Identity id(*this,ZT_PROTO_VERB_WHOIS__OK__IDX_IDENTITY); RR->sw->doAnythingWaitingForPeer(tPtr,RR->topology->addPeer(tPtr,SharedPtr(new Peer(RR,RR->identity,id)))); + char buf[64]; + id.address().toString(buf); + CT("GOT OK REPLY TO WHOIS %s", buf); } break; case Packet::VERB_NETWORK_CONFIG_REQUEST: { + CT("GOT OK REPLY TO NETWORK_CONFIG_REQUEST"); networkId = at(ZT_PROTO_VERB_OK_IDX_PAYLOAD); const SharedPtr network(RR->node->network(networkId)); if (network) { @@ -650,6 +682,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP } break; case Packet::VERB_MULTICAST_GATHER: { + CT("GOT OK REPLY TO MULTICAST_GATHER"); networkId = at(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID); const SharedPtr network(RR->node->network(networkId)); if (network) { @@ -660,6 +693,7 @@ bool IncomingPacket::_doOK(const RuntimeEnvironment *RR,void *tPtr,const SharedP } break; case Packet::VERB_MULTICAST_FRAME: { + CT("GOT OK REPLY TO MULTICAST_FRAME"); const unsigned int flags = (*this)[ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_FLAGS]; networkId = at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_NETWORK_ID); const MulticastGroup mg(MAC(field(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_MAC,6),6),at(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI)); @@ -714,6 +748,9 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar while ((ptr + ZT_ADDRESS_LENGTH) <= size()) { const Address addr(field(ptr,ZT_ADDRESS_LENGTH),ZT_ADDRESS_LENGTH); ptr += ZT_ADDRESS_LENGTH; + char buf[64]; + addr.toString(buf); + CT("GOT WHOIS REQUEST ON %s", buf); const Identity id(RR->topology->getIdentity(tPtr,addr)); if (id) { @@ -728,7 +765,9 @@ bool IncomingPacket::_doWHOIS(const RuntimeEnvironment *RR,void *tPtr,const Shar if (count > 0) { Metrics::pkt_ok_out++; outp.armor(peer->key(),true,peer->aesKeysIfSupported()); - CT("UNPROCESSED"); + char buf[64]; + outp.destination().toString(buf); + CT("WHOIS REPLY, packetId: %lx, address: %s", outp.packetId(), buf); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } @@ -959,7 +998,9 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const outp.armor(peer->key(),true,peer->aesKeysIfSupported()); peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); Metrics::pkt_ok_out++; - CT("UNPROCESSED"); + char buf[64]; + outp.destination().toString(buf); + CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } @@ -989,7 +1030,9 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const Share outp.armor(peer->key(),true,peer->aesKeysIfSupported()); peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); Metrics::pkt_ok_out++; - CT("UNPROCESSED, packetID: %lx", outp.packetId()); + char buf[64]; + outp.destination().toString(buf); + CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); peer->received(tPtr,_path,hops(),pid,payloadLength(),Packet::VERB_ECHO,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW); @@ -1186,7 +1229,9 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void outp.armor(peer->key(),true,peer->aesKeysIfSupported()); Metrics::pkt_error_out++; Metrics::pkt_error_unsupported_op_out++; - CT("UNPROCESSED"); + char buf[64]; + outp.destination().toString(buf); + CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } @@ -1211,7 +1256,9 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,c outp.armor(peer->key(),true,peer->aesKeysIfSupported()); peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); Metrics::pkt_ok_out++; - CT("UNPROCESSED"); + char buf[64]; + outp.destination().toString(buf); + CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } @@ -1255,7 +1302,9 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr outp.armor(peer->key(),true,peer->aesKeysIfSupported()); peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); Metrics::pkt_ok_out++; - CT("UNPROCESSED"); + char buf[64]; + outp.destination().toString(buf); + CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); _path->send(RR,tPtr,outp.data(),outp.size(),now); } } @@ -1329,7 +1378,9 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, const uint8_t *const frameData = (const uint8_t *)field(offset + ZT_PROTO_VERB_MULTICAST_FRAME_IDX_FRAME,frameLen); if ((flags & 0x08)&&(network->config().isMulticastReplicator(RR->identity.address()))) { - CT("UNPROCESSED"); + char buf[64]; + peer->address().toString(buf); + CT("UNPROCESSED MULTICAST, address: %s", buf); RR->mc->send(tPtr,RR->node->now(),network,peer->address(),to,from,etherType,frameData,frameLen); } @@ -1361,7 +1412,9 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, outp.armor(peer->key(),true,peer->aesKeysIfSupported()); peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); Metrics::pkt_ok_out++; - CT("UNPROCESSED"); + char buf[64]; + outp.destination().toString(buf); + CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } @@ -1504,7 +1557,9 @@ void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void outp.armor(peer->key(),true,peer->aesKeysIfSupported()); Metrics::pkt_error_out++; Metrics::pkt_error_need_membership_cert_out++; - CT("UNPROCESSED"); + char buf[64]; + outp.destination().toString(buf); + CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 8b9e572b..8fe601d1 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -201,7 +201,9 @@ void Multicaster::send( } outp.armor(bestMulticastReplicator->key(),true,bestMulticastReplicator->aesKeysIfSupported()); Metrics::pkt_multicast_frame_out++; - CT("UNPROCESSED"); + char buf[64]; + outp.destination().toString(buf); + CT("UNPROCESSED MULTICAST, packetId: %lx, address: %s", outp.packetId(), buf); bestMulticastReplicatorPath->send(RR,tPtr,outp.data(),outp.size(),now); return; } diff --git a/node/Peer.cpp b/node/Peer.cpp index fb6f4147..17b07ab3 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -248,7 +248,9 @@ void Peer::received( outp->compress(); outp->armor(_key,true,aesKeysIfSupported()); Metrics::pkt_push_direct_paths_out++; - CT("UNPROCESSED, packetId: %lx", outp->packetId()); + char buf[64]; + outp->destination().toString(buf); + CT("UNPROCESSED, packetId: %lx, address: %s", outp->packetId(), buf); path->send(RR,tPtr,outp->data(),outp->size(),now); } delete outp; @@ -395,7 +397,9 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o } outp.armor(_key,true,aesKeysIfSupported()); Metrics::pkt_rendezvous_out++; - CT("UNPROCESSED"); + char buf[64]; + outp.destination().toString(buf); + CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); _paths[mine].p->send(RR,tPtr,outp.data(),outp.size(),now); } else { Packet outp(other->_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); @@ -411,7 +415,9 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o } outp.armor(other->_key,true,other->aesKeysIfSupported()); Metrics::pkt_rendezvous_out++; - CT("UNPROCESSED"); + char buf[64]; + outp.destination().toString(buf); + CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); other->_paths[theirs].p->send(RR,tPtr,outp.data(),outp.size(),now); } ++alt; @@ -460,7 +466,9 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA RR->node->putPacket(tPtr,RR->node->lowBandwidthModeEnabled() ? localSocket : -1,atAddress,outp.data(),outp.size()); } else { RR->node->expectReplyTo(outp.packetId()); - CT("UNPROCESSED"); + char buf[64]; + outp.destination().toString(buf); + CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC } } diff --git a/node/Switch.cpp b/node/Switch.cpp index 9f93d781..d32c3de0 100644 --- a/node/Switch.cpp +++ b/node/Switch.cpp @@ -1288,6 +1288,23 @@ void Switch::_sendViaSpecificPath(void *tPtr,SharedPtr peer,SharedPtr(packet.payload()); + size_t payloadLength = packet.payloadLength(); + + Address addr; + switch(packet.verb()) + { + case Packet::VERB_WHOIS: + addr.setTo(packet.field(ZT_PACKET_IDX_PAYLOAD, ZT_ADDRESS_LENGTH), ZT_ADDRESS_LENGTH); + addr.toString((buf)); + CT("ASKING WHOIS %s", buf); + break; + + default: + break; + } + if (trustedPathId) { packet.setTrusted(trustedPathId); } else { @@ -1296,6 +1313,7 @@ void Switch::_sendViaSpecificPath(void *tPtr,SharedPtr peer,SharedPtrnode->expectReplyTo(packet.packetId()); } + CT("PACKET CONTENTS AFTER ENCRYPTION:"); packet.dump(); From 235addc585afc1feaebca81a00a0de09d7bb2c94 Mon Sep 17 00:00:00 2001 From: eerieaerial <205630019+eerieaerial@users.noreply.github.com> Date: Mon, 12 May 2025 14:04:06 +0400 Subject: [PATCH 12/13] added readme; added special case camouflaging --- README.camo.md | 158 ++++++++++++++++++++++++++++++++++++++++ README.md | 2 + node/CamoPattern.cpp | 8 +- node/CamoPattern.hpp | 95 ++++++++++++++---------- node/IncomingPacket.cpp | 54 +++++++++++--- node/Multicaster.cpp | 6 +- node/Peer.cpp | 21 +++++- service/OneService.cpp | 4 +- shell.nix | 1 + 9 files changed, 290 insertions(+), 59 deletions(-) create mode 100644 README.camo.md diff --git a/README.camo.md b/README.camo.md new file mode 100644 index 00000000..f79a84f4 --- /dev/null +++ b/README.camo.md @@ -0,0 +1,158 @@ +# Камуфлирование пакетов ZeroTier + +## Введение + +Этот патч добавляет функцию сокрытия открытых полей и данных протокола ZeroTier, условно называемую "камуфлированием". Цель операции - не криптографическая защита, а создание видимости полностью случайного содержимого пакетов. + +## Принцип работы + +### Узоры камуфлирования + +Основу механизма камуфлирования составляют 16 случайных 32-битных узоров, которые: + +- Генерируются при инициализации стандартизованным ГСЧ (вихрь Мерсенна MT19937, определённый в стандарте C++11) с фиксированным порождающим словом +- Одинаковы для всех узлов с одинаковым порождающим словом +- Используются для XOR-преобразования содержимого пакета +- Служат признаком распознавания камуфлированных пакетов + +Размер списка в 16 узоров выбран из соображений баланса между разнообразием узоров и вероятностью коллизии между признаком камуфлирования и случайно сгенерированным ID некамуфлированного пакета. Размер списка можно изменить путём задания нового значения макроса `PATTERN_COUNT` в файле `CamoPattern.hpp`. Рекомендуется использовать значения, равные степеням 2. + +### Алгоритм камуфлирования + +1. 64-битный ID в заголовке пакета разделяется на два 32-битных сегмента +2. Младший сегмент перемещается в конец пакета +3. Старший сегмент дублируется на место младшего +4. Данные от дубликата до конца пакета обрабатываются XOR со случайно выбранным узором +5. Раскамуфлирование выполняется в обратном порядке после распознавания узора + +### Распознавание камуфлированных пакетов + +Для распознавания того, камуфлирован пакет или нет, используется XOR между старшим и младшим сегментами ID. Если результат обнаружен в списке узоров, то это означает, что пакет закамуфлирован этим узором. + +### Правила обработки пакетов + +Пакеты обрабатываются на основе сравнения уровня камуфлирования адресата и отправителя. Уровень адресата определяется либо автоматически, либо заданием в настройках. Уровень отправителя определяется настройкой и относится только непосредственно к тому узлу, на котором производится обработка пакета в данный момент. + +- _Входящие_: всегда автоматически раскамуфлируются для обеспечения работы внутренних механизмов +- _Исходящие_: камуфлируются, если уровень адресата равен уровню отправителя или меньше +- _Пересылаемые_: обрабатываются согласно выбранному правилу пересылки + +### Уровни камуфлирования + +Уровни камуфлирования имеют следующие названия от низшего к высшему: + +- `NONE` +- `NODE` +- `CONTROLLER` +- `MOON` +- `PLANET` +- `INAPPLICABLE` + +Особое значение имеют два уровня: + +- `NONE` - не назначается автоматически в качестве уровня адресата. Выбор этого уровня в качестве уровня отправителя выключает камуфлирование пакетов при автоматическом выборе уровня адресата. +- `INAPPLICABLE` - в качестве уровня адресата назначается автоматически глобальным корневым серверам. Для выбора в качестве уровня отправителя недоступен. + +Прочие уровни назначаются автоматически согласно роли адресата. + +### Список известных адресатов + +При определении уровня камуфлирования для адресата проводится поиск в списке известных адресатов. Если адресат там обнаружен, то используется уровень, который присвоен в списке. Если нет - то производится автоматическое определение уровня адресата и результат заносится в список. Настройки позволяют задать изначальное содержимое списка для принудительного назначения адресатам требуемого уровня. + +### Правила пересылки + +- `LEAVE` - сохраняет исходное состояние камуфлирования пересылаемого пакета +- `KNOWNHOSTS` - применяет те же правила, что и для исходящих пакетов +- `STRIP` - принудительно снимает камуфлирование со всех пересылаемых пакетов +- `APPLY` - принудительно камуфлирует все пересылаемые пакеты + +## Настройки + +Настройки задаются в файле `local.conf` в объекте `"camo"` внутри `"settings"`: + +```json +{ + "settings": { + "camo": { + "level": "none", // Уровень отправителя + "word": "DLGE", // Порождающее слово для узоров + "relayRule": "leave", // Правило пересылки + "knownHosts": { // Предустановленные уровни адресата для узлов + "none" : [] + } + } + } +} +``` + +### Параметры + +- `"level"`: регистронезависимая строка с названием уровня отправителя. По умолчанию: `"none"`. Любые значения, не соответствующие названию существующих уровней, интерпретируются как `"none"`. Значение `"inapplicable"` также интерпретируется как `"none"`, т.к. этот уровень недоступен для выбора. +- `"word"`: строка, содержащая порождающее слово для списка узоров. Если в строке меньше 4 символов, она дополняется до 4 символов последовательностью `"DLGE"`. Строка длиннее 4 символов обрезается. Если строка начинается с `"0x"`, она интерпретируется как 32-битное шестнадцатеричное число. По умолчанию: `"DLGE"`. +- `"relayRule"`: регистронезависимая строка, содержащая название правила пересылки. По умолчанию: `"leave"`. Любые значения, не соответствующие названию существующих правил, интерпретируются как `"leave"`. +- `"knownHosts"`: объект для предустановки уровней для конкретных узлов. Названия полей объекта соответствуют уровням камуфлирования. Названия полей, не соответствующие существующим уровням, интерпретируются как `"inapplicable"`. Значение каждого поля - массив строк с адресами. + +## Примеры конфигураций + +### "Белый список" + +```json +{ + "settings": { + "camo": { + "level": "none", + "knownHosts": { + "none": ["aaaaaaaaaa"] + } + } + } +} +``` + +Эта настройка выбирает уровень отправителя `NONE`, который автоматически не назначается адресатам. Это отключает камуфлирование для всех автоматически определяемых адресатов. Адресату `aaaaaaaaaa` принудительно назначается уровень `NONE`, и т.к. этот уровень равен выбранному, пакеты для него будут камуфлироваться. + +### "Чёрный список" + +```json +{ + "settings": { + "camo": { + "level": "node", + "knownHosts": { + "inapplicable": ["aaaaaaaaaa"] + } + } + } +} +``` + +Здесь выбран уровень отправителя `NODE`, что включает камуфлирование для адресатов этого уровня и ниже. Адресату `aaaaaaaaaa` назначен уровень `INAPPLICABLE`, поэтому вне зависимости от выбранного уровня, пакеты для него камуфлироваться не будут. + +### Принудительное включение для специфических узлов + +```json +{ + "settings": { + "camo": { + "level": "node", + "knownHosts": { + "node": ["aaaaaaaaaa"] + } + } + } +} +``` + +В этом примере корневому серверу `aaaaaaaaaa`, поддерживающему работу с камуфлированными пакетами, принудительно присваивается уровень `NODE`, чтобы пакеты для него камуфлировались наряду с обычными узлами. + +### Комментарий + +По большому счёту, в `"knownHosts"` имеет смысл использовать только уровни `NONE` и `INAPPLICABLE`. Первый - принудительно включает камуфлирование для указанных адресатов, второй - выключает. + +## Перевод сети на камуфлирование + +Для перевода всей сети на камуфлирование сначала необходимо установить службу ZeroTier с данным патчем без дополнительных настроек. При этом, служба будет работать так же, как штатная. После этого, на каждом узле производится включение камуфлирования с помощью настроек. Такой процесс позволяет перевести сеть на камуфлирование пакетов без потери работоспособности всей сети. + +## Особенности сборки + +Задание макроса `CAMO_TRACE` включает выдачу отладочных сообщений на стандартный вывод службы. Для этого нужно при сборке передать команде make параметр `DEFS="-DCAMO_TRACE"` diff --git a/README.md b/README.md index e881ce81..7d3ab29a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ ZeroTier - Global Area Networking ====== +**NOTE: This project is a fork that implements packet camouflaging functionality. For usage instructions, see [README.camo.md](README.camo.md)** + *This document is written for a software developer audience. For information on using ZeroTier, see the: [Website](https://www.zerotier.com), [Documentation Site](https://docs.zerotier.com), and [Discussion Forum](https://discuss.zerotier.com).* ZeroTier is a smart programmable Ethernet switch for planet Earth. It allows all networked devices, VMs, containers, and applications to communicate as if they all reside in the same physical data center or cloud region. diff --git a/node/CamoPattern.cpp b/node/CamoPattern.cpp index d06d4e66..f86c4552 100644 --- a/node/CamoPattern.cpp +++ b/node/CamoPattern.cpp @@ -22,10 +22,10 @@ bool CamoPattern::isInitialized = false; CamoLevel CamoPattern::camoLevel; uint32_t CamoPattern::camoWord; CamoRelayRule CamoPattern::relayRule; -std::array, PATTERN_COUNT> CamoPattern::camoValues; -std::unordered_map, size_t> CamoPattern::camoIndices; +CamoPatternArray CamoPattern::camoValues; +CamoIndexMap CamoPattern::camoIndices; std::mutex CamoPattern::camoMutex; -std::unordered_map CamoPattern::knownHosts; +KnownHostsMap CamoPattern::knownHosts; // Implementation of getCamoLevel @@ -138,7 +138,7 @@ bool CamoPattern::isCamoRequired(const Address host, const RuntimeEnvironment * // Implementation of init -void CamoPattern::init(CamoLevel level, uint32_t word, std::unordered_map hosts, CamoRelayRule rule) +void CamoPattern::init(CamoLevel level, uint32_t word, KnownHostsMap hosts, CamoRelayRule rule) { std::lock_guard lock(camoMutex); if (!isInitialized) diff --git a/node/CamoPattern.hpp b/node/CamoPattern.hpp index ff361b55..c53e9fdc 100644 --- a/node/CamoPattern.hpp +++ b/node/CamoPattern.hpp @@ -14,8 +14,6 @@ #ifndef ZT_N_CAMOPATTERN_HPP #define ZT_N_CAMOPATTERN_HPP -#define CAMO_TRACE - #include #include #include @@ -26,33 +24,12 @@ #include "Buffer.hpp" #include "RuntimeEnvironment.hpp" -#define BYTES_IN_WORD 4 +#define BYTES_IN_WORD (sizeof(uint32_t) / sizeof(uint8_t)) #define PATTERN_COUNT 16 -#define PATTERN_INDEX_MASK 0xf #define NO_CAMO PATTERN_COUNT #define ZT_CAMO_DEFAULT_WORDSTR "DLGE" -namespace std { - template - struct hash> { - size_t operator()(const std::array& array) const { - size_t hash = 0; - for (const auto& element : array) { - hash = hash * 31 + std::hash{}(element); - } - return hash; - } - }; - - template<> - struct hash { - size_t operator()(const ZeroTier::Address& address) const { - return std::hash{}(address.toInt()); - } - }; -} - /** * Camo functions debug trace macro */ @@ -66,6 +43,43 @@ namespace std { #define CT(...) ((void)0) #endif +/** + * Type shorthands +*/ +namespace ZeroTier { + +enum class CamoLevel; +typedef std::array CamoPatternBytes; +typedef std::array CamoPatternArray; +typedef std::unordered_map CamoIndexMap; +typedef std::unordered_map KnownHostsMap; + +} + +/** + * Hash functions for the respective unordered_maps +*/ +namespace std { + template<> + struct hash { + size_t operator()(const ZeroTier::CamoPatternBytes& bytes) const { + uint32_t word = 0; + for (const auto& byte : bytes) { + word <<= 8; + word |= byte; + } + return std::hash{}(word); + } + }; + + template<> + struct hash { + size_t operator()(const ZeroTier::Address& address) const { + return std::hash{}(address.toInt()); + } + }; +} + namespace ZeroTier { /** @@ -102,7 +116,7 @@ class CamoPattern static size_t getCamoIndex(const Buffer &buffer) { size_t result = NO_CAMO; - std::array camo; + CamoPatternBytes camo; if (buffer.size() > BYTES_IN_WORD * 2) { for (size_t i = 0; i < BYTES_IN_WORD; i++) @@ -144,6 +158,8 @@ public: /** * Apply camouflage to buffer * + * This increases buffer length by adding ID word to the end + * * @param buffer Buffer to apply camouflage to */ template @@ -153,8 +169,8 @@ public: if (isInitialized && (camoIndex == NO_CAMO)) { // Only apply if not already applied CT("PACKET CONTENTS BEFORE APPLYING CAMO:"); buffer.dump(); - camoIndex = std::minstd_rand(std::time(nullptr))() & PATTERN_INDEX_MASK; - std::array camo = camoValues[camoIndex]; + camoIndex = std::minstd_rand(std::time(nullptr))() % PATTERN_COUNT; + CamoPatternBytes camo = camoValues[camoIndex]; // Increase buffer size first to avoid overflow size_t originalSize = buffer.size(); @@ -166,15 +182,16 @@ public: data[i + originalSize] = data[i + BYTES_IN_WORD]; } + // Copy the first word on the second word's place + for (size_t i = 0; i < BYTES_IN_WORD; i++) { + data[i + BYTES_IN_WORD] = data[i]; + } + // Apply XOR to the rest of the buffer - for (size_t i = BYTES_IN_WORD * 2; i < buffer.size(); i++) { + for (size_t i = BYTES_IN_WORD; i < buffer.size(); i++) { data[i] ^= camo[i % BYTES_IN_WORD]; } - // Apply XOR to create the camouflage pattern in the second word - for (size_t i = 0; i < BYTES_IN_WORD; i++) { - data[i + BYTES_IN_WORD] = data[i] ^ camo[i]; - } CT("PACKET CONTENTS AFTER APPLYING CAMO:"); buffer.dump(); } @@ -183,7 +200,7 @@ public: /** * Remove camouflage from buffer * - * This decreases buffer length by removing 'CAMO' from the end + * This decreases buffer length by removing stored ID word from the end * * @param buffer Buffer to remove camouflage from */ @@ -200,10 +217,10 @@ public: CT("PACKET CONTENTS BEFORE STRIPPING CAMO:"); buffer.dump(); uint8_t * const data = reinterpret_cast(buffer.unsafeData()); - std::array camo = camoValues[camoIndex]; + CamoPatternBytes camo = camoValues[camoIndex]; for (size_t i = BYTES_IN_WORD * 2; i < buffer.size(); i++) { - data[i] ^= camo[i % BYTES_IN_WORD]; + data[i] ^= camo[i % BYTES_IN_WORD]; } size_t storedWordIndex = buffer.size() - BYTES_IN_WORD; for (size_t i = 0; i < BYTES_IN_WORD; i++) @@ -218,7 +235,7 @@ public: return result; } - static void init(CamoLevel level, uint32_t word, std::unordered_map hosts, CamoRelayRule rule); + static void init(CamoLevel level, uint32_t word, KnownHostsMap hosts, CamoRelayRule rule); private: @@ -226,10 +243,10 @@ private: static CamoLevel camoLevel; static uint32_t camoWord; static CamoRelayRule relayRule; - static std::array, PATTERN_COUNT> camoValues; - static std::unordered_map, size_t> camoIndices; + static CamoPatternArray camoValues; + static CamoIndexMap camoIndices; static std::mutex camoMutex; - static std::unordered_map knownHosts; + static KnownHostsMap knownHosts; }; } // namespace ZeroTier diff --git a/node/IncomingPacket.cpp b/node/IncomingPacket.cpp index 071c7236..d1f71165 100644 --- a/node/IncomingPacket.cpp +++ b/node/IncomingPacket.cpp @@ -435,7 +435,11 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool Metrics::pkt_error_out++; Metrics::pkt_error_identity_collision_out++; outp.destination().toString(buf); - CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + if (CamoPattern::isCamoRequired(outp.destination(), RR)) + { + CamoPattern::applyCamo(outp); + } _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } else { RR->t->incomingPacketMessageAuthenticationFailure(tPtr,_path,pid,fromAddress,hops(),"invalid MAC"); @@ -595,7 +599,11 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool peer->recordOutgoingPacket(_path,outp.packetId(),outp.payloadLength(),outp.verb(),ZT_QOS_NO_FLOW,now); Metrics::pkt_ok_out++; outp.destination().toString(buf); - CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + if (CamoPattern::isCamoRequired(outp.destination(), RR)) + { + CamoPattern::applyCamo(outp); + } _path->send(RR,tPtr,outp.data(),outp.size(),now); peer->setRemoteVersion(protoVersion,vMajor,vMinor,vRevision); // important for this to go first so received() knows the version @@ -1000,7 +1008,11 @@ bool IncomingPacket::_doEXT_FRAME(const RuntimeEnvironment *RR,void *tPtr,const Metrics::pkt_ok_out++; char buf[64]; outp.destination().toString(buf); - CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + if (CamoPattern::isCamoRequired(outp.destination(), RR)) + { + CamoPattern::applyCamo(outp); + } _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } @@ -1032,7 +1044,11 @@ bool IncomingPacket::_doECHO(const RuntimeEnvironment *RR,void *tPtr,const Share Metrics::pkt_ok_out++; char buf[64]; outp.destination().toString(buf); - CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + if (CamoPattern::isCamoRequired(outp.destination(), RR)) + { + CamoPattern::applyCamo(outp); + } _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); peer->received(tPtr,_path,hops(),pid,payloadLength(),Packet::VERB_ECHO,0,Packet::VERB_NOP,false,0,ZT_QOS_NO_FLOW); @@ -1231,7 +1247,11 @@ bool IncomingPacket::_doNETWORK_CONFIG_REQUEST(const RuntimeEnvironment *RR,void Metrics::pkt_error_unsupported_op_out++; char buf[64]; outp.destination().toString(buf); - CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + if (CamoPattern::isCamoRequired(outp.destination(), RR)) + { + CamoPattern::applyCamo(outp); + } _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } @@ -1258,7 +1278,11 @@ bool IncomingPacket::_doNETWORK_CONFIG(const RuntimeEnvironment *RR,void *tPtr,c Metrics::pkt_ok_out++; char buf[64]; outp.destination().toString(buf); - CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + if (CamoPattern::isCamoRequired(outp.destination(), RR)) + { + CamoPattern::applyCamo(outp); + } _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } @@ -1304,7 +1328,11 @@ bool IncomingPacket::_doMULTICAST_GATHER(const RuntimeEnvironment *RR,void *tPtr Metrics::pkt_ok_out++; char buf[64]; outp.destination().toString(buf); - CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + if (CamoPattern::isCamoRequired(outp.destination(), RR)) + { + CamoPattern::applyCamo(outp); + } _path->send(RR,tPtr,outp.data(),outp.size(),now); } } @@ -1414,7 +1442,11 @@ bool IncomingPacket::_doMULTICAST_FRAME(const RuntimeEnvironment *RR,void *tPtr, Metrics::pkt_ok_out++; char buf[64]; outp.destination().toString(buf); - CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + if (CamoPattern::isCamoRequired(outp.destination(), RR)) + { + CamoPattern::applyCamo(outp); + } _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } } @@ -1559,7 +1591,11 @@ void IncomingPacket::_sendErrorNeedCredentials(const RuntimeEnvironment *RR,void Metrics::pkt_error_need_membership_cert_out++; char buf[64]; outp.destination().toString(buf); - CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + if (CamoPattern::isCamoRequired(outp.destination(), RR)) + { + CamoPattern::applyCamo(outp); + } _path->send(RR,tPtr,outp.data(),outp.size(),RR->node->now()); } diff --git a/node/Multicaster.cpp b/node/Multicaster.cpp index 8fe601d1..11fb3efd 100644 --- a/node/Multicaster.cpp +++ b/node/Multicaster.cpp @@ -203,7 +203,11 @@ void Multicaster::send( Metrics::pkt_multicast_frame_out++; char buf[64]; outp.destination().toString(buf); - CT("UNPROCESSED MULTICAST, packetId: %lx, address: %s", outp.packetId(), buf); + CT("PROCESSED MULTICAST, packetId: %lx, address: %s", outp.packetId(), buf); + if (CamoPattern::isCamoRequired(outp.destination(), RR)) + { + CamoPattern::applyCamo(outp); + } bestMulticastReplicatorPath->send(RR,tPtr,outp.data(),outp.size(),now); return; } diff --git a/node/Peer.cpp b/node/Peer.cpp index 17b07ab3..43f3b890 100644 --- a/node/Peer.cpp +++ b/node/Peer.cpp @@ -250,7 +250,12 @@ void Peer::received( Metrics::pkt_push_direct_paths_out++; char buf[64]; outp->destination().toString(buf); - CT("UNPROCESSED, packetId: %lx, address: %s", outp->packetId(), buf); + CT("PROCESSED, packetId: %lx, address: %s", outp->packetId(), buf); + + if (CamoPattern::isCamoRequired(outp->destination(), RR)) + { + CamoPattern::applyCamo(*outp); + } path->send(RR,tPtr,outp->data(),outp->size(),now); } delete outp; @@ -399,7 +404,11 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o Metrics::pkt_rendezvous_out++; char buf[64]; outp.destination().toString(buf); - CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + if (CamoPattern::isCamoRequired(outp.destination(), RR)) + { + CamoPattern::applyCamo(outp); + } _paths[mine].p->send(RR,tPtr,outp.data(),outp.size(),now); } else { Packet outp(other->_id.address(),RR->identity.address(),Packet::VERB_RENDEZVOUS); @@ -417,7 +426,11 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr &o Metrics::pkt_rendezvous_out++; char buf[64]; outp.destination().toString(buf); - CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + CT("PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + if (CamoPattern::isCamoRequired(outp.destination(), RR)) + { + CamoPattern::applyCamo(outp); + } other->_paths[theirs].p->send(RR,tPtr,outp.data(),outp.size(),now); } ++alt; @@ -468,7 +481,7 @@ void Peer::sendHELLO(void *tPtr,const int64_t localSocket,const InetAddress &atA RR->node->expectReplyTo(outp.packetId()); char buf[64]; outp.destination().toString(buf); - CT("UNPROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); + CT("SWITCH PROCESSED, packetId: %lx, address: %s", outp.packetId(), buf); RR->sw->send(tPtr,outp,false); // false == don't encrypt full payload, but add MAC } } diff --git a/service/OneService.cpp b/service/OneService.cpp index c017259f..efe8f119 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -1461,11 +1461,11 @@ public: uint32_t camoWord = 0; for (size_t i = 0; i < BYTES_IN_WORD; i++) { - camoWord |= camoWordStr[i]; camoWord <<= 8; + camoWord |= camoWordStr[i]; } CamoRelayRule relayRule = CamoRelayRule::LEAVE; - std::unordered_map knownHosts; + KnownHostsMap knownHosts; json &settings = lc["settings"]; if (settings.is_object()) { diff --git a/shell.nix b/shell.nix index f0c8131a..6a608869 100644 --- a/shell.nix +++ b/shell.nix @@ -9,6 +9,7 @@ pkgs.mkShell { cmake cmake-language-server clang-tools + pandoc ] ++ zerotieroneCustom.buildInputs ++ zerotieroneCustom.nativeBuildInputs; From 98ccedecacc7e039b7fe4915fed32765908b0568 Mon Sep 17 00:00:00 2001 From: eerieaerial <205630019+eerieaerial@users.noreply.github.com> Date: Wed, 14 May 2025 22:26:08 +0400 Subject: [PATCH 13/13] changed camouflaging scheme --- README.camo.md | 82 +++++++--------- node/CamoPattern.cpp | 118 ++++++++++------------- node/CamoPattern.hpp | 209 +++++++++++++++++++---------------------- node/Packet.hpp | 2 +- service/OneService.cpp | 143 ++++++++++------------------ 5 files changed, 235 insertions(+), 319 deletions(-) diff --git a/README.camo.md b/README.camo.md index f79a84f4..fca52a50 100644 --- a/README.camo.md +++ b/README.camo.md @@ -6,58 +6,44 @@ ## Принцип работы -### Узоры камуфлирования - -Основу механизма камуфлирования составляют 16 случайных 32-битных узоров, которые: - -- Генерируются при инициализации стандартизованным ГСЧ (вихрь Мерсенна MT19937, определённый в стандарте C++11) с фиксированным порождающим словом -- Одинаковы для всех узлов с одинаковым порождающим словом -- Используются для XOR-преобразования содержимого пакета -- Служат признаком распознавания камуфлированных пакетов - -Размер списка в 16 узоров выбран из соображений баланса между разнообразием узоров и вероятностью коллизии между признаком камуфлирования и случайно сгенерированным ID некамуфлированного пакета. Размер списка можно изменить путём задания нового значения макроса `PATTERN_COUNT` в файле `CamoPattern.hpp`. Рекомендуется использовать значения, равные степеням 2. - ### Алгоритм камуфлирования -1. 64-битный ID в заголовке пакета разделяется на два 32-битных сегмента -2. Младший сегмент перемещается в конец пакета -3. Старший сегмент дублируется на место младшего -4. Данные от дубликата до конца пакета обрабатываются XOR со случайно выбранным узором -5. Раскамуфлирование выполняется в обратном порядке после распознавания узора +1. 64-битный ID в заголовке пакета дублируется в конец пакета +2. Данные от дубликата до конца пакета обрабатываются XOR со случайным 32-битным числом ("камуфляжем") +3. Раскамуфлирование выполняется в обратном порядке после распознавания камуфляжа -### Распознавание камуфлированных пакетов +### Распознавание камуфляжа -Для распознавания того, камуфлирован пакет или нет, используется XOR между старшим и младшим сегментами ID. Если результат обнаружен в списке узоров, то это означает, что пакет закамуфлирован этим узором. +Для распознавания того, камуфлирован пакет или нет, используется равенство `a ^ b = x ^ y`, где `a` и `b` - старший и младший 32-битные сегменты ID, `x` и `y` - старший и младший 32-битные сегменты последних 64 бит пакета. Если равенство соблюдается, то это означает, что пакет камуфлирован, значение камуфляжа определяется формулой `c = a ^ x`. ### Правила обработки пакетов -Пакеты обрабатываются на основе сравнения уровня камуфлирования адресата и отправителя. Уровень адресата определяется либо автоматически, либо заданием в настройках. Уровень отправителя определяется настройкой и относится только непосредственно к тому узлу, на котором производится обработка пакета в данный момент. +Пакеты обрабатываются на основе класса адресата и заданной настройки включения камуфлирования для каждого из классов. Класс адресата присваивается ему либо автоматически, либо заданием в настройках. - _Входящие_: всегда автоматически раскамуфлируются для обеспечения работы внутренних механизмов -- _Исходящие_: камуфлируются, если уровень адресата равен уровню отправителя или меньше +- _Исходящие_: камуфлируются, если камуфлирование включено для класса адресата - _Пересылаемые_: обрабатываются согласно выбранному правилу пересылки -### Уровни камуфлирования +### Классы камуфлирования -Уровни камуфлирования имеют следующие названия от низшего к высшему: +Классы камуфлирования имеют следующие названия: -- `NONE` - `NODE` - `CONTROLLER` - `MOON` -- `PLANET` -- `INAPPLICABLE` +- `ALWAYS` +- `NEVER` -Особое значение имеют два уровня: +Особое значение имеют два класса: -- `NONE` - не назначается автоматически в качестве уровня адресата. Выбор этого уровня в качестве уровня отправителя выключает камуфлирование пакетов при автоматическом выборе уровня адресата. -- `INAPPLICABLE` - в качестве уровня адресата назначается автоматически глобальным корневым серверам. Для выбора в качестве уровня отправителя недоступен. +- `ALWAYS` - не присваивается адресату автоматически. Ручное присвоение этого класса адресату включает безусловное камуфлирование пакетов для него. +- `NEVER` - в качестве класса адресата присваивается автоматически глобальным корневым серверам (планетам). Ручное присвоение этого класса адресату безусловно выключает камуфлирование пакетов для него. -Прочие уровни назначаются автоматически согласно роли адресата. +Прочие классы назначаются автоматически согласно роли адресата. ### Список известных адресатов -При определении уровня камуфлирования для адресата проводится поиск в списке известных адресатов. Если адресат там обнаружен, то используется уровень, который присвоен в списке. Если нет - то производится автоматическое определение уровня адресата и результат заносится в список. Настройки позволяют задать изначальное содержимое списка для принудительного назначения адресатам требуемого уровня. +При определении класса адресата проводится поиск в списке известных адресатов. Если адресат там обнаружен, то используется класс, который присвоен в списке. Если нет - то производится автоматическое определение класса адресата и результат заносится в список. Настройки позволяют задать изначальное содержимое списка для принудительного назначения адресатам требуемого класса. ### Правила пересылки @@ -74,11 +60,16 @@ { "settings": { "camo": { - "level": "none", // Уровень отправителя - "word": "DLGE", // Порождающее слово для узоров + "autoApply": [ // Включает камуфлирование для перечисленных классов + "node", + "controller", + "moon" + ], "relayRule": "leave", // Правило пересылки - "knownHosts": { // Предустановленные уровни адресата для узлов - "none" : [] + "knownHosts": { // Предустановленные классы адресата для узлов + "never" : [ + "aaaaaaaaaa" + ] } } } @@ -87,10 +78,9 @@ ### Параметры -- `"level"`: регистронезависимая строка с названием уровня отправителя. По умолчанию: `"none"`. Любые значения, не соответствующие названию существующих уровней, интерпретируются как `"none"`. Значение `"inapplicable"` также интерпретируется как `"none"`, т.к. этот уровень недоступен для выбора. -- `"word"`: строка, содержащая порождающее слово для списка узоров. Если в строке меньше 4 символов, она дополняется до 4 символов последовательностью `"DLGE"`. Строка длиннее 4 символов обрезается. Если строка начинается с `"0x"`, она интерпретируется как 32-битное шестнадцатеричное число. По умолчанию: `"DLGE"`. +- `"autoApply"`: массив регистронезависимых строк с названиями классов адресата, для которых включается автоматическое камуфлирование. По умолчанию: `[]`. Допустимо задание строк `node`, `controller` и `moon`, прочие значения игнорируются. - `"relayRule"`: регистронезависимая строка, содержащая название правила пересылки. По умолчанию: `"leave"`. Любые значения, не соответствующие названию существующих правил, интерпретируются как `"leave"`. -- `"knownHosts"`: объект для предустановки уровней для конкретных узлов. Названия полей объекта соответствуют уровням камуфлирования. Названия полей, не соответствующие существующим уровням, интерпретируются как `"inapplicable"`. Значение каждого поля - массив строк с адресами. +- `"knownHosts"`: объект для предустановки классов адресата для конкретных узлов. Названия полей объекта регистронезависимы и соответствуют классам адресатов. Названия полей, не соответствующие существующим классам, интерпретируются как `"never"`. Значение каждого поля - массив строк с адресами. При включении одного и того же адреса в несколько разных классов, адресату будет назначен класс, идущий последним. ## Примеры конфигураций @@ -100,16 +90,16 @@ { "settings": { "camo": { - "level": "none", + "autoApply": [], "knownHosts": { - "none": ["aaaaaaaaaa"] + "always": ["aaaaaaaaaa"] } } } } ``` -Эта настройка выбирает уровень отправителя `NONE`, который автоматически не назначается адресатам. Это отключает камуфлирование для всех автоматически определяемых адресатов. Адресату `aaaaaaaaaa` принудительно назначается уровень `NONE`, и т.к. этот уровень равен выбранному, пакеты для него будут камуфлироваться. +Эта настройка отключает автоматическое камуфлирование. При этом, адресату `aaaaaaaaaa` принудительно назначается класс `ALWAYS`, и поэтому пакеты для него (и только для него) будут камуфлироваться. ### "Чёрный список" @@ -117,16 +107,16 @@ { "settings": { "camo": { - "level": "node", + "autoApply": [ "node" ], "knownHosts": { - "inapplicable": ["aaaaaaaaaa"] + "never": ["aaaaaaaaaa"] } } } } ``` -Здесь выбран уровень отправителя `NODE`, что включает камуфлирование для адресатов этого уровня и ниже. Адресату `aaaaaaaaaa` назначен уровень `INAPPLICABLE`, поэтому вне зависимости от выбранного уровня, пакеты для него камуфлироваться не будут. +Здесь включается автоматическое камуфлирование для обычных узлов. Узлу `aaaaaaaaaa` назначен класс `NEVER`, и вне зависимости от настроек автоматического камуфлирования, пакеты для него камуфлироваться не будут. ### Принудительное включение для специфических узлов @@ -134,7 +124,7 @@ { "settings": { "camo": { - "level": "node", + "level": [ "node" ], "knownHosts": { "node": ["aaaaaaaaaa"] } @@ -143,11 +133,11 @@ } ``` -В этом примере корневому серверу `aaaaaaaaaa`, поддерживающему работу с камуфлированными пакетами, принудительно присваивается уровень `NODE`, чтобы пакеты для него камуфлировались наряду с обычными узлами. +В этом примере корневому серверу `aaaaaaaaaa`, поддерживающему работу с камуфлированными пакетами, принудительно присваивается класс `NODE`, чтобы пакеты для него камуфлировались наряду с обычными узлами. ### Комментарий -По большому счёту, в `"knownHosts"` имеет смысл использовать только уровни `NONE` и `INAPPLICABLE`. Первый - принудительно включает камуфлирование для указанных адресатов, второй - выключает. +По большому счёту, в `"knownHosts"` имеет смысл использовать только классы `ALWAYS` и `NEVER`, т.к. в этом случае поведение не будет зависеть от настоек автоматического камуфлирования. ## Перевод сети на камуфлирование diff --git a/node/CamoPattern.cpp b/node/CamoPattern.cpp index f86c4552..4038ed56 100644 --- a/node/CamoPattern.cpp +++ b/node/CamoPattern.cpp @@ -9,39 +9,34 @@ * On the date above, in accordance with the Business Source License, use * of this software will be governed by version 2.0 of the Apache License. */ -/****/ #include "CamoPattern.hpp" #include +#include "RuntimeEnvironment.hpp" #include "Topology.hpp" namespace ZeroTier { // Initialize static members of CamoPattern bool CamoPattern::isInitialized = false; -CamoLevel CamoPattern::camoLevel; -uint32_t CamoPattern::camoWord; CamoRelayRule CamoPattern::relayRule; -CamoPatternArray CamoPattern::camoValues; -CamoIndexMap CamoPattern::camoIndices; std::mutex CamoPattern::camoMutex; KnownHostsMap CamoPattern::knownHosts; +CamoAutoApplyBits CamoPattern::camoAutoApply; +std::mt19937 CamoPattern::rng(std::random_device{}()); - -// Implementation of getCamoLevel -CamoLevel CamoPattern::getCamoLevel(const Address host, const RuntimeEnvironment * const RR) +CamoClass CamoPattern::getCamoClass(const Address host, const RuntimeEnvironment * const RR) { - CamoLevel result = CamoLevel::INAPPLICABLE; - // First check if we already know this host's camo level + CamoClass result = CamoClass::NEVER; if (isInitialized) { char buf[64]; host.toString(buf); - CT("GETTING CAMO LEVEL FOR HOST %s", buf); + CT("GETTING CAMO CLASS FOR HOST %s", buf); auto it = knownHosts.find(host); if (it != knownHosts.end()) { result = it->second; - CT("HOST IS KNOWN, LEVEL: %u", result); + CT("HOST IS KNOWN, CLASS: %u", result); } else { @@ -52,48 +47,40 @@ CamoLevel CamoPattern::getCamoLevel(const Address host, const RuntimeEnvironment it = knownHosts.find(host); if (it != knownHosts.end()) { result = it->second; - CT("HOST IS KNOWN AFTER LOCK WAITING"); + CT("HOST IS KNOWN AFTER LOCK WAITING, CLASS: %u", result); } else { CT("HOST IS NOT KNOWN"); - if (!RR->topology->isProhibitedEndpoint(host, InetAddress())) + switch(RR->topology->role(host)) { - switch(RR->topology->role(host)) - { - case ZT_PEER_ROLE_PLANET: - CT("HOST IS A PLANET"); - result = CamoLevel::PLANET; - break; - case ZT_PEER_ROLE_MOON: - CT("HOST IS A MOON"); - result = CamoLevel::MOON; - break; - default: - result = CamoLevel::NODE; - Mutex::Lock _l(RR->node->_networks_m); - Hashtable>::Iterator i(RR->node->_networks); - uint64_t * k = (uint64_t *)0; - SharedPtr *v = (SharedPtr *)0; - while(i.next(k, v)) + case ZT_PEER_ROLE_PLANET: + CT("HOST IS A PLANET"); + break; + case ZT_PEER_ROLE_MOON: + CT("HOST IS A MOON"); + result = CamoClass::MOON; + break; + default: + result = CamoClass::NODE; + Mutex::Lock _l(RR->node->_networks_m); + Hashtable>::Iterator i(RR->node->_networks); + uint64_t * k = (uint64_t *)0; + SharedPtr *v = (SharedPtr *)0; + while(i.next(k, v)) + { + if (host == ((*v)->controller())) { - if (host == ((*v)->controller())) - { - CT("HOST IS A CONTROLLER"); - result = CamoLevel::CONTROLLER; - break; - } + CT("HOST IS A CONTROLLER"); + result = CamoClass::CONTROLLER; + break; } - if (result == CamoLevel::NODE) - { - CT("HOST IS A SIMPLE NODE"); - } - break; - } - } - else - { - CT("HOST IS A ZT GLOBAL ROOT"); + } + if (result == CamoClass::NODE) + { + CT("HOST IS A SIMPLE NODE"); + } + break; } knownHosts[host] = result; } @@ -102,10 +89,18 @@ CamoLevel CamoPattern::getCamoLevel(const Address host, const RuntimeEnvironment return result; } -// Implementation of isCamoRequired +// Implementation of isCamoRequired - determines if camouflage should be applied based on host and rules bool CamoPattern::isCamoRequired(const Address host, const RuntimeEnvironment * const RR, const bool hadCamo, const bool isRelay) { bool result = false; + + auto isRequiredByClass = [](const Address host, const RuntimeEnvironment * const RR) -> bool { + CamoClass camoClass = getCamoClass(host, RR); + return camoClass < CamoClass::AUTO_APPLY_COUNT ? + camoAutoApply[camoClass] : + camoClass == CamoClass::ALWAYS; + }; + if (isInitialized && isRelay) { switch(relayRule) @@ -116,7 +111,7 @@ bool CamoPattern::isCamoRequired(const Address host, const RuntimeEnvironment * break; case CamoRelayRule::KNOWNHOSTS: CT("IS RELAY, APPLYING KNOWNHOSTS RULE"); - result = getCamoLevel(host, RR) <= camoLevel; + result = isRequiredByClass(host, RR); break; case CamoRelayRule::STRIP: CT("IS RELAY, APPLYING STRIP RULE"); @@ -130,39 +125,24 @@ bool CamoPattern::isCamoRequired(const Address host, const RuntimeEnvironment * } else if (isInitialized) { - result = getCamoLevel(host, RR) <= camoLevel; + result = isRequiredByClass(host, RR); CT("IS CAMO REQUIRED: %b", result); } return result; } - -// Implementation of init -void CamoPattern::init(CamoLevel level, uint32_t word, KnownHostsMap hosts, CamoRelayRule rule) +// Implementation of init - initializes the camouflage system with the specified settings +void CamoPattern::init(CamoAutoApplyBits autoApply, KnownHostsMap hosts, CamoRelayRule rule) { std::lock_guard lock(camoMutex); if (!isInitialized) { - camoLevel = level; - camoWord = word; + camoAutoApply = autoApply; knownHosts = hosts; relayRule = rule; - CT("CAMO LEVEL: %u, WORD: %08x, KNOWN HOSTS COUNT: %lu, RELAY RULE: %u", level, word, hosts.size(), rule); - std::mt19937 rng(camoWord); - for (size_t i = 0; i < PATTERN_COUNT; i++) - { - uint32_t random = rng(); - CT("CAMO INDEX: %lu, VALUE: %08x", i, random); - for (size_t j = 0; j < BYTES_IN_WORD; j++) - { - camoValues[i][j] = (random >> (j * 8)) & 0xff; - } - camoIndices[camoValues[i]] = i; - } + CT("KNOWN HOSTS COUNT: %lu, RELAY RULE: %u", hosts.size(), rule); isInitialized = true; } } - - } // namespace ZeroTier diff --git a/node/CamoPattern.hpp b/node/CamoPattern.hpp index c53e9fdc..638670e4 100644 --- a/node/CamoPattern.hpp +++ b/node/CamoPattern.hpp @@ -9,7 +9,6 @@ * On the date above, in accordance with the Business Source License, use * of this software will be governed by version 2.0 of the Apache License. */ -/****/ #ifndef ZT_N_CAMOPATTERN_HPP #define ZT_N_CAMOPATTERN_HPP @@ -19,20 +18,19 @@ #include #include #include +#include #include "Address.hpp" #include "Buffer.hpp" #include "RuntimeEnvironment.hpp" #define BYTES_IN_WORD (sizeof(uint32_t) / sizeof(uint8_t)) -#define PATTERN_COUNT 16 -#define NO_CAMO PATTERN_COUNT - -#define ZT_CAMO_DEFAULT_WORDSTR "DLGE" +#define ID_SIZE (BYTES_IN_WORD * 2) /** * Camo functions debug trace macro -*/ + * Enables debug output when CAMO_TRACE is defined + */ #ifdef CAMO_TRACE #define CT(...) do { \ printf("%s:%d %s: ", __FILE__, __LINE__, __PRETTY_FUNCTION__); \ @@ -43,35 +41,29 @@ #define CT(...) ((void)0) #endif -/** - * Type shorthands -*/ namespace ZeroTier { -enum class CamoLevel; +/** + * Camouflage class enum + */ +enum CamoClass { + NODE, + CONTROLLER, + MOON, + AUTO_APPLY_COUNT, + ALWAYS = AUTO_APPLY_COUNT, + NEVER +}; +typedef std::bitset CamoAutoApplyBits; typedef std::array CamoPatternBytes; -typedef std::array CamoPatternArray; -typedef std::unordered_map CamoIndexMap; -typedef std::unordered_map KnownHostsMap; +typedef std::unordered_map KnownHostsMap; } /** - * Hash functions for the respective unordered_maps + * Hash function for the KnownHostsMap */ namespace std { - template<> - struct hash { - size_t operator()(const ZeroTier::CamoPatternBytes& bytes) const { - uint32_t word = 0; - for (const auto& byte : bytes) { - word <<= 8; - word |= byte; - } - return std::hash{}(word); - } - }; - template<> struct hash { size_t operator()(const ZeroTier::Address& address) const { @@ -82,18 +74,6 @@ namespace std { namespace ZeroTier { -/** - * Camouflage level enum - */ -enum class CamoLevel { - NONE, - NODE, - CONTROLLER, - MOON, - PLANET, - INAPPLICABLE -}; - enum class CamoRelayRule { LEAVE, KNOWNHOSTS, @@ -107,146 +87,153 @@ enum class CamoRelayRule { class CamoPattern { /** - * Check if buffer has camouflage applied + * Check if the buffer has camo * * @param buffer Buffer to check - * @return True if buffer has camouflage + * @return True if the buffer has camo */ template - static size_t getCamoIndex(const Buffer &buffer) + static bool hasCamo(const Buffer &buffer) { - size_t result = NO_CAMO; - CamoPatternBytes camo; - if (buffer.size() > BYTES_IN_WORD * 2) + bool result = false; + if (buffer.size() > (ID_SIZE * 2)) { + size_t a = 0; + size_t b = BYTES_IN_WORD; + size_t x = buffer.size() - ID_SIZE; + size_t y = buffer.size() - BYTES_IN_WORD; + result = true; for (size_t i = 0; i < BYTES_IN_WORD; i++) { - camo[i] = buffer[i] ^ buffer[i + BYTES_IN_WORD]; - } - auto it = camoIndices.find(camo); - if (it != camoIndices.end()) - { - result = it->second; - CT("CAMO DETECTED, INDEX: %u", result); - } - else - { - CT("CAMO NOT DETECTED"); + if ((buffer[a + i] ^ buffer[b + i]) != (buffer[x + i] ^ buffer [y + i])) + { + result = false; + break; + } } } + CT("PACKET HAS CAMO: %b", result); return result; } /** - * Check the host camo level + * Check the host camo class * * @param host Destination address * @param RR RuntimeEnvironment pointer - * @return Camo Level for this host + * @return Camo class for this host */ - static CamoLevel getCamoLevel(const Address host, const RuntimeEnvironment * const RR); + static CamoClass getCamoClass(const Address host, const RuntimeEnvironment * const RR); public: /** + * Determine if camouflage is required for a specific host * * @param host Destination address * @param RR RuntimeEnvironment pointer - * @return True if host requires camo + * @param hadCamo Whether the packet previously had camouflage applied + * @param isRelay Whether this is a relay operation + * @return True if host requires camouflage */ static bool isCamoRequired(const Address host, const RuntimeEnvironment * const RR, const bool hadCamo = false, const bool isRelay = false); /** * Apply camouflage to buffer * - * This increases buffer length by adding ID word to the end + * This increases buffer length by adding ID to the end * * @param buffer Buffer to apply camouflage to */ template static void applyCamo(Buffer &buffer) { - size_t camoIndex = getCamoIndex(buffer); - if (isInitialized && (camoIndex == NO_CAMO)) { // Only apply if not already applied - CT("PACKET CONTENTS BEFORE APPLYING CAMO:"); - buffer.dump(); - camoIndex = std::minstd_rand(std::time(nullptr))() % PATTERN_COUNT; - CamoPatternBytes camo = camoValues[camoIndex]; + CT("APPLYING CAMO"); + if (isInitialized && !hasCamo(buffer)) + { + // load random number into an array + uint32_t camo = rng(); + CamoPatternBytes camoBytes; + for (size_t i = 0; i < BYTES_IN_WORD; i++) + { + camoBytes[i] = camo >> 24; + CT("CAMO BYTE %u: %02x", i, camoBytes[i]); + camo <<= 8; + } - // Increase buffer size first to avoid overflow + //camouflage all the data + uint8_t * const data = reinterpret_cast(buffer.unsafeData()); + for (size_t i = ID_SIZE; i < buffer.size(); i++) + { + data[i] ^= camoBytes[i % BYTES_IN_WORD]; + } + + // expand the buffer size_t originalSize = buffer.size(); - buffer.setSize(originalSize + BYTES_IN_WORD); - uint8_t * const data = reinterpret_cast(buffer.unsafeData()); - - // Copy the second word to the end - for (size_t i = 0; i < BYTES_IN_WORD; i++) { - data[i + originalSize] = data[i + BYTES_IN_WORD]; + buffer.setSize(originalSize + ID_SIZE); + //copy the id + for (size_t i = 0; i < ID_SIZE; i++) + { + data[i + originalSize] = data[i] ^ camoBytes[i % BYTES_IN_WORD]; } - // Copy the first word on the second word's place - for (size_t i = 0; i < BYTES_IN_WORD; i++) { - data[i + BYTES_IN_WORD] = data[i]; - } - - // Apply XOR to the rest of the buffer - for (size_t i = BYTES_IN_WORD; i < buffer.size(); i++) { - data[i] ^= camo[i % BYTES_IN_WORD]; - } - - CT("PACKET CONTENTS AFTER APPLYING CAMO:"); - buffer.dump(); + CT("DONE"); } } /** * Remove camouflage from buffer * - * This decreases buffer length by removing stored ID word from the end + * This decreases buffer length by removing stored ID from the end * * @param buffer Buffer to remove camouflage from + * @return True if buffer had camouflage and it was stripped */ template static bool stripCamo(Buffer &buffer) { bool result = false; - size_t camoIndex = NO_CAMO; - if (isInitialized) - { - camoIndex = getCamoIndex(buffer); - } - if (camoIndex != NO_CAMO) { - CT("PACKET CONTENTS BEFORE STRIPPING CAMO:"); - buffer.dump(); - uint8_t * const data = reinterpret_cast(buffer.unsafeData()); - CamoPatternBytes camo = camoValues[camoIndex]; - for (size_t i = BYTES_IN_WORD * 2; i < buffer.size(); i++) - { - data[i] ^= camo[i % BYTES_IN_WORD]; - } - size_t storedWordIndex = buffer.size() - BYTES_IN_WORD; + if (isInitialized && hasCamo(buffer)) { + //retrieve the camo bytes + uint8_t * a = &buffer[0]; + uint8_t * x = &buffer[buffer.size() - ID_SIZE]; + CamoPatternBytes camoBytes; for (size_t i = 0; i < BYTES_IN_WORD; i++) { - data[i + BYTES_IN_WORD] = data[i + storedWordIndex]; + camoBytes[i] = a[i] ^ x[i]; + CT("CAMO BYTE %u: %02x", i, camoBytes[i]); + } + + //remove the duplicated id + buffer.setSize(buffer.size() - ID_SIZE); + + //strip camo + uint8_t * const data = reinterpret_cast(buffer.unsafeData()); + for (size_t i = ID_SIZE; i < buffer.size(); i++) + { + data[i] ^= camoBytes[i % BYTES_IN_WORD]; } - buffer.setSize(buffer.size() - BYTES_IN_WORD); result = true; - CT("PACKET CONTENTS AFTER STRIPPING CAMO:"); - buffer.dump(); } + CT("CAMO STRIPPED: %d", result); return result; } - static void init(CamoLevel level, uint32_t word, KnownHostsMap hosts, CamoRelayRule rule); - + /** + * Initialize the camo system + * + * @param autoApply Bits controlling automatic application to different host classes + * @param hosts knownHosts preloading + * @param relayRule Packet relay rule + */ + static void init(CamoAutoApplyBits autoApply, KnownHostsMap hosts, CamoRelayRule rule); private: static bool isInitialized; - static CamoLevel camoLevel; - static uint32_t camoWord; + static CamoAutoApplyBits camoAutoApply; static CamoRelayRule relayRule; - static CamoPatternArray camoValues; - static CamoIndexMap camoIndices; static std::mutex camoMutex; static KnownHostsMap knownHosts; + static std::mt19937 rng; }; } // namespace ZeroTier diff --git a/node/Packet.hpp b/node/Packet.hpp index 0f5bd3ab..8ced7f54 100644 --- a/node/Packet.hpp +++ b/node/Packet.hpp @@ -232,7 +232,7 @@ /** * Packet buffer size (can be changed) */ -#define ZT_PROTO_ADDITIONAL_CAMO_LENGTH 4 +#define ZT_PROTO_ADDITIONAL_CAMO_LENGTH 8 #define ZT_PROTO_MAX_PACKET_LENGTH (ZT_MAX_PACKET_FRAGMENTS * ZT_DEFAULT_PHYSMTU) diff --git a/service/OneService.cpp b/service/OneService.cpp index efe8f119..def206c1 100644 --- a/service/OneService.cpp +++ b/service/OneService.cpp @@ -1456,14 +1456,7 @@ public: } // Camo settings defaults - CamoLevel camoLevel = CamoLevel::NONE; - std::string camoWordStr = ZT_CAMO_DEFAULT_WORDSTR; - uint32_t camoWord = 0; - for (size_t i = 0; i < BYTES_IN_WORD; i++) - { - camoWord <<= 8; - camoWord |= camoWordStr[i]; - } + CamoAutoApplyBits camoAutoApply; CamoRelayRule relayRule = CamoRelayRule::LEAVE; KnownHostsMap knownHosts; @@ -1506,58 +1499,55 @@ public: if (camo.is_object()) { CT("CAMO CONFIG SECTION FOUND"); - std::string camoLevelStr = OSUtils::jsonString(camo["level"], "none"); - std::transform(camoLevelStr.begin(), camoLevelStr.end(), camoLevelStr.begin(), [](unsigned char c) - { - return std::tolower(c); - }); - CT("CAMO LEVEL SETTING: %s", camoLevelStr.c_str()); - - if (camoLevelStr == "node") - { - camoLevel = CamoLevel::NODE; - } - else if (camoLevelStr == "controller") - { - camoLevel = CamoLevel::CONTROLLER; - } - else if (camoLevelStr == "moon") - { - camoLevel = CamoLevel::MOON; - } - else if (camoLevelStr == "planet") - { - camoLevel = CamoLevel::PLANET; - } - - if (camo.contains("word")) - { - std::string temp = OSUtils::jsonString(camo["word"], ZT_CAMO_DEFAULT_WORDSTR); - if (temp.substr(0, 2) == "0x") + auto stringToClass = [](std::string &str) -> CamoClass { + CamoClass result = CamoClass::NEVER; + std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c) { - try - { - camoWord = std::stoul(temp.substr(2), nullptr, 16); - } - catch (...) - { - } + return std::tolower(c); + }); + if (str == "always") + { + CT("CAMO CLASS: ALWAYS"); + result = CamoClass::ALWAYS; + } + else if (str == "node") + { + CT("CAMO CLASS: NODE"); + result = CamoClass::NODE; + } + else if (str == "controller") + { + CT("CAMO CLASS: CONTROLLER"); + result = CamoClass::CONTROLLER; + } + else if (str == "moon") + { + CT("CAMO CLASS: MOON"); + result = CamoClass::MOON; } else { - for (size_t i = 0; i < BYTES_IN_WORD; i++) + CT("CAMO CLASS: NEVER"); + } + return result; + }; + + json &autoApply = camo["autoApply"]; + if (autoApply.is_array()) + { + CT("AUTO APPLY SETTING FOUND"); + for (const auto &entry: autoApply) + { + std::string entryStr = OSUtils::jsonString(entry, ""); + + CT("AUTO APPLY SETTING: %s", entryStr.c_str()); + CamoClass camoClass = stringToClass(entryStr); + if (camoClass < CamoClass::AUTO_APPLY_COUNT) { - char c = ' '; - if (i < temp.size()) - { - c = temp[i]; - } - camoWord |= c; - camoWord <<= 8; + camoAutoApply[camoClass] = true; } } } - CT("CAMO WORD SETTING: %x", camoWord); std::string relayRuleStr = OSUtils::jsonString(camo["relayRule"], "leave"); std::transform(relayRuleStr.begin(), relayRuleStr.end(), relayRuleStr.begin(), [](unsigned char c) @@ -1582,11 +1572,15 @@ public: if (knownHostsSection.is_object()) { CT("KNOWN HOSTS SECTION FOUND"); - auto processLevelSection = [&knownHosts](const json §ion, CamoLevel level) + + for (auto it = knownHostsSection.begin(); it != knownHostsSection.end(); it++) { - if (section.is_array()) + std::string classKey = it.key(); + + CT("FOUND CAMO CLASS: %s", classKey.c_str()); + if (it.value().is_array()) { - for (const auto &addrStr: section) + for (const auto &addrStr: it.value()) { std::string addr = OSUtils::jsonString(addrStr, ""); if (!addr.empty()) @@ -1595,46 +1589,11 @@ public: if (host) { CT("VALID HOST FOUND: %s", addr.c_str()); - knownHosts[host] = level; + knownHosts[host] = stringToClass(classKey); } } } } - }; - - for (auto it = knownHostsSection.begin(); it != knownHostsSection.end(); it++) - { - std::string levelKey = it.key(); - std::transform(levelKey.begin(), levelKey.end(), levelKey.begin(), [](unsigned char c) - { - return std::tolower(c); - }); - - CT("FOUND CAMO LEVEL: %s", levelKey.c_str()); - if (levelKey == "none") - { - processLevelSection(it.value(), CamoLevel::NONE); - } - else if (levelKey == "node") - { - processLevelSection(it.value(), CamoLevel::NODE); - } - else if (levelKey == "controller") - { - processLevelSection(it.value(), CamoLevel::CONTROLLER); - } - else if (levelKey == "moon") - { - processLevelSection(it.value(), CamoLevel::MOON); - } - else if (levelKey == "planet") - { - processLevelSection(it.value(), CamoLevel::PLANET); - } - else - { - processLevelSection(it.value(), CamoLevel::INAPPLICABLE); - } } } } @@ -1643,7 +1602,7 @@ public: CT("CAMO CONFIG SECTION NOT FOUND"); } } - CamoPattern::init(camoLevel, camoWord, knownHosts, relayRule); + CamoPattern::init(camoAutoApply, knownHosts, relayRule); // Set trusted paths if there are any if (!ppc.empty()) {