Browse Source

Plan interface STUN profiles as fallback for unavailable ETCP probes

master
evgeny 13 hours ago
parent
commit
8b8b73983b
  1. 215
      doc/nat_detection.txt
  2. 12
      doc/tasks.md

215
doc/nat_detection.txt

@ -144,78 +144,143 @@ tests/stream_netns --nat-only: 16 настоящих uTun с 10 NAT, прове
профилей и точного собственного внешнего адреса. --nat-check включает эту фазу
до обычных JOIN/Merkle/BGP/streaming. Главный network namespace не меняется.
Объединение со STUN: проект доработки после rebase 2026-10-12
-----------------------------------------------------------
Сейчас stun_nat — дополнительная локальная диагностика другого UDP-порта.
Она возвращает mapped адреса, MATCH/EIM/ADM/APDM и EIF/ADF/APDF, но не меняет
address_profile или NODEINFO. Это корректная граница текущего модуля: общий
интерфейс и одинаковый SO_MARK/FIB не означают одинаковое состояние двух портов.
В ходе rebase тест переведён на address_profile, probe_only исключён из сканирования.
Сборка и полный основной набор из 145 тестов прошли.
Варианты:
1. Оставить независимый порт: показывать STUN рядом с профилем ETCP, с точным
тестовым endpoint и временем. Полезно для диагностики расхождений, но ни
внешний порт, ни классификация не становятся фактами рабочего сокета.
2. Для участия STUN в рабочем профиле использовать фактический ETCP UDP fd.
Рекомендуемый вариант для объединённого детектора; требует доработок ниже.
Владение и алгоритм варианта 2:
- NAT_DETECTION остаётся единственным планировщиком раундов и владельцем
address_profile/nat_addr/публикации. STUN выполняет транзакции и отдаёт
наблюдения; самостоятельно не назначает профиль и не закрывает ETCP fd.
- Каждое наблюдение содержит actual local IP:port, socket ID, generation,
round, endpoint наблюдателя, observed endpoint, monotonic time и причину.
Имя сокета — только метка для человека. Диагностика другого порта хранится
отдельно и не проходит проверку принадлежности рабочему endpoint.
- В прямом UDP read_callback распознавать ответы STUN до ETCP decrypt:
формат/cookie, активная 96-битная транзакция, ожидаемый source, receiving
socket/generation/round. Единственный читатель fd остаётся у транспорта;
STUN не добавляет второго uasync-reader. Отправки проходят общий учёт контактов.
- Раунд выбирает доступные ETCP или настроенные STUN-наблюдатели. Разные
имена серверов не заменяют разные реальные IP. Для обычного STUN нужны
независимые IP; расширенные пробы требуют фактически доступных alternate IP/port.
- До mapping-проб выполнять чистые ingress/CHANGE-пробы, затем наблюдения
на разных назначениях, затем повтор исходного наблюдения. Обе проверки
используют общую историю всех UDP-отправок, а не отдельную STUN history.
Загрязнение теста или отсутствие независимого адреса даёт частичный результат.
- Обычный Binding дополняет наблюдения. MATCH сам по себе не назначает EIM;
стабильное расхождение назначений даёт DEPENDENT. RFC5780 EIM соответствует
EIM либо UNCHANGED при отсутствии трансляции, ADM/APDM — DEPENDENT.
- Положительный чистый ingress может подтвердить OPEN. ADF/APDF сохранять
в диагностике; CONTACT_REQUIRED публиковать после подтверждённого перехода
до/после контакта на неизменном endpoint. Таймаут CHANGE без доказательства
работы альтернативной отправки не отличает фильтрацию от поведения сервера.
- У STUN нет проверки ключа ETCP; FINGERPRINT — CRC, не аутентификация.
Расхождение с действующими аутентифицированными фактами требует повторного
раунда и лога обоих наблюдений, а не перезаписи по принципу «последний ответ».
Таймаут дополнительной проверки не сбрасывает ещё действующий профиль.
- Свежесть проверяется по локальному monotonic времени. checked_at/evidence_id
формирует владелец при применении результата, в единой транзакции публикации.
Смена endpoint/маршрута, generation, закрытие, reload и stop отменяют все пробы.
TCP и SOCKS5 не наследуют native UDP-факты; существующая listener-проверка остаётся.
Порядок реализации: (1) общий контракт наблюдения и жизненного цикла,
(2) STUN-транзакции через рабочий UDP и безопасный demux,
(3) единое расписание/история контактов и применение результатов,
(4) локальные тесты и RFC5780-серверы в существующем изолированном стенде.
Обязательные новые тесты: разные NAT-свойства тестового и рабочего портов;
ETCP DATA/INIT во время STUN; чужие/поздние ID и reused socket generation;
контакт к alternate IP через INIT/ACK/keepalive перед CHANGE; отсутствие RFC5780,
молчаливое игнорирование CHANGE, потери и недоступные альтернативы;
расхождения STUN/ETCP, TTL, reload, смена маршрута без смены IP, shutdown/leaks;
реальные EIM/EIF, EIM/ADF, EIM/APDF, ADM/APDM на netns NAT с RTT/jitter/loss.
В текущей независимой диагностике до объединения остаются ограничения:
source_snapshot обнуляет исходный порт и не сохраняет generation; сканирование
не замечает пересоздание рабочего сокета с тем же именем/IP/настройками;
неизменившийся источник не обновляется без явного recheck; свежий тест исключает
только непосредственно предыдущий порт, а не всю возможную историю NAT этого tuple.
Эти результаты нельзя автоматически использовать как актуальные рабочие факты.
Нормативные протоколы: https://www.rfc-editor.org/rfc/rfc8489 (Binding, transaction ID),
https://www.rfc-editor.org/rfc/rfc5780#section-4.3 (mapping), #section-4.4 (filtering),
#section-4.5 (порядок и зависимость от прежнего состояния). Приведённая схема
владения и согласования результатов — проект интеграции uTun, а не требование RFC.
Резервное определение типа NAT через STUN: план 2026-10-12
-------------------------------------------------------
Уточнение пользователя: STUN группирует рабочие сокеты по одинаковым IP/netif,
создаёт аналогичный UDP-сокет с другим портом и определяет тип NAT для группы.
Когда ETCP не может выполнить проверку из-за нехватки узлов, используется STUN.
Это заменяет прежнее предложение использовать STUN непосредственно на ETCP fd.
Далее описан план; работающая резервная интеграция ещё не реализована.
1. Реестр уникальных путей
Ключ группы — (address family, фактический local IP, netif_index), без порта,
имени и socket ID. Несколько рабочих портов одного IP/netif дают одну группу.
Одинаковый IP на разных netif и разные IP одного netif — разные группы.
netif=0 сохраняет смысл автоматической маршрутизации, не приравнивается
произвольно к явно привязанному интерфейсу. Wildcard не становится отдельным IP:
сначала нужен фактический адрес пути. Неопределённый путь получает UNKNOWN.
Сканировать native UDP, исключать probe_only, SOCKS5 и only_local. TCP listener
сохраняет отдельную проверку STCP: UDP-результат ему не присваивается.
Начать с IPv4, уже поддержанного stun_nat; IPv6 требует отдельного этапа:
XOR-MAPPED IPv6, IPv6 server/config/DNS и scope/interface, без переноса IPv4-фактов.
Выбрать представителя группы, скопировать фактические bind IP/device/mark/FIB.
Порты исходных сокетов не копировать; проба владеет собственным fd/reader.
Разные mark/FIB/device внутри одного ключа означают неоднозначный путь:
группа получает UNKNOWN/incompatible_route_policy с логом, а не случайный
результат первого сокета. Ключ IP/netif при этом не усложняется.
2. Измерение и кэш STUN
Одна активная проба и один результат на группу, независимо от числа её сокетов.
Тестовый порт случайный, отличается от рабочих портов. В пределах жизни ядра
не переиспользовать ранее измеренные порты на этом IP/netif; при исчерпании
не выполнять заведомо загрязнённое входящее испытание, вернуть явную причину.
Самостоятельно закрывать только пробный fd, отменять его DNS и таймеры.
STUN запускается при появлении группы, при наличии enabled и настроенных серверов.
Разные имена серверов с одинаковым IP не считаются независимыми наблюдателями.
На чистом тестовом порту сначала проверять filtering, потом mapping и стабильность
исходного наблюдения. Переносить в кэш только завершённые пригодные свойства;
потери, ошибки, отсутствие RFC5780 и сомнительный CHANGE дают UNKNOWN/причину.
В результате хранить ключ группы, её generation, случайный evidence ID,
test IP:port, фактические серверы, mapped адреса, mapping/filtering, причины,
время измерения monotonic и Unix microseconds. TTL=300с, refresh=180с,
повтор неполной проверки через 30с; темп новых транзакций остаётся ограниченным.
Применение готового кэша к новому сокету не обновляет время измерения.
3. Выбор результата NAT_DETECTION
NAT_DETECTION остаётся единственным владельцем эффективного socket profile,
nat_addr и публикации NODEINFO. STUN предоставляет кэш по ключу группы,
уведомляет о завершении/инвалидации; сам не меняет профили рабочих сокетов.
Реестр групп не держит указателей на рабочие сокеты: потребитель проверяет
собственные socket generation и актуальную принадлежность группе перед применением.
Хранить отдельно собственный результат ETCP и выбранный эффективный профиль.
Добавить profile source: NONE / ETCP / STUN, в том числе в подпись, wire,
SQLite и диагностические API. STUN означает резервную оценку по интерфейсу,
ETCP — измерение рабочего endpoint. Подписывает публикацию только сам узел.
Приоритет: действующий измеренный ETCP -> пригодный STUN при невозможности
ETCP из-за отсутствия наблюдателя/независимого помощника -> UNKNOWN.
Для STUN использовать реальные NO_OBSERVER/NO_HELPER, не общее число узлов:
третий узел может быть offline, несовместимым или иметь тот же IP наблюдателя.
После исчерпания замены таких помощников разрешать резервное применение.
Пока STUN не готов, оставить UNKNOWN или ещё действующий профиль ETCP.
Частичный, но измеренный ETCP не заменять целиком STUN: DEPENDENT с неизвестным
ingress является полезным результатом. В первой версии не смешивать facets
разных источников. Неудача нового раунда не стирает ещё действующий ETCP.
Появление подходящего помощника ускоряет повтор ETCP; его успешный результат
заменяет резервный без ожидания TTL. Не сбрасывать ETCP при завершении STUN.
4. Преобразование и использование типа
RFC5780 EIM -> EIM; отсутствие трансляции в согласованном измерении -> UNCHANGED;
ADM/APDM и устойчивое расхождение обычных серверов -> DEPENDENT.
EIF -> OPEN; ADF/APDF -> CONTACT_REQUIRED; неизвестный facet остаётся UNKNOWN.
Это преобразование применяется с source=STUN и описывает резервную оценку.
Обычный MATCH остаётся неполной диагностикой, сам по себе не назначает EIM.
Для полного определения типа необходимы доступные серверы с RFC5780.
Тип STUN помогает выбирать прямые/reverse попытки, но не доказывает их успех.
Различное поведение NAT для рабочих и тестовых портов допустимо: источник
оценки виден в логах и метаданных, реальные факты ETCP имеют приоритет.
Не запрещать LAN/hairpin или закрывать работающую связь по резервной оценке.
NCD не объявляет рабочий endpoint недоступным только на основании STUN.
mapped IP:port тестового сокета никогда не копировать в nat_addr рабочего.
Не подставлять туда рабочий local port: NAT может изменить его независимо.
Общий внешний адрес рабочего сокета публиковать только с самостоятельным
подтверждением его EIM/endpoint средствами ETCP. При наличии одного наблюдателя
его адрес остаётся наблюдением для данного назначения, не общим NAT-адресом.
5. Жизненный цикл и диагностика
Добавление/удаление дубликата не повторяет STUN для неизменившейся группы.
Исчезновение последнего рабочего сокета удаляет группу и отменяет пробу.
Смена IP/interface/параметров маршрутизации инвалидирует соответствующий кэш;
смена маршрута без смены IP и явный recheck запускают новое измерение.
Generation относится к пути и раунду STUN, а не к имени представителя.
Поздние ответы не применяются к пересозданной группе. Reload/stop отменяют всё
до освобождения config/сокетов; порядок уничтожения не вызывает публикацию.
INFO: создание/удаление группы, начало/результат пробы, выбор source, возврат
к ETCP. DEBUG: объединённые дубликаты, transaction/generation/время/причины.
WARN/ERROR: неподходящие помощники, неоднозначный путь, timeout/ошибка/несогласованность.
В статусе доступны эффективный профиль, оба результата и причина выбора STUN.
Этапы реализации: (1) группировка и API STUN по ключу IP/netif,
(2) generation/TTL/обновление и завершение проб,
(3) source в модели/подписи/wire/SQLite/статусе,
(4) выбор резерва и возврат к ETCP, независимое хранение внешних адресов,
(5) локальные и изолированные сетевые тесты. Изменять ETCP UDP demux не требуется.
План тестов
-----------
- Два порта одного IP/netif: одна проба, применение резерва обоим сокетам.
Разные IP/netif: отдельные пробы; разные mark/FIB внутри группы: явный UNKNOWN.
- Смена представителя и удаление одного дубликата не теряют результат; удаление
последнего, новая группа и поздний ответ проверяют владение и generation.
- Нет узлов / один наблюдатель / все помощники за одним IP: STUN fallback.
Живой независимый помощник: ETCP; появление/исчезновение, TTL и обе очередности
завершения проверяют приоритет. Частичный ETCP не затирается полным STUN.
- RFC5780 EIM/EIF, EIM/ADF, EIM/APDF, ADM/APDM; обычный MATCH; недоступные
альтернативы, ignored CHANGE, DNS, потери, нестабильность и ограничение повторов.
- NAT по-разному обрабатывает тестовый и рабочий порты: резерв помечен STUN,
реальный ETCP его заменяет; тестовый mapped port не попадает в NODEINFO/NCD.
- Смена маршрута без смены IP, refresh, reload, stop, callbacks и утечки.
Общий evidence/time кэша не омолаживается при новом socket или NODEINFO.
- В tests/stream_netns разместить RFC5780-серверы с двумя IP/двумя портами,
сценарий двух uTun, затем добавить третьего. Проверить переключение источника
типа при RTT/jitter/loss; всю сетевую настройку выполнять в отдельных namespace.
Основания: https://www.rfc-editor.org/rfc/rfc5780#section-4.1 (выбор тестового порта
и ограниченность переноса результата), #section-4.3/#section-4.4 (классы).
Приоритет и применение резерва — согласованный проект uTun, не гарантия RFC.

