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] 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;