Сегодня сложно кого-то удивить терминами DoH (DNS over HTTPS), DoT (DNS over TLS) и прочими крипто-примочками для DNS. Если кто-то запрыгнул в поезд только что и не понимает о чем речь, DNS (Domain Name System) - это система доменных имен, которую каждый из нас использует сотни и тысячи раз в течение дня. Все человекочитаемые имена вроде habr.com, cia.gov и прочие ведут на определенный IP-адрес, который компьютер может узнать, обратившись на специальные серверы. Свой DNS сервер всегда есть на крупных предприятиях, у домашних интернет-провайдеров, а также у любого желающего, потому что DNS-сервер весьма прост в своем устройстве. Помимо прочих соображений, свои серверы разворачивают из соображений дополнительной приватности, потому что администратор чужого сервера, к которому мы обратимся, увидит наш адрес и будет знать какой веб-ресурс мы решили посетить.  Протокол DNS стар, как мир (~1987), поэтому не предусматривает никакого шифрования. Все запросы и ответы DNS идут по сети в открытом виде, поэтому в изначальной вариации шпионить за пользователем может не только администратор DNS-сервера, но и операторы всех промежуточных узлов, через которые проходит трафик. Современные решения вроде DNSCrypt, DNS over HTTPS и подобные им решают проблему перехвата информации по пути ее следования, так как шифруют DNS-запросы от пользователя до сервера и в обратном направлении. Но! Протоколы, которые шифруют трафик, не решают один важный вопрос - анализ всех запросов на стороне самого сервера, который всё еще видит как сам запрос, так и IP-адрес, с которого он пришел. У проекта DNSCrypt есть дополнительная примочка для этого, но меня это наслоение на трехэтажный пирог не впечатлило. Возможно, потому что у меня свой пирог... Адекватной критике буду рад, но надеюсь, не возникнет глупых комментариев о том, что каждому человеку на планете для сохранения приватности нужно иметь свой персональный DNS-сервер. DNS через анонимную сеть I2P - это концепция, в которой DNS-запросы идут в зашифрованном виде, но кроме того: во-первых, администратор сервера не имеет представления о реальном IP-адресе пользователя; во-вторых, пользователь не знает месторасположение сервера, к которому обращается (тоже хорошо, дабы избежать возможное давление на администратора). DNS over I2P, или DoI2P (или вовсе DoI) - это весьма занимательная вариация использования скрытых сетей, подробным рассмотрением которой сейчас и займемся. Стандарт предусматривает работу сервера DNS на 53 порте (веб-сайты, например, работают на стандартных портах 80 и 443), но в данном случае интереснее другое: какой транспортный протокол использует DNS. Эта информация необходима для создания подходящих туннелей через сеть I2P. I2P-роутер, обеспечивающий выход в сеть I2P, предоставляет на локальном адресе прокси типов SOCKS и HTTP. В большинстве случаев для работы с сетью используется именно прокси, но для более тонкой настройки соединения через скрытую сеть в специальном конфигурационном файле создаются отдельные туннели. Туннели бывают серверными и клиентскими. Их суть заключается в приеме соединений из скрытой сети на назначенный локальный порт какой-либо службы, например, веб-сервера, либо в передаче клиентских подключений с локального адреса туннеля в скрытую сеть. Туннели делятся на два основных типа: TCP и UDP. Основным рабочим протоколом DNS является UDP, однако стандарт предусматривает передачу некоторой информации и по протоколу TCP. Это означает, что необходимо создать два серверных и два клиентских туннеля: первый - для соединений по UDP, второй - для TCP. В примере используется крайне простой в установке и настройке сервер dnsmasq, но вы можете использовать любой другой на ваш вкус. Самый простой вариант конфигурации данного сервера выглядит так: Такая конфигурация означает, что абсолютно все запросы будут переданы на адрес 8.8.8.8. Большого смысла такой сервер не имеет, но как прослойка анонимности и просто пример для статья - самое то. Сервер принимает обращения на IP-адрес 256.257.258.259, порт 53.  Вымышленный IP-адрес выступает исключительно в роли примера, как бы изображая уже существующий сервер DNS, доступный из обычного интернета. По факту вы можете использовать локальный адрес 127.0.0.1 и любой порт на свое усмотрение, если будете обслуживать пользователей исключительно через скрытую сеть. Чтобы сделать сервер DNS доступным из I2P, необходимо создать серверные туннели. Я использую i2pd на Debian 10. Конфигурационный файл туннелей по умолчанию лежит по пути /etc/i2pd/tunnels.conf. Ниже приведена минимальная конфигурация, необходимая для работы. Обратите внимание на строку address в секции UDP-туннеля. Это необходимый параметр для нелокального адреса, который сообщает i2pd с какого адреса будут исходить поступающие обращения из скрытой сети. Этот параметр необходим для UDP-туннелей. Его можно опустить, если используется адрес 127.0.0.1. В параметре keys указываются ключи, которые образуют внутрисетевой адрес. По умолчанию они лежат в директории /var/lib/i2pd. Если файл не обнаружен, создается новый.  Перезапустите i2pd, чтобы изменения вступили в силу. I2P-адрес туннеля можно увидеть в веб-консоли, во вкладке "I2P Tunnels". В моем случае это dnsgzxkak4zlrrs5tfh42ob57iley4xrp7srrltn2j2yl2ynbiaq.b32.i2p. В моем случае на клиентской машине также используется i2pd и операционная система Debian, файл туннелей располагается в том же месте, что и на сервере - /etc/i2pd/tunnels.conf. Клиентская конфигурация может выглядить так: Параметры inbound.length и outbound.length отвечают за длину входящих и исходящих туннелей. По умолчанию они составляют три транзитных узла, но я сократил эти значения до двух, чтобы немного минимизировать задержку. Аналогичные параметры применимы в том числе и для серверных туннелей. Дополнительные параметры указаны только в первой секции, так как в самом первом блоке определяются параметры, которые применяются для всех туннелей, использующих тот же ключ (в моем случае это transient-dns). Ключи, начинающиеся со слова transient являются временными - после каждого рестарта i2pd, клиент будет обращаться к серверу с нового внутрисетевого адреса.  Параметр keepaliveinterval на клиентской стороне отвечает за отправку одного служебного пакета I2P-роутеру сервера. Именно I2P-роутеру, а не DNS-серверу или любому другому приложению, которое слушает серверный туннель I2P. Значение задается в секундах. Данная опция позволяет клиенту иметь актуальный лизсет (контактную информацию сервера), которая меняется каждые 10 минут. В случае отсутствия лизсета в момент реального DNS-запроса случится ощутимая задержка (~2-5 секунд), в момент которой будет происходить поиск лизсета. Опция keepaliveinterval появилась в i2pd 2.40. Статья актуализирована в марте 2022. Чтобы новые туннели были созданы, нужно перезапустить i2pd. На этом может показаться, что дело сделано. Но нет, остался еще один нюанс. Файл, отвечающий за настройку DNS в моей операционной системе (Debian 10), не поддерживает указание порта. Можно указать только IP-адрес сервера. Все запросы будут отправлены на порт 53, но наш туннель висит на порте 35353. Если указать в клиентских туннелях порт 53, случится ошибка и туннели созданы не будут, потому что все порты ниже 1024 являются привелегированными - зарезервированными для специальных нужд. Запустить службу на таком порте может только суперпользователь (root), а i2pd, как и другие прикладные программы, работает без прав суперпользователя. Прежде, чем запускать i2pd (или какое-то другое стороннее ПО) с правами root, глубого выдохните, а затем читайте статью дальше. Удаляем из /etc/resolv.conf прежние DNS, чтобы все запросы шли исключительно через I2P, и добавляем единственный сервер - локальный: nameserver 127.0.0.1. Это сообщит операционной системе, что за разрешением имен в адреса нужно обращаться на адрес 127.0.0.1:53. Осталось попросить ядро системы перенаправлять запросы с порта 53 на 35353, где висят наши TCP/UDP туннели, а затем отдавать ответы в обратном направлении. Самое время для магии iptables (простите, что не новомодный netfilter, я маг старой школы). Слышите? Прислушайтесь, это звучат фанфары! Проверьте резолвинг любым удобным способом, я воспользуюсь утилитой nslookup: В ходе настройки я обратил внимание, что dnsmasq в режиме ожидания занимает только UDP-сокет, однако решил оставить и TCP-туннель согласно стандарту DNS, который предусматривает передачу некоторой информации по TCP. Как бы там ни было, функциональность описанного отлично наблюдается даже при отсутствии TCP-туннелей. У приведенной конфигурации уходит в среднем 1-2 секунды на запрос и ответ до DNS-сервера. Если ваш результат покажется вам слишком медленным, вы можете сократить длину серверных и клиентских туннелей до 2. Возможны варианты с туннелями в один транзитный узел, но это применимо только для устройств, за компрометацию которых вы не переживаете: например, если ваш DNS не является секретным, длина туннелей может быть равно единице или даже нулю! В таком случае вы даете возможность пользователю выстроить более длинный анонимизирующий туннель с его стороны. Главное, делать всё с умом и не лениться знакомиться с документацией, а также советоваться со знающими людьми. В качестве демонстрации (а может быть и для постоянного использования), можете воспользоваться сервером DNS, пользовательские конфиги для которого приведены выше. Энтузиаст отказоустойчивых и скрытых сетей