Files
utun2/doc/nat_detection.txt
T

110 lines
11 KiB
Plaintext

Как работает детектор NAT
========================
Детектор выясняет две вещи: какой внешний IP:порт получает рабочий UDP-сокет
при обращении к разным IP и проходят ли к нему пакеты от незнакомого IP.
Проверяется именно сокет, через который работает приложение.
Есть быстрый путь без помощников: если рабочий сокет принял подключение
и локальный IP и фактический IP подключившегося узла публичные,
ему сразу ставится direct/open (UNCHANGED + OPEN). Это правило действует
для UDP и TCP, даже если с IP пира раньше уже был исходящий обмен.
Локальные подключения и SOCKS интернет-вход не подтверждают. Для TCP
фактический локальный IP должен совпадать с IP интерфейса сокета.
Нужны три узла: A проверяет себя, B наблюдает его внешний адрес,
C помогает проверить входящие пакеты. Команды и результаты передаются
по уже работающей сети uTun, в том числе через TCP или промежуточные узлы.
Сами тестовые пакеты идут напрямую по UDP.
Порядок проверки
---------------
1. A отправляет пакет узлу B. Тот сообщает, с какого IP:порта его получил.
Ответ идёт по управляющему соединению, поэтому блокировка прямого
UDP-ответа не мешает узнать внешний адрес A.
2. Через B узел A просит C отправить несколько пакетов на этот внешний адрес.
До этого A не должен отправлять ничего на IP узла C с проверяемого сокета.
Приложение хранит историю таких отправок и учитывает новые во время проверки.
На входящие тестовые пакеты A автоматически не отвечает.
3. Получатель проверяет настоящий адрес отправителя каждого тестового пакета.
Локальный или другой непубличный IP не подходит для интернет-проверки.
Для проверки незнакомого входа также не подходят IP узла B, собственный
внешний IP узла A и IP, на который A уже отправлял пакеты.
Если помощник не подходит, A выбирает другого. Разные узлы с одним IP
не считаются разными источниками. Проверяются также подлинность пакета
и принадлежность текущей попытке, чтобы чужой или старый пакет не влиял на результат.
4. Затем A сам отправляет пакет C и узнаёт, какой внешний IP:порт видит C.
Если входящие до этого не проходили и внешний адрес совпал с увиденным B,
C повторяет отправку с того же IP:порта на исходный внешний адрес A.
Так проверяется, открыл ли исходящий контакт путь для входящих.
Параллельный обмен с B подтверждает, что UDP-связь в целом работает.
5. A повторяет измерение внешнего адреса через B и C. Результат принимается,
только если адрес для каждого направления остаётся стабильным.
Сравниваются разные IP назначения; другие порты того же IP не проверяются.
Что означает результат
----------------------
strict — B и C стабильно видят разные внешние IP:порты узла A.
Единого внешнего адреса для подключения с любого IP нет.
eim open — B и C видят одинаковый внешний IP:порт, и пакет от C пришёл
ещё до исходящего контакта A с его IP.
eim filtered — внешний IP:порт одинаковый, серия пакетов до контакта не прошла,
а после исходящего контакта пакеты с того же адреса C начали приходить.
Это оценка: потерю UDP-пакетов нельзя абсолютно отличить от блокировки.
EIM? — два направления видят одинаковый внешний IP:порт, но незнакомый вход
проверить не удалось, например все доступные помощники уже были знакомы.
Это EIM с неизвестной доступностью входящих, без обещания открытого входа.
Такой же предварительный EIM? дают два STUN-сервера, видящие одинаковый внешний
IP:порт тестового сокета на том же локальном IP и интерфейсе. Поддержка запроса
с незнакомого IP для этого не нужна. Источник оценки — STUN, вход остаётся UNKNOWN.
Измерение рабочего сокета имеет приоритет; STUN-оценка действует до пяти минут
и обновляется автоматически. Публичный порт для подключения берётся только
из наблюдения рабочего сокета: внешний порт STUN в него не подставляется.
Если внешний IP:порт совпадает с локальным, отдельно отмечается отсутствие
трансляции адреса. Доступность входящих всё равно проверяется.
Если данных недостаточно, соответствующая часть результата остаётся UNKNOWN.
Известный тип NAT можно сохранить, даже если входящие проверить не удалось.
Таймаут и отсутствие подходящих узлов сами по себе не означают strict.
Если один пир уже увидел публичный IP:порт, отличный от локального, этот адрес
сразу сохраняется как NAT с type=UNKNOWN. Он публикуется отдельно от адреса
интерфейса и остаётся кандидатом для пробного подключения: одного наблюдения
недостаточно, чтобы обещать тот же адрес для других IP или открытый вход.
Уже знакомый помощник пригоден для измерения типа NAT, хотя проверить незнакомый
вход через него нельзя. Потеря результата входящих не останавливает сравнение
адресов через доступные публичные узлы; ожидание одного этапа ограничено по времени.
Измеренный mapping сохраняется сразу, а проверка незнакомого входа продолжается
через остальных помощников. Порядок обхода фиксирован на его начало; фактический
source всегда проверяется по актуальной истории. При паузе по общему бюджету
незавершённая попытка повторяется с новыми идентификаторами, без сброса обхода.
Если попытка уже получила полный бюджет, его исчерпание считается таймаутом:
обход переходит дальше, а не повторяет одного помощника бесконечно.
Старый сохранённый результат входящих не считается успехом новой проверки.
Соединения по LAN работают независимо и не сбрасывают интернет-профиль.
Если доступны только локальные узлы, измерить тип интернет-NAT для UDP нельзя.
STUN на другом порту даёт предварительную оценку типа NAT для того же IP/интерфейса.
Работа TCP не заменяет проверку UDP.
Для TCP определяется только наличие NAT. Непубличный локальный IP сразу означает
NAT с неизвестным типом. Если локальный IP публичный, достаточно одного публичного
TCP-пира: по готовому защищённому соединению он сообщает увиденный IP.
IP совпали — трансляция IP не обнаружена; отличаются — NAT есть, тип UNKNOWN.
Порты при сравнении не учитываются. Публичный внешний IP сохраняется с портом 0:
входящий порт неизвестен, поэтому NCD не использует эту запись для подключения.
Активных проб типа NAT и TCP-входа нет; OPEN устанавливается по принятому
публичному подключению и сохраняется при последующих совпавших наблюдениях IP.
Через SOCKS внешний IP прокси
не записывается как собственный адрес.