Большинство пользователей интернета не имеют выделенного адреса. Это связано с ограниченным диапазоном адресов в протоколе 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" и режимом работы исключительно через проводников. Однако надо учесть, что это может несущественно повредить скорости.