You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
13 KiB
145 lines
13 KiB
Детектор свойств endpoint |
|
======================== |
|
|
|
Владелец рабочего сокета единственный вычисляет и публикует его профиль. |
|
Помощники возвращают наблюдения и выполняют прямые испытания. Профиль относится |
|
к протоколу, семейству, фактическому локальному IP:port и поколению сокета. |
|
PUBLIC/NAT/PRIVATE/LOCAL — политика конфигурации, а не результат измерения. |
|
|
|
Модель: src/routing_layer/address_profile.h. |
|
mapping: UNKNOWN, UNCHANGED, EIM, DEPENDENT. |
|
inbound: UNKNOWN, OPEN, CONTACT_REQUIRED. |
|
evidence_id: случайный 64-битный ID завершённого раунда владельца. |
|
checked_at: время измерения владельца, Unix microseconds. |
|
generation: случайный 64-битный ID жизненного цикла локального endpoint. |
|
|
|
UNCHANGED означает совпадение наблюдаемых и локального адресов на испытанных |
|
направлениях. Оно не доказывает свободный вход. EIM означает одинаковый внешний |
|
endpoint на испытанных разных IP и портах; оно также не доказывает свободный вход. |
|
DEPENDENT означает различие mapping на испытанных назначениях, без общего |
|
внешнего адреса. Дальнейшее разделение ADM/APDM не используется для выбора NCD. |
|
|
|
UDP-раунд |
|
--------- |
|
|
|
1. Владелец A выбирает живого наблюдателя B с доступным native UDP endpoint. |
|
Через проверяемый сокет S выполняет OBSERVE. Ответ содержит фактический |
|
source IP:port, наблюдаемый B, и исходный тег S/generation/round. |
|
2. Через уже установленный ETCP к B запрашивает поиск помощника C. |
|
B выбирает C из своих работающих UDP-пиров и возвращает его ключ и endpoint. |
|
Собственный подтверждённый NAT-профиль B/C не требуется: иначе bootstrap |
|
зависел бы от уже завершённой детекции. Пригодность подтверждают реальные пробы. |
|
3. Если внешний IP C совпадает с IP B, A исключает C и командует B искать |
|
следующего помощника. Совпадающие Node ID и разные порты одного IP не дают |
|
независимого IP-наблюдения. При отсутствии второго IP результат неполный. |
|
4. Для входящего испытания выбирается C, с IP которого S ранее не контактировал. |
|
Все команды C идут A -> B -> C. До первого испытания A не шлёт UDP к C. |
|
C отправляет три аутентифицированные ADDRESS_CHECK к endpoint из наблюдения B. |
|
A регистрирует фактический ingress на S; один отчёт о PONG не заменяет ingress. |
|
5. После завершения первого испытания S выполняет OBSERVE к основному порту C, |
|
затем к другому UDP-порту того же помощника. Вспомогательный порт принадлежит |
|
наблюдателю, скрыт из NODEINFO и исключён из NCD. Проверяемый S не меняется. |
|
6. Если первый ingress отсутствовал, C здоров и mapping к C совпал с mapping к B, |
|
после исходящего контакта выполняется второе входящее испытание от того же C. |
|
Контролируемый переход до/после контакта даёт CONTACT_REQUIRED. |
|
7. S повторяет исходное наблюдение у B. Изменение этого mapping во время раунда |
|
даёт UNKNOWN/address_changed и инвалидирует прежний общий внешний адрес. |
|
8. При совпадении наблюдений B/C/C-alt выбирается UNCHANGED или EIM; различие |
|
назначений даёт DEPENDENT. Первый чистый ingress даёт OPEN; подтверждённый |
|
переход после контакта при неизменном endpoint — CONTACT_REQUIRED. |
|
|
|
Если независимых от истории C больше нет, уже контактировавший C может измерить |
|
mapping. Входящая часть остаётся UNKNOWN/contact_history. Отказ проверки одного |
|
facet не превращается в ложный STRICT. Потери, ошибка отправки, отсутствие |
|
помощника, разрыв управления и неправильный ответ имеют отдельную причину. |
|
|
|
Контакты и повторы |
|
----------------- |
|
|
|
История IP назначения учитывает INIT, DATA, ACK, keepalive, PING/PONG и другие |
|
отправки с S в двух общих точках UDP-send. Любая неожиданная отправка к C до |
|
получения первого ingress делает входящее испытание загрязнённым. |
|
|
|
История записывается в nat_contacts общей SQLite один раз на новый IP. Ключ — |
|
семейство и фактический локальный IP:port. Перезапуск на том же endpoint её не |
|
очищает. Максимум 256 IP на endpoint; переполнение/ошибка сохранения отмечаются |
|
постоянным маркером неполной истории. Неизвестная история запрещает вывод OPEN |
|
по испытанию, которое может использовать старое разрешение фильтра. |
|
|
|
История характеризует наблюдаемый приложением трафик. Удаление БД, использование |
|
того же tuple другим процессом или изменение NAT вне наблюдаемого раунда нельзя |
|
превратить в доказательство полного отсутствия прежнего состояния. Результаты |
|
остаются подсказками для попыток, подтверждение связи даёт handshake с нужным ключом. |
|
|
|
Один активный раунд на S. Таймаут пробы — max(1 секунда, 4*RTT), не более 3 секунд; |
|
три попытки, бюджет раунда 30 секунд. Повтор после ошибки через 30 секунд или |
|
после появления подходящего транспорта; штатный refresh через 180 секунд. |
|
Срок фактов — 300 секунд. Таймеры владельца используют monotonic timebase; |
|
checked_at не обновляется повторным NODEINFO и не зависит от ответа сервера NTP. |
|
При несогласованных часах получатель использует осторожные попытки, не отказ. |
|
|
|
TCP и прокси |
|
------------- |
|
|
|
TCP inbound проверяется отдельным STCP handshake к объявленному настоящему |
|
listener с проверкой ключа владельца. Его target должен присутствовать в |
|
подписанном snapshot. Внешний порт исходящего TCP-соединения не рекламируется |
|
как listener. Без публичного кандидата профиль остаётся UNKNOWN/no_listener. |
|
UDP-факты не переносятся на TCP. Входящий TCP source port не определяет профиль |
|
listener удалённого клиента. SOCKS5 UDP не классифицируется как native endpoint. |
|
|
|
Корреляция и владение |
|
-------------------- |
|
|
|
Транспортный PONG сопоставляется по криптографически случайному nonce, ожидаемому |
|
ключу, source IP:port, ID и поколению принимающего сокета. Входящее испытание |
|
дополнительно проверяет владельца, round, step и token. Перед callback PING |
|
удаляется из pending. Отмена не вызывает callback и не интерпретирует void* arg |
|
как контекст другого типа. Произвольный выбор первого IPv4/TCP-сокета запрещён. |
|
|
|
Broker принимает RUN только для записанного им UDP-наблюдения данного владельца. |
|
Размер wire, версия, enum, границы списка исключений и ненулевые поколения/раунды |
|
проверяются до обработки. Числа новых сообщений — BE, IP — сетевые байты. |
|
owner_key и helper_key имеют разные поля и никогда не меняют значение по роли. |
|
|
|
На смене адреса, закрытии сокета, reset/DELETE транспорта и остановке ядра |
|
отменяются собственные раунды и связанные helper jobs. Поздние ответы не |
|
применяются к новому socket generation даже при повторном ID и IP:port. |
|
Детектор останавливается до разборки групп, сокетов и соединений. |
|
|
|
Публикация и NCD |
|
--------------- |
|
|
|
Профиль публикуется только владельцем в общей подписанной записи NODEINFO. |
|
Списки и их границы входят в подпись; mapping/inbound/evidence/checked_at |
|
сохраняются и загружаются вместе. node_addresses — производная проекция: |
|
nat_mapping, nat_inbound, nat_evidence, nat_checked, address_kind. |
|
При изменении формата старый кэш адресов пересоздаётся; старый NAT_TYPE не |
|
интерпретируется как новая модель. Подписанные snapshots и записи чата не удаляются. |
|
|
|
Общий NAT-адрес рекламируется только после EIM. DEPENDENT не рекламирует |
|
универсальный внешний endpoint. NTP.reachable не управляет рекламой адресов. |
|
Ошибки публикации логируются; детектор повторяет сохранение/публикацию. |
|
|
|
NCD различает OPEN, CONTACT и непроверенные публичные кандидаты. UNKNOWN допускает |
|
ограниченные попытки. Контактирующие EIM используют обычные встречные INIT-пробы |
|
NCD и reverse. Одинаковый внешний IP не запрещает hairpin и не доказывает общую |
|
LAN; частные адреса проверяются маршрутизацией и аутентификацией нужного пира. |
|
Профиль не закрывает уже работающий транспорт. Признак PUBLIC конфигурации |
|
может влиять на очередность попыток CM, но не назначает подтверждённый NAT-тип. |
|
Стриминг сохраняет raw NCD + REVERSE_REQ через группу, без routed DATA fallback. |
|
|
|
Проверки |
|
-------- |
|
|
|
test_route_ping: реальные UDP-наблюдения, эталонные байты IPv4/IPv6, неправильный |
|
round, аутентичный PONG чужого ключа, старое поколение, отмена без callback. |
|
test_nat_detection: разные socket ID, два рабочих UDP endpoint, TCP listener, |
|
замена помощника с тем же IP, повтор по старому контакту, подпись/SQLite профиля, |
|
закрытие S посреди раунда и повторный ID/порт. Утечки/таймеры/сокеты проверяются. |
|
test_sock_match: независимость политики от фактов, UNKNOWN, CONTACT, давность, |
|
частные адреса и разрешённая попытка hairpin. |
|
|
|
tests/stream_netns --nat-only: 16 настоящих uTun с 10 NAT, проверка всех UDP/TCP |
|
профилей и точного собственного внешнего адреса. --nat-check включает эту фазу |
|
до обычных JOIN/Merkle/BGP/streaming. Главный network namespace не меняется.
|
|
|