12
doc/tasks.md

@ -4,12 +4,12 @@
## Текущие задачи
[ ] **STUN: объединённый детектор рабочего endpoint** — план и варианты в
`doc/nat_detection.txt`, раздел после rebase 12.10.2026. Текущий STUN измеряет
другой порт, его результат нельзя переносить в ETCP/NODEINFO. Нужны единый
владелец профиля, STUN через рабочий UDP fd, общая история контактов и отмена
по socket generation. Дополнительно проверить молчаливое игнорирование CHANGE,
повторное использование тестовых портов, давность и смену маршрута без смены IP.
[ ] **STUN: резервное определение типа NAT по IP/netif** — уточнённый план
12.10.2026 в `doc/nat_detection.txt`. Одна группа и отдельный тестовый UDP-порт
на уникальный IP/netif, общий кэш с generation/TTL. При NO_OBSERVER/NO_HELPER
применять пригодную оценку STUN с явным source; измеренный ETCP приоритетен.
mapped адрес тестового сокета не переносить на рабочий. Проверить дубликаты,
переход STUN -> ETCP, различия по портам и жизненный цикл; namespace-стенд.
[ ] **check.sh: изоляция сетевых integration-тестов** — после основного набора
автоматически запускает check-proxy/burst/load при доступном sudo. Скрипты

Loading…
Cancel
Save