From 857092508a00cf08b6b95c883fc824e0897cbe30 Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 17 Oct 2026 19:53:34 +0200 Subject: [PATCH] docs: explain TCP NAT presence and IP-only addresses --- doc/nat_detection.txt | 11 ++++++++++- doc/node_snapshot.md | 6 +++++- src/routing_layer/topo_node.h | 1 + 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/doc/nat_detection.txt b/doc/nat_detection.txt index 0ba84b80..53c9e8b7 100644 --- a/doc/nat_detection.txt +++ b/doc/nat_detection.txt @@ -79,6 +79,15 @@ IP:порт тестового сокета на том же локальном адресов через доступные публичные узлы; ожидание одного этапа ограничено по времени. Соединения по LAN работают независимо и не сбрасывают интернет-профиль. -Если доступны только локальные узлы, определить интернет-NAT нельзя. +Если доступны только локальные узлы, измерить тип интернет-NAT для UDP нельзя. STUN на другом порту даёт предварительную оценку типа NAT для того же IP/интерфейса. Работа TCP не заменяет проверку UDP. + +Для TCP определяется только наличие NAT. Непубличный локальный IP сразу означает +NAT с неизвестным типом. Если локальный IP публичный, достаточно одного публичного +TCP-пира: по готовому защищённому соединению он сообщает увиденный IP. +IP совпали — трансляция IP не обнаружена; отличаются — NAT есть, тип UNKNOWN. +Порты при сравнении не учитываются. Публичный внешний IP сохраняется с портом 0: +входящий порт неизвестен, поэтому NCD не использует эту запись для подключения. +Тип NAT и доступность TCP-входа не проверяются. Через SOCKS внешний IP прокси +не записывается как собственный адрес. diff --git a/doc/node_snapshot.md b/doc/node_snapshot.md index 17dde208..7097aed8 100644 --- a/doc/node_snapshot.md +++ b/doc/node_snapshot.md @@ -19,7 +19,7 @@ ID и время измерения не передаются: последни проверка с тем же результатом не меняет NODEINFO. Все поля SOCKMETA — отдельные байты; границы списков metadata/адресов/REALITY также входят в каноническую подпись. Алгоритм и условия неопределённости описаны в `doc/nat_detection.txt`. -`source=ETCP` обозначает наблюдение рабочего endpoint. Одно наблюдение может дать +`source=ETCP` обозначает результат детектора рабочего endpoint. Одно UDP-наблюдение может дать адрес `TOPO_ADDR_NAT` при `mapping=UNKNOWN`, `inbound=UNKNOWN`: это NAT-кандидат для пробного подключения, а не адрес интерфейса или подтверждённый открытый вход. Общий внешний адрес подтверждает EIM; strict не публикует универсальный NAT-адрес. @@ -27,6 +27,10 @@ Source входит в подпись; SOCKMETA занимает 5 байт. `so EIM? для того же локального IP/netif с неизвестным входом; измерение ETCP приоритетно. Владелец снимает STUN-оценку после TTL. Внешний адрес тестового порта не публикуется: NAT-кандидат по-прежнему требует наблюдения рабочего сокета. +Для TCP достаточно одного публичного пира: внешний IP с неизвестным входящим +портом публикуется как `TOPO_ADDR_NAT` с `port=0`, `mapping=UNKNOWN`, `inbound=UNKNOWN`. +NCD пропускает нулевые порты. Непубличный локальный TCP IP сразу означает NAT; +совпавший с наблюдением публичный IP даёт UNCHANGED без подтверждения открытого входа. Таблица `node_snapshots` хранит полную сериализованную запись без группового окружения. `node_addresses` остаётся проекцией для поиска и отображения, а не diff --git a/src/routing_layer/topo_node.h b/src/routing_layer/topo_node.h index 805ba942..bae701af 100644 --- a/src/routing_layer/topo_node.h +++ b/src/routing_layer/topo_node.h @@ -144,6 +144,7 @@ struct TOPOMSG_NODE { #define TOPOMSG_NODE_HDR_SIZE sizeof(struct TOPOMSG_NODE) struct TOPO_SOCKMETA4 { struct TOPO_SOCKMETA4* next; uint8_t id, config_type; struct address_profile address_profile; }; +/* port=0 — известен только внешний TCP IP; адрес хранится, но не участвует в подключении. */ struct TOPO_ADDR4 { struct TOPO_ADDR4* next; uint8_t addr[4]; uint16_t port; uint8_t type, socket_id, protocol; }; struct TOPO_SOCKMETA6 { struct TOPO_SOCKMETA6* next; uint8_t id, config_type; struct address_profile address_profile; }; struct TOPO_ADDR6 { struct TOPO_ADDR6* next; uint8_t addr[16]; uint16_t port; uint8_t type, socket_id, protocol; };