Compare commits
19 commits
Author | SHA1 | Date | |
---|---|---|---|
|
98ccedecac | ||
|
235addc585 | ||
|
5fb3f5c228 | ||
|
083b833bf8 | ||
|
cdaf5e5468 | ||
|
826fcca1c9 | ||
|
185a3a2c76 | ||
|
3fcef51137 | ||
|
b7a6e106fd | ||
|
7dca7fac11 | ||
|
4ef2d4cc8e | ||
|
36b4659f77 | ||
|
0b5666bde2 | ||
|
e1c72e6d51 | ||
|
5799d9a15b | ||
|
d9d58c8bde | ||
|
d34481d830 | ||
|
4920b68d2c | ||
|
5ce3d1e7a1 |
33 changed files with 1571 additions and 309 deletions
12
.gitignore
vendored
12
.gitignore
vendored
|
@ -140,3 +140,15 @@ __pycache__
|
|||
snap/.snapcraft
|
||||
tcp-proxy/tcp-proxy
|
||||
rustybits/target
|
||||
|
||||
#direnv
|
||||
.envrc
|
||||
|
||||
#nix stuff
|
||||
result
|
||||
result-man
|
||||
|
||||
#zerotier devs seem to forgot those
|
||||
rustybits/zerotier-cli
|
||||
rustybits/zerotier-idtool
|
||||
.aider*
|
||||
|
|
|
@ -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
|
||||
|
|
148
README.camo.md
Normal file
148
README.camo.md
Normal file
|
@ -0,0 +1,148 @@
|
|||
# Камуфлирование пакетов ZeroTier
|
||||
|
||||
## Введение
|
||||
|
||||
Этот патч добавляет функцию сокрытия открытых полей и данных протокола ZeroTier, условно называемую "камуфлированием". Цель операции - не криптографическая защита, а создание видимости полностью случайного содержимого пакетов.
|
||||
|
||||
## Принцип работы
|
||||
|
||||
### Алгоритм камуфлирования
|
||||
|
||||
1. 64-битный ID в заголовке пакета дублируется в конец пакета
|
||||
2. Данные от дубликата до конца пакета обрабатываются XOR со случайным 32-битным числом ("камуфляжем")
|
||||
3. Раскамуфлирование выполняется в обратном порядке после распознавания камуфляжа
|
||||
|
||||
### Распознавание камуфляжа
|
||||
|
||||
Для распознавания того, камуфлирован пакет или нет, используется равенство `a ^ b = x ^ y`, где `a` и `b` - старший и младший 32-битные сегменты ID, `x` и `y` - старший и младший 32-битные сегменты последних 64 бит пакета. Если равенство соблюдается, то это означает, что пакет камуфлирован, значение камуфляжа определяется формулой `c = a ^ x`.
|
||||
|
||||
### Правила обработки пакетов
|
||||
|
||||
Пакеты обрабатываются на основе класса адресата и заданной настройки включения камуфлирования для каждого из классов. Класс адресата присваивается ему либо автоматически, либо заданием в настройках.
|
||||
|
||||
- _Входящие_: всегда автоматически раскамуфлируются для обеспечения работы внутренних механизмов
|
||||
- _Исходящие_: камуфлируются, если камуфлирование включено для класса адресата
|
||||
- _Пересылаемые_: обрабатываются согласно выбранному правилу пересылки
|
||||
|
||||
### Классы камуфлирования
|
||||
|
||||
Классы камуфлирования имеют следующие названия:
|
||||
|
||||
- `NODE`
|
||||
- `CONTROLLER`
|
||||
- `MOON`
|
||||
- `ALWAYS`
|
||||
- `NEVER`
|
||||
|
||||
Особое значение имеют два класса:
|
||||
|
||||
- `ALWAYS` - не присваивается адресату автоматически. Ручное присвоение этого класса адресату включает безусловное камуфлирование пакетов для него.
|
||||
- `NEVER` - в качестве класса адресата присваивается автоматически глобальным корневым серверам (планетам). Ручное присвоение этого класса адресату безусловно выключает камуфлирование пакетов для него.
|
||||
|
||||
Прочие классы назначаются автоматически согласно роли адресата.
|
||||
|
||||
### Список известных адресатов
|
||||
|
||||
При определении класса адресата проводится поиск в списке известных адресатов. Если адресат там обнаружен, то используется класс, который присвоен в списке. Если нет - то производится автоматическое определение класса адресата и результат заносится в список. Настройки позволяют задать изначальное содержимое списка для принудительного назначения адресатам требуемого класса.
|
||||
|
||||
### Правила пересылки
|
||||
|
||||
- `LEAVE` - сохраняет исходное состояние камуфлирования пересылаемого пакета
|
||||
- `KNOWNHOSTS` - применяет те же правила, что и для исходящих пакетов
|
||||
- `STRIP` - принудительно снимает камуфлирование со всех пересылаемых пакетов
|
||||
- `APPLY` - принудительно камуфлирует все пересылаемые пакеты
|
||||
|
||||
## Настройки
|
||||
|
||||
Настройки задаются в файле `local.conf` в объекте `"camo"` внутри `"settings"`:
|
||||
|
||||
```json
|
||||
{
|
||||
"settings": {
|
||||
"camo": {
|
||||
"autoApply": [ // Включает камуфлирование для перечисленных классов
|
||||
"node",
|
||||
"controller",
|
||||
"moon"
|
||||
],
|
||||
"relayRule": "leave", // Правило пересылки
|
||||
"knownHosts": { // Предустановленные классы адресата для узлов
|
||||
"never" : [
|
||||
"aaaaaaaaaa"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Параметры
|
||||
|
||||
- `"autoApply"`: массив регистронезависимых строк с названиями классов адресата, для которых включается автоматическое камуфлирование. По умолчанию: `[]`. Допустимо задание строк `node`, `controller` и `moon`, прочие значения игнорируются.
|
||||
- `"relayRule"`: регистронезависимая строка, содержащая название правила пересылки. По умолчанию: `"leave"`. Любые значения, не соответствующие названию существующих правил, интерпретируются как `"leave"`.
|
||||
- `"knownHosts"`: объект для предустановки классов адресата для конкретных узлов. Названия полей объекта регистронезависимы и соответствуют классам адресатов. Названия полей, не соответствующие существующим классам, интерпретируются как `"never"`. Значение каждого поля - массив строк с адресами. При включении одного и того же адреса в несколько разных классов, адресату будет назначен класс, идущий последним.
|
||||
|
||||
## Примеры конфигураций
|
||||
|
||||
### "Белый список"
|
||||
|
||||
```json
|
||||
{
|
||||
"settings": {
|
||||
"camo": {
|
||||
"autoApply": [],
|
||||
"knownHosts": {
|
||||
"always": ["aaaaaaaaaa"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Эта настройка отключает автоматическое камуфлирование. При этом, адресату `aaaaaaaaaa` принудительно назначается класс `ALWAYS`, и поэтому пакеты для него (и только для него) будут камуфлироваться.
|
||||
|
||||
### "Чёрный список"
|
||||
|
||||
```json
|
||||
{
|
||||
"settings": {
|
||||
"camo": {
|
||||
"autoApply": [ "node" ],
|
||||
"knownHosts": {
|
||||
"never": ["aaaaaaaaaa"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Здесь включается автоматическое камуфлирование для обычных узлов. Узлу `aaaaaaaaaa` назначен класс `NEVER`, и вне зависимости от настроек автоматического камуфлирования, пакеты для него камуфлироваться не будут.
|
||||
|
||||
### Принудительное включение для специфических узлов
|
||||
|
||||
```json
|
||||
{
|
||||
"settings": {
|
||||
"camo": {
|
||||
"level": [ "node" ],
|
||||
"knownHosts": {
|
||||
"node": ["aaaaaaaaaa"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
В этом примере корневому серверу `aaaaaaaaaa`, поддерживающему работу с камуфлированными пакетами, принудительно присваивается класс `NODE`, чтобы пакеты для него камуфлировались наряду с обычными узлами.
|
||||
|
||||
### Комментарий
|
||||
|
||||
По большому счёту, в `"knownHosts"` имеет смысл использовать только классы `ALWAYS` и `NEVER`, т.к. в этом случае поведение не будет зависеть от настоек автоматического камуфлирования.
|
||||
|
||||
## Перевод сети на камуфлирование
|
||||
|
||||
Для перевода всей сети на камуфлирование сначала необходимо установить службу ZeroTier с данным патчем без дополнительных настроек. При этом, служба будет работать так же, как штатная. После этого, на каждом узле производится включение камуфлирования с помощью настроек. Такой процесс позволяет перевести сеть на камуфлирование пакетов без потери работоспособности всей сети.
|
||||
|
||||
## Особенности сборки
|
||||
|
||||
Задание макроса `CAMO_TRACE` включает выдачу отладочных сообщений на стандартный вывод службы. Для этого нужно при сборке передать команде make параметр `DEFS="-DCAMO_TRACE"`
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
6
debian/changelog
vendored
6
debian/changelog
vendored
|
@ -1,3 +1,9 @@
|
|||
zerotier-one (1.14.2) unstable; urgency=medium
|
||||
|
||||
* See RELEASE-NOTES.md for release notes.
|
||||
|
||||
-- Adam Ierymenko <adam.ierymenko@zerotier.com> Wed, 23 Oct 2024 01:00:00 -0700
|
||||
|
||||
zerotier-one (1.14.1) unstable; urgency=medium
|
||||
|
||||
* See RELEASE-NOTES.md for release notes.
|
||||
|
|
|
@ -701,7 +701,7 @@
|
|||
<key>USE_HFS+_COMPRESSION</key>
|
||||
<false/>
|
||||
<key>VERSION</key>
|
||||
<string>1.14.1</string>
|
||||
<string>1.14.2</string>
|
||||
</dict>
|
||||
<key>TYPE</key>
|
||||
<integer>0</integer>
|
||||
|
|
|
@ -24,10 +24,10 @@
|
|||
<ROW Property="AiFeatIcoZeroTierOne" Value="ZeroTierIcon.exe" Type="8"/>
|
||||
<ROW Property="MSIFASTINSTALL" MultiBuildValue="DefaultBuild:2"/>
|
||||
<ROW Property="Manufacturer" Value="ZeroTier, Inc."/>
|
||||
<ROW Property="ProductCode" Value="1033:{EC58088A-4E0F-4BD5-B0B2-FD81C803EEC4} " Type="16"/>
|
||||
<ROW Property="ProductCode" Value="1033:{0143A36C-46C6-458D-AB9B-C8843E089323} " Type="16"/>
|
||||
<ROW Property="ProductLanguage" Value="1033"/>
|
||||
<ROW Property="ProductName" Value="ZeroTier One"/>
|
||||
<ROW Property="ProductVersion" Value="1.14.0" Options="32"/>
|
||||
<ROW Property="ProductVersion" Value="1.14.2" Options="32"/>
|
||||
<ROW Property="REBOOT" MultiBuildValue="DefaultBuild:ReallySuppress"/>
|
||||
<ROW Property="SecureCustomProperties" Value="OLDPRODUCTS;AI_NEWERPRODUCTFOUND;AI_SETUPEXEPATH;SETUPEXEDIR"/>
|
||||
<ROW Property="UpgradeCode" Value="{B0E2A5F3-88B6-4E77-B922-CB4739B4C4C8}"/>
|
||||
|
@ -62,7 +62,7 @@
|
|||
<ROW Directory="regid.201001.com.zerotier_Dir" Directory_Parent="CommonAppDataFolder" DefaultDir="REGID2~1.ZER|regid.2010-01.com.zerotier" DirectoryOptions="12"/>
|
||||
</COMPONENT>
|
||||
<COMPONENT cid="caphyon.advinst.msicomp.MsiCompsComponent">
|
||||
<ROW Component="AI_CustomARPName" ComponentId="{8BC01817-02AC-4C44-A84C-0727BC5B6E22}" Directory_="APPDIR" Attributes="4" KeyPath="DisplayName" Options="1"/>
|
||||
<ROW Component="AI_CustomARPName" ComponentId="{DFE7A60C-C2B9-41F6-9171-8955BA30E556}" Directory_="APPDIR" Attributes="4" KeyPath="DisplayName" Options="1"/>
|
||||
<ROW Component="AI_DisableModify" ComponentId="{46FFA8C5-A0CB-4E05-9AD3-911D543DE8CA}" Directory_="APPDIR" Attributes="4" KeyPath="NoModify" Options="1"/>
|
||||
<ROW Component="AI_ExePath" ComponentId="{8E02B36C-7A19-429B-A93E-77A9261AC918}" Directory_="APPDIR" Attributes="4" KeyPath="AI_ExePath"/>
|
||||
<ROW Component="APPDIR" ComponentId="{4DD7907D-D7FE-4CD6-B1A0-B5C1625F5133}" Directory_="APPDIR" Attributes="0"/>
|
||||
|
@ -498,7 +498,7 @@
|
|||
<ROW XmlAttribute="xsischemaLocation" XmlElement="swidsoftware_identification_tag" Name="xsi:schemaLocation" Flags="14" Order="3" Value="http://standards.iso.org/iso/19770/-2/2008/schema.xsd software_identification_tag.xsd"/>
|
||||
</COMPONENT>
|
||||
<COMPONENT cid="caphyon.advinst.msicomp.XmlElementComponent">
|
||||
<ROW XmlElement="swidbuild" ParentElement="swidnumeric" Name="swid:build" Condition="1" Order="2" Flags="14" Text="0" UpdateIndexInParent="0"/>
|
||||
<ROW XmlElement="swidbuild" ParentElement="swidnumeric" Name="swid:build" Condition="1" Order="2" Flags="14" Text="2" UpdateIndexInParent="0"/>
|
||||
<ROW XmlElement="swidentitlement_required_indicator" ParentElement="swidsoftware_identification_tag" Name="swid:entitlement_required_indicator" Condition="1" Order="0" Flags="14" Text="false" UpdateIndexInParent="0"/>
|
||||
<ROW XmlElement="swidmajor" ParentElement="swidnumeric" Name="swid:major" Condition="1" Order="0" Flags="14" Text="1" UpdateIndexInParent="0"/>
|
||||
<ROW XmlElement="swidminor" ParentElement="swidnumeric" Name="swid:minor" Condition="1" Order="1" Flags="14" Text="14" UpdateIndexInParent="0"/>
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
namespace prometheus {
|
||||
|
||||
// структура, в которую копируются значения метрик перед их сериализацией
|
||||
|
||||
struct ClientMetric {
|
||||
|
||||
// Label
|
||||
|
|
64
flake.lock
generated
Normal file
64
flake.lock
generated
Normal file
|
@ -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
|
||||
}
|
35
flake.nix
Normal file
35
flake.nix
Normal file
|
@ -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;
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
|
@ -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/
|
||||
|
|
|
@ -445,6 +445,11 @@ public:
|
|||
*/
|
||||
inline unsigned int capacity() const { return C; }
|
||||
|
||||
/**
|
||||
* Dump buffer contents to stdout in hex format
|
||||
*/
|
||||
void dump() const;
|
||||
|
||||
template<unsigned int C2>
|
||||
inline bool operator==(const Buffer<C2> &b) const
|
||||
{
|
||||
|
|
148
node/CamoPattern.cpp
Normal file
148
node/CamoPattern.cpp
Normal file
|
@ -0,0 +1,148 @@
|
|||
/*
|
||||
* 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 <ctime>
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
#include "Topology.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
// Initialize static members of CamoPattern
|
||||
bool CamoPattern::isInitialized = false;
|
||||
CamoRelayRule CamoPattern::relayRule;
|
||||
std::mutex CamoPattern::camoMutex;
|
||||
KnownHostsMap CamoPattern::knownHosts;
|
||||
CamoAutoApplyBits CamoPattern::camoAutoApply;
|
||||
std::mt19937 CamoPattern::rng(std::random_device{}());
|
||||
|
||||
CamoClass CamoPattern::getCamoClass(const Address host, const RuntimeEnvironment * const RR)
|
||||
{
|
||||
CamoClass result = CamoClass::NEVER;
|
||||
if (isInitialized)
|
||||
{
|
||||
char buf[64];
|
||||
host.toString(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, CLASS: %u", result);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Host not found in known hosts, run mutex-protected section
|
||||
std::lock_guard<std::mutex> 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, CLASS: %u", result);
|
||||
}
|
||||
else
|
||||
{
|
||||
CT("HOST IS NOT KNOWN");
|
||||
switch(RR->topology->role(host))
|
||||
{
|
||||
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<uint64_t, SharedPtr<Network>>::Iterator i(RR->node->_networks);
|
||||
uint64_t * k = (uint64_t *)0;
|
||||
SharedPtr<Network> *v = (SharedPtr<Network> *)0;
|
||||
while(i.next(k, v))
|
||||
{
|
||||
if (host == ((*v)->controller()))
|
||||
{
|
||||
CT("HOST IS A CONTROLLER");
|
||||
result = CamoClass::CONTROLLER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (result == CamoClass::NODE)
|
||||
{
|
||||
CT("HOST IS A SIMPLE NODE");
|
||||
}
|
||||
break;
|
||||
}
|
||||
knownHosts[host] = result;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
case CamoRelayRule::LEAVE:
|
||||
CT("IS RELAY, APPLYING LEAVE RULE");
|
||||
result = hadCamo;
|
||||
break;
|
||||
case CamoRelayRule::KNOWNHOSTS:
|
||||
CT("IS RELAY, APPLYING KNOWNHOSTS RULE");
|
||||
result = isRequiredByClass(host, RR);
|
||||
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 = isRequiredByClass(host, RR);
|
||||
CT("IS CAMO REQUIRED: %b", result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Implementation of init - initializes the camouflage system with the specified settings
|
||||
void CamoPattern::init(CamoAutoApplyBits autoApply, KnownHostsMap hosts, CamoRelayRule rule)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(camoMutex);
|
||||
if (!isInitialized)
|
||||
{
|
||||
camoAutoApply = autoApply;
|
||||
knownHosts = hosts;
|
||||
relayRule = rule;
|
||||
CT("KNOWN HOSTS COUNT: %lu, RELAY RULE: %u", hosts.size(), rule);
|
||||
isInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZeroTier
|
266
node/CamoPattern.hpp
Normal file
266
node/CamoPattern.hpp
Normal file
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* 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
|
||||
|
||||
#include <stdint.h>
|
||||
#include <array>
|
||||
#include <unordered_map>
|
||||
#include <mutex>
|
||||
#include <random>
|
||||
#include <bitset>
|
||||
|
||||
#include "Address.hpp"
|
||||
#include "Buffer.hpp"
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
|
||||
#define BYTES_IN_WORD (sizeof(uint32_t) / sizeof(uint8_t))
|
||||
#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__); \
|
||||
printf(__VA_ARGS__); \
|
||||
printf("\n"); \
|
||||
} while(0)
|
||||
#else
|
||||
#define CT(...) ((void)0)
|
||||
#endif
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
/**
|
||||
* Camouflage class enum
|
||||
*/
|
||||
enum CamoClass {
|
||||
NODE,
|
||||
CONTROLLER,
|
||||
MOON,
|
||||
AUTO_APPLY_COUNT,
|
||||
ALWAYS = AUTO_APPLY_COUNT,
|
||||
NEVER
|
||||
};
|
||||
typedef std::bitset<CamoClass::AUTO_APPLY_COUNT> CamoAutoApplyBits;
|
||||
typedef std::array<uint8_t, BYTES_IN_WORD> CamoPatternBytes;
|
||||
typedef std::unordered_map<Address, CamoClass> KnownHostsMap;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Hash function for the KnownHostsMap
|
||||
*/
|
||||
namespace std {
|
||||
template<>
|
||||
struct hash<ZeroTier::Address> {
|
||||
size_t operator()(const ZeroTier::Address& address) const {
|
||||
return std::hash<uint64_t>{}(address.toInt());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
enum class CamoRelayRule {
|
||||
LEAVE,
|
||||
KNOWNHOSTS,
|
||||
STRIP,
|
||||
APPLY
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper class for packet camouflage operations
|
||||
*/
|
||||
class CamoPattern
|
||||
{
|
||||
/**
|
||||
* Check if the buffer has camo
|
||||
*
|
||||
* @param buffer Buffer to check
|
||||
* @return True if the buffer has camo
|
||||
*/
|
||||
template<unsigned int C>
|
||||
static bool hasCamo(const Buffer<C> &buffer)
|
||||
{
|
||||
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++)
|
||||
{
|
||||
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 class
|
||||
*
|
||||
* @param host Destination address
|
||||
* @param RR RuntimeEnvironment pointer
|
||||
* @return Camo class for this host
|
||||
*/
|
||||
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
|
||||
* @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 to the end
|
||||
*
|
||||
* @param buffer Buffer to apply camouflage to
|
||||
*/
|
||||
template<unsigned int C>
|
||||
static void applyCamo(Buffer<C> &buffer)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
//camouflage all the data
|
||||
uint8_t * const data = reinterpret_cast<uint8_t * const>(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 + ID_SIZE);
|
||||
//copy the id
|
||||
for (size_t i = 0; i < ID_SIZE; i++)
|
||||
{
|
||||
data[i + originalSize] = data[i] ^ camoBytes[i % BYTES_IN_WORD];
|
||||
}
|
||||
|
||||
CT("DONE");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove camouflage from buffer
|
||||
*
|
||||
* 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<unsigned int C>
|
||||
static bool stripCamo(Buffer<C> &buffer)
|
||||
{
|
||||
bool result = false;
|
||||
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++)
|
||||
{
|
||||
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<uint8_t * const>(buffer.unsafeData());
|
||||
for (size_t i = ID_SIZE; i < buffer.size(); i++)
|
||||
{
|
||||
data[i] ^= camoBytes[i % BYTES_IN_WORD];
|
||||
}
|
||||
result = true;
|
||||
}
|
||||
CT("CAMO STRIPPED: %d", result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 CamoAutoApplyBits camoAutoApply;
|
||||
static CamoRelayRule relayRule;
|
||||
static std::mutex camoMutex;
|
||||
static KnownHostsMap knownHosts;
|
||||
static std::mt19937 rng;
|
||||
};
|
||||
|
||||
} // namespace ZeroTier
|
||||
|
||||
// Implementation of Buffer::dump() method
|
||||
template<unsigned int C>
|
||||
void ZeroTier::Buffer<C>::dump() const
|
||||
{
|
||||
#ifdef CAMO_TRACE
|
||||
const unsigned char *bytes = reinterpret_cast<const unsigned char *>(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
|
|
@ -19,6 +19,7 @@
|
|||
#include "../include/ZeroTierOne.h"
|
||||
|
||||
#include "Constants.hpp"
|
||||
#include "Identity.hpp"
|
||||
#include "RuntimeEnvironment.hpp"
|
||||
#include "IncomingPacket.hpp"
|
||||
#include "Topology.hpp"
|
||||
|
@ -39,6 +40,7 @@
|
|||
#include "Bond.hpp"
|
||||
#include "Metrics.hpp"
|
||||
#include "PacketMultiplexer.hpp"
|
||||
#include "CamoPattern.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
|
@ -61,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);
|
||||
}
|
||||
|
@ -88,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;
|
||||
}
|
||||
|
@ -157,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;
|
||||
}
|
||||
|
@ -374,7 +399,9 @@ bool IncomingPacket::_doHELLO(const RuntimeEnvironment *RR,void *tPtr,const bool
|
|||
const int64_t timestamp = at<int64_t>(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;
|
||||
|
@ -407,6 +434,12 @@ 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++;
|
||||
outp.destination().toString(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");
|
||||
|
@ -565,6 +598,12 @@ 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++;
|
||||
outp.destination().toString(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
|
||||
|
@ -635,10 +674,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<Peer>(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<uint64_t>(ZT_PROTO_VERB_OK_IDX_PAYLOAD);
|
||||
const SharedPtr<Network> network(RR->node->network(networkId));
|
||||
if (network) {
|
||||
|
@ -647,6 +690,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<uint64_t>(ZT_PROTO_VERB_MULTICAST_GATHER__OK__IDX_NETWORK_ID);
|
||||
const SharedPtr<Network> network(RR->node->network(networkId));
|
||||
if (network) {
|
||||
|
@ -657,6 +701,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<uint64_t>(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<uint32_t>(ZT_PROTO_VERB_MULTICAST_FRAME__OK__IDX_ADI));
|
||||
|
@ -711,6 +756,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) {
|
||||
|
@ -725,6 +773,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());
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -955,6 +1006,13 @@ 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++;
|
||||
char buf[64];
|
||||
outp.destination().toString(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());
|
||||
}
|
||||
|
||||
|
@ -984,6 +1042,13 @@ 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++;
|
||||
char buf[64];
|
||||
outp.destination().toString(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);
|
||||
|
@ -1180,6 +1245,13 @@ 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++;
|
||||
char buf[64];
|
||||
outp.destination().toString(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());
|
||||
}
|
||||
|
||||
|
@ -1204,6 +1276,13 @@ 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++;
|
||||
char buf[64];
|
||||
outp.destination().toString(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());
|
||||
}
|
||||
}
|
||||
|
@ -1247,6 +1326,13 @@ 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++;
|
||||
char buf[64];
|
||||
outp.destination().toString(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);
|
||||
}
|
||||
}
|
||||
|
@ -1320,6 +1406,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()))) {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -1351,6 +1440,13 @@ 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++;
|
||||
char buf[64];
|
||||
outp.destination().toString(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());
|
||||
}
|
||||
}
|
||||
|
@ -1493,6 +1589,13 @@ 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++;
|
||||
char buf[64];
|
||||
outp.destination().toString(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());
|
||||
}
|
||||
|
||||
|
|
|
@ -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> &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> &path, int64_t now)
|
||||
{
|
||||
copyFrom(packet.data(), packet.size());
|
||||
_receiveTime = now;
|
||||
_path = path;
|
||||
_authenticated = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to decode this packet
|
||||
*
|
||||
|
|
|
@ -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<ZT_PROTO_MAX_PACKET_LENGTH> &appendTo,unsigned int limit) const
|
||||
unsigned int Multicaster::gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer<ZT_PROTO_MAX_PACKET_LENGTH + ZT_PROTO_ADDITIONAL_CAMO_LENGTH> &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,13 @@ void Multicaster::send(
|
|||
}
|
||||
outp.armor(bestMulticastReplicator->key(),true,bestMulticastReplicator->aesKeysIfSupported());
|
||||
Metrics::pkt_multicast_frame_out++;
|
||||
char buf[64];
|
||||
outp.destination().toString(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;
|
||||
}
|
||||
|
|
|
@ -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<ZT_PROTO_MAX_PACKET_LENGTH> &appendTo,unsigned int limit) const;
|
||||
unsigned int gather(const Address &queryingPeer,uint64_t nwid,const MulticastGroup &mg,Buffer<ZT_PROTO_MAX_PACKET_LENGTH + ZT_PROTO_ADDITIONAL_CAMO_LENGTH> &appendTo,unsigned int limit) const;
|
||||
|
||||
/**
|
||||
* Get subscribers to a multicast group
|
||||
|
|
|
@ -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<ZT_PROTO_MAX_PACKET_LENGTH> &chunk,unsigned int ptr)
|
||||
uint64_t Network::handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer<ZT_PROTO_MAX_PACKET_LENGTH + ZT_PROTO_ADDITIONAL_CAMO_LENGTH> &chunk,unsigned int ptr)
|
||||
{
|
||||
if (_destroyed) {
|
||||
return 0;
|
||||
|
|
|
@ -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<ZT_PROTO_MAX_PACKET_LENGTH> &chunk,unsigned int ptr);
|
||||
uint64_t handleConfigChunk(void *tPtr,const uint64_t packetId,const Address &source,const Buffer<ZT_PROTO_MAX_PACKET_LENGTH + ZT_PROTO_ADDITIONAL_CAMO_LENGTH> &chunk,unsigned int ptr);
|
||||
|
||||
/**
|
||||
* Set network configuration
|
||||
|
|
|
@ -232,6 +232,8 @@
|
|||
/**
|
||||
* Packet buffer size (can be changed)
|
||||
*/
|
||||
#define ZT_PROTO_ADDITIONAL_CAMO_LENGTH 8
|
||||
|
||||
#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<ZT_PROTO_MAX_PACKET_LENGTH>
|
||||
class Packet : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH + ZT_PROTO_ADDITIONAL_CAMO_LENGTH>
|
||||
{
|
||||
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<ZT_PROTO_MAX_PACKET_LENGTH>
|
||||
class Fragment : public Buffer<ZT_PROTO_MAX_PACKET_LENGTH + ZT_PROTO_ADDITIONAL_CAMO_LENGTH>
|
||||
{
|
||||
public:
|
||||
Fragment() :
|
||||
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>()
|
||||
Buffer<ZT_PROTO_MAX_PACKET_LENGTH + ZT_PROTO_ADDITIONAL_CAMO_LENGTH>()
|
||||
{
|
||||
}
|
||||
|
||||
template<unsigned int C2>
|
||||
Fragment(const Buffer<C2> &b) :
|
||||
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
|
||||
Buffer<ZT_PROTO_MAX_PACKET_LENGTH + ZT_PROTO_ADDITIONAL_CAMO_LENGTH>(b)
|
||||
{
|
||||
}
|
||||
|
||||
Fragment(const void *data,unsigned int len) :
|
||||
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(data,len)
|
||||
Buffer<ZT_PROTO_MAX_PACKET_LENGTH + ZT_PROTO_ADDITIONAL_CAMO_LENGTH>(data,len)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1091,12 +1093,12 @@ public:
|
|||
|
||||
template<unsigned int C2>
|
||||
Packet(const Buffer<C2> &b) :
|
||||
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(b)
|
||||
Buffer<ZT_PROTO_MAX_PACKET_LENGTH + ZT_PROTO_ADDITIONAL_CAMO_LENGTH>(b)
|
||||
{
|
||||
}
|
||||
|
||||
Packet(const void *data,unsigned int len) :
|
||||
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(data,len)
|
||||
Buffer<ZT_PROTO_MAX_PACKET_LENGTH + ZT_PROTO_ADDITIONAL_CAMO_LENGTH>(data,len)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -1108,7 +1110,7 @@ public:
|
|||
* the header. Payload should be appended; initial size is header size.
|
||||
*/
|
||||
Packet() :
|
||||
Buffer<ZT_PROTO_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
|
||||
Buffer<ZT_PROTO_MAX_PACKET_LENGTH + ZT_PROTO_ADDITIONAL_CAMO_LENGTH>(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<ZT_PROTO_MAX_PACKET_LENGTH>(prototype)
|
||||
Buffer<ZT_PROTO_MAX_PACKET_LENGTH + ZT_PROTO_ADDITIONAL_CAMO_LENGTH>(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_MAX_PACKET_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
|
||||
Buffer<ZT_PROTO_MAX_PACKET_LENGTH + ZT_PROTO_ADDITIONAL_CAMO_LENGTH>(ZT_PROTO_MIN_PACKET_LENGTH)
|
||||
{
|
||||
Utils::getSecureRandom(field(ZT_PACKET_IDX_IV,8),8);
|
||||
setDestination(dest);
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include "RingBuffer.hpp"
|
||||
#include "Utils.hpp"
|
||||
#include "Metrics.hpp"
|
||||
#include "Buffer.hpp"
|
||||
|
||||
namespace ZeroTier {
|
||||
|
||||
|
@ -247,6 +248,14 @@ void Peer::received(
|
|||
outp->compress();
|
||||
outp->armor(_key,true,aesKeysIfSupported());
|
||||
Metrics::pkt_push_direct_paths_out++;
|
||||
char buf[64];
|
||||
outp->destination().toString(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;
|
||||
|
@ -393,6 +402,13 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
|
|||
}
|
||||
outp.armor(_key,true,aesKeysIfSupported());
|
||||
Metrics::pkt_rendezvous_out++;
|
||||
char buf[64];
|
||||
outp.destination().toString(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);
|
||||
|
@ -408,6 +424,13 @@ void Peer::introduce(void *const tPtr,const int64_t now,const SharedPtr<Peer> &o
|
|||
}
|
||||
outp.armor(other->_key,true,other->aesKeysIfSupported());
|
||||
Metrics::pkt_rendezvous_out++;
|
||||
char buf[64];
|
||||
outp.destination().toString(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;
|
||||
|
@ -456,6 +479,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());
|
||||
char buf[64];
|
||||
outp.destination().toString(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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<Path> bp(getAppropriatePath(now,force));
|
||||
if (bp) {
|
||||
CT("UNPROCESSED");
|
||||
return bp->send(RR,tPtr,data,len,now);
|
||||
}
|
||||
return false;
|
||||
|
|
284
node/Switch.cpp
284
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> 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<const char *>(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<const uint8_t *>(data)[ZT_PACKET_FRAGMENT_IDX_FRAGMENT_INDICATOR] == ZT_PACKET_FRAGMENT_INDICATOR) {
|
||||
if (reinterpret_cast<const uint8_t &>(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<const uint8_t *>(data) + 8,ZT_ADDRESS_LENGTH);
|
||||
const Address source(reinterpret_cast<const uint8_t *>(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<Peer> 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<Peer> 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<Peer> 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<const uint8_t *>(data)[ZT_PACKET_IDX_FLAGS] & ZT_PROTO_FLAG_FRAGMENTED) != 0) {
|
||||
} else if ((reinterpret_cast<const uint8_t &>(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<const uint8_t *>(data)[0]) << 56) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[1]) << 48) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[2]) << 40) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[3]) << 32) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[4]) << 24) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[5]) << 16) |
|
||||
(((uint64_t)reinterpret_cast<const uint8_t *>(data)[6]) << 8) |
|
||||
((uint64_t)reinterpret_cast<const uint8_t *>(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;f<rq->totalFragments;++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,217 @@ 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> peer,SharedPtr<Path> 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<uint64_t, SharedPtr<Network>>::Iterator i(RR->node->_networks);
|
||||
uint64_t * k = (uint64_t *)0;
|
||||
SharedPtr<Network> *v = (SharedPtr<Network> *)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();
|
||||
|
||||
const uint8_t * payload = reinterpret_cast<const uint8_t *>(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 {
|
||||
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;fno<totalFragments;fno++) {
|
||||
chunkSize = std::min(remaining, fragSize);
|
||||
Packet::Fragment frag(packet,fragStart,chunkSize,fno,totalFragments);
|
||||
if (isCamoRequired)
|
||||
{
|
||||
CamoPattern::applyCamo(frag);
|
||||
}
|
||||
viaPath->send(RR,tPtr,frag.data(),frag.size(),now);
|
||||
fragStart += chunkSize;
|
||||
remaining -= chunkSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
void Switch::_sendViaSpecificPath(void *tPtr,SharedPtr<Peer> peer,SharedPtr<Path> viaPath,uint16_t userSpecifiedMtu, int64_t now,Packet &packet,bool encrypt,int32_t flowId)
|
||||
{
|
||||
unsigned int mtu = ZT_DEFAULT_PHYSMTU;
|
||||
|
@ -1171,6 +1400,7 @@ void Switch::_sendViaSpecificPath(void *tPtr,SharedPtr<Peer> peer,SharedPtr<Path
|
|||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void Switch::_recordOutgoingPacketMetrics(const Packet &p) {
|
||||
switch (p.verb()) {
|
||||
|
|
|
@ -3,6 +3,7 @@ CORE_OBJS=\
|
|||
node/AES_aesni.o \
|
||||
node/AES_armcrypto.o \
|
||||
node/C25519.o \
|
||||
node/CamoPattern.o \
|
||||
node/Capability.o \
|
||||
node/CertificateOfMembership.o \
|
||||
node/CertificateOfOwnership.o \
|
||||
|
|
|
@ -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();
|
||||
|
|
18
package.nix
Normal file
18
package.nix
Normal file
|
@ -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 = "tspu";
|
||||
};
|
||||
|
||||
patches = [];
|
||||
nativeBuildInputs = oldAttrs.nativeBuildInputs ++ [ ];
|
||||
|
||||
meta = oldAttrs.meta // {
|
||||
description = "Custom ZeroTierOne build with private patches";
|
||||
};
|
||||
})
|
503
rustybits/Cargo.lock
generated
503
rustybits/Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -47,6 +47,7 @@
|
|||
#include "../node/Bond.hpp"
|
||||
#include "../node/Peer.hpp"
|
||||
#include "../node/PacketMultiplexer.hpp"
|
||||
#include "../node/CamoPattern.hpp"
|
||||
|
||||
#include "../osdep/Phy.hpp"
|
||||
#include "../osdep/OSUtils.hpp"
|
||||
|
@ -1454,6 +1455,11 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// Camo settings defaults
|
||||
CamoAutoApplyBits camoAutoApply;
|
||||
CamoRelayRule relayRule = CamoRelayRule::LEAVE;
|
||||
KnownHostsMap knownHosts;
|
||||
|
||||
json &settings = lc["settings"];
|
||||
if (settings.is_object()) {
|
||||
// Allow controller DB path to be put somewhere else
|
||||
|
@ -1487,7 +1493,116 @@ public:
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Camo settings
|
||||
json &camo = settings["camo"];
|
||||
if (camo.is_object())
|
||||
{
|
||||
CT("CAMO CONFIG SECTION FOUND");
|
||||
auto stringToClass = [](std::string &str) -> CamoClass {
|
||||
CamoClass result = CamoClass::NEVER;
|
||||
std::transform(str.begin(), str.end(), str.begin(), [](unsigned char c)
|
||||
{
|
||||
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
|
||||
{
|
||||
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)
|
||||
{
|
||||
camoAutoApply[camoClass] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
for (auto it = knownHostsSection.begin(); it != knownHostsSection.end(); it++)
|
||||
{
|
||||
std::string classKey = it.key();
|
||||
|
||||
CT("FOUND CAMO CLASS: %s", classKey.c_str());
|
||||
if (it.value().is_array())
|
||||
{
|
||||
for (const auto &addrStr: it.value())
|
||||
{
|
||||
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] = stringToClass(classKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
CT("CAMO CONFIG SECTION NOT FOUND");
|
||||
}
|
||||
}
|
||||
CamoPattern::init(camoAutoApply, knownHosts, relayRule);
|
||||
|
||||
// Set trusted paths if there are any
|
||||
if (!ppc.empty()) {
|
||||
|
@ -2599,6 +2714,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);
|
||||
|
|
22
shell.nix
Normal file
22
shell.nix
Normal file
|
@ -0,0 +1,22 @@
|
|||
{ pkgs ? import <nixpkgs> { } }:
|
||||
|
||||
let
|
||||
zerotieroneCustom = pkgs.callPackage ./package.nix {};
|
||||
in
|
||||
pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
bear
|
||||
cmake
|
||||
cmake-language-server
|
||||
clang-tools
|
||||
pandoc
|
||||
]
|
||||
++ zerotieroneCustom.buildInputs
|
||||
++ zerotieroneCustom.nativeBuildInputs;
|
||||
|
||||
SSH_AUTH_SOCK = builtins.getEnv "SSH_AUTH_SOCK";
|
||||
NIXPKGS_ALLOW_UNFREE = "1";
|
||||
|
||||
shellHook = ''
|
||||
'';
|
||||
}
|
|
@ -27,7 +27,7 @@
|
|||
/**
|
||||
* Revision
|
||||
*/
|
||||
#define ZEROTIER_ONE_VERSION_REVISION 1
|
||||
#define ZEROTIER_ONE_VERSION_REVISION 2
|
||||
|
||||
/**
|
||||
* Build version
|
||||
|
|
|
@ -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 <adam.ierymenko@zerotier.com> - 1.14.2
|
||||
- see https://github.com/zerotier/ZeroTierOne for release notes
|
||||
|
||||
* Tue Mar 19 2024 Adam Ierymenko <adam.ierymenko@zerotier.com> - 1.14.0
|
||||
- see https://github.com/zerotier/ZeroTierOne for release notes
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue