Pull to refresh

Как I2P-роутер работает без выделенного IP-адреса. Магия прямого подключения двух абонентов за NAT-ом

Reading time5 min
Views22K

Большинство пользователей интернета не имеют выделенного адреса. Это связано с ограниченным диапазоном адресов в протоколе IP четвертой версии (IPv4) – 4,2 миллиарда. Учитывая, что людей на планете в два раза больше, да еще у некоторых по несколько гаджетов – адресов не напасешься. Проблема решена в протоколе IPv6, который имеет невообразимо большой диапазон, где адресов хватит на всю Солнечную систему, даже когда все планеты будут населены. Однако загвоздка в том, что IPv6 внедряется очень медленно и неохотно в современную сеть. Поэтому имеем то, что имеем: интернет-провайдеры выпускают в глобальную сеть сотни и тысячи человек под одним адресом IPv4 (через NAT-сервер).

Модель выхода в сеть через NAT работает только в одну сторону – от пользователя за натом до веб-ресурса. Когда соединение установлено пользователем, веб-сервер может ему отвечать, но, если установленной сессии нет, – до пользователя нельзя достучаться извне, потому что тысячи других абонентов провайдера выходят в сеть под этим же IP-адресом, который по факту не принадлежит никому из них.

В ключе I2P сложность ситуации заключается в том, что скрытая сеть полностью децентрализована и все участники общаются со своими соседями напрямую. Вопрос, на который ответит эта статья: как происходит взаимодействие с пользователями, чьи I2P-роутеры находятся вне прямой доступности для установки соединения.

UDP Hole punch

Чтобы понять следующую часть статьи, необходимо рассмотреть протокол передачи информации UDP. UDP не контролирует целостность пакетов, зато очень быстро может их передавать. Наглядный пример использования UDP – это видео- и аудио-звонки через интернет, где предпочтительнее безвозвратная потеря информации, чем прослушивание неактуальных слов пятисекундной давности после зависания, либо NTP – протокол синхронизации времени, где нужна минимальная задержка.

В протоколе TCP информация передается в рамках установленной сессии с контролем целостности пакетов. В UDP информация просто летит на заданный адрес без всякого контроля.

В UDP существует понятие «hole punch» (пробитие окна), которое означает кратковременное резервирование порта на NAT-сервере, который закрепляется за абонентом. Вся информация, приходящая на этот порт, будет передана конкретному абоненту. Чтобы созданное окно оставалось закрепленным за абонентом, ему необходимо регулярно отправлять через него какую-либо информацию.

Из всего сказанного главное понять, что пока существует UDP-окно (hole punch), в него кто угодно может отсылать информацию, и пользователь, за которым закреплено окно, ее получит. Никаких заранее установленных сессий, как в TCP, не требуется.

Немного о транспортных протоколах I2P

В I2P используются крипто-обертки протоколов TCP и UDP – это NTCP2 и SSU соответственно. Это самые низкоуровневые протоколы I2P, через которые осуществляется вся передача информации между узлами. Иногда эти протоколы называются крипто-аналогами TCP и UDP, но фактически это крипто-обертки, которые работают поверх TCP и UDP.

NTCP2 использует в качестве транспорта TCP, поэтому имеет прямую зависимость от выделенного IP-адреса. Если прямой доступности нет, NTCP2 работать не может. Логично, что SSU работает поверх UDP и имеет его фичу в виде окна. Это позволяет использовать SSU для работы без белого адреса, например, при использовании сотовой связи.

На скриншоте показан веб-интерфейс роутера, запущенного на USB-модеме. Выделено две графы: сетевой статус со статусом недоступности и список внешних адресов. В графе SSU отображается адрес провайдерского NAT-сервера и порт, который в настоящее время закреплен за абонентом, то есть является окном (hole punch). NTCP2 не подает признаков жизни, все соединения с внешним миром идут через SSU, а для провайдера это зашифрованный UDP-трафик.

Надо заметить, что трафик пользовательского приложения и транспортный протокол I2P – две независимые плоскости, т.е. фактически пользовательский TCP-трафик может передаваться через SSU.

Флаг проводника

В статье про флудфилы описана механика публикации роутерами информации о себе (Router Info, сокращенно «RI»), которая содержит публичные ключи шифрования и флаги (Router Caps), сообщающие о пропускной способности роутера и другие важные параметры. Основываясь на этой информации, участники сети выбирают роутеры для участия в своих туннелях.

Помимо общих флагов роутера, существуют флаги для каждого адреса, указанного в RI. Например, IPv4 может быть за натом, а IPv6 – доступным глобально. Согласитесь, что обозначать одним общим флагом два адреса с абсолютно разным статусом как минимум не разумно.

Специальных флагов у адресов не много:

Нас интересует флаг C, который сигнализирует о том, что роутер может выступать в роли проводника (introducer). В современной реализации i2pd этот флаг назначается автоматически, если есть прямая доступность по SSU, то есть I2P-роутер имеет выделенный IP-адрес и открытый порт для приема внешних обращений без пробития окна.

Проводники (интродьюсеры)

I2P-роутер, который общается с внешним миром исключительно через SSU посредством пробития окон (hole punch), не может публиковать в Router Info временный адрес и порт из текущего окна.

При работе за NAT-ом роутер ищет в своей базе RI, который может быть проводником. Обращаясь к роутеру с просьбой об услуге проводника, ожидается согласие. Если согласие получено, плохо доступный роутер обзаводится проводником и с этого момента он может принимать подключения, инициированные извне.

Когда роутер работает через проводника, он вносит в свой Router Info его адрес и время истечения. Согласие между роутером и проводником длится час, после чего роутер выбирает нового проводника, либо повторно обращается к прежнему, обнуляя часовой счетчик. Новый Router Info сообщается всем актуальным собеседникам, а также публикуется на флудфилах. Как правило, роутер пользуется одновременно услугами трех проводников, публикуя адрес каждого в RI.

Задача проводника заключается в посредничестве при установлении сессии между его подопечным роутером и третьим узлом.

Внешний роутер (Alice на скриншоте) отправляет запрос проводнику (Bob), который передает информацию о новом соединении роутеру за натом (Charlie). В сообщении (RelayIntro) сообщается IP-адрес и порт того, кто хочет установить соединение. Роутер за натом отправляет на этот адрес пустой UDP-пакет, тем самым образуя окно (hole punch). Затем через это окно происходит полноценная инициализация SSU-соединения.

Таким образом может быть установлено соединение между двумя роутерами, каждый из которых находится за натом: первый при обращении к проводнику образует окно, а второй роутер при обращении в окно собеседника образует свое окно. После этого два I2P-роутера без выделенных IP-адресов общаются между собой напрямую. Изящно!

Для более подробного ознакомления с механизмами SSU можно ознакомиться в документации.

Использование не по прямому назначению

Использование фичи с проводниками (интродьюсерами) возможно и в случае с выделенным IP-адресом. Это может понадобиться для сокрытия IP-адреса из файла Router Info. В таком случае даже подробный анализ известных I2P-роутеров не выдаст злоумышленникам IP-адрес нашего роутера, потому что он не публикуется в открытом виде, а передается персонально каждому, кто устанавливает с нами соединение.

Важно понять, что речь идет о прямом соединении с роутером, а не с каким-то нашим скрытым ресурсом напрямую. Подключение к скрытым ресурсам практически всегда происходит через цепочку транзитных роутеров, где через проводника к нашему роутеру подключится только ближайший сосед по туннелю.

Чтобы i2pd с выделенным IP-адресом работал через проводников, публикуя только их адреса, необходимо запретить входящие соединения на рабочий порт I2P-роутера (то есть закрыть рабочий порт, указанный на главной странице в веб-консоли).

Рабочий порт на скриншоте - 19972
Рабочий порт на скриншоте - 19972

Для iptables правила файервола будут выглядить так:

iptables -A INPUT -p tcp --dport <i2pd_port> -j DROP
iptables -A INPUT -p udp --dport <i2pd_port> -j DROP

Если у вас есть IPv6-интерфейс, проделайте с ним аналогичные операции через утилиту ip6tables.

На выходе получим роутер с сетевым статусом "Firewalled" и режимом работы исключительно через проводников. Однако надо учесть, что это может несущественно повредить скорости.

Tags:
Hubs:
+21
Comments15

Articles