Сегодня сложно кого-то удивить терминами 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, но вы можете использовать любой другой на ваш вкус. Самый простой вариант конфигурации данного сервера выглядит так:
port=53
listen-address=256.257.258.259
domain-needed
bogus-priv
server=8.8.8.8
Такая конфигурация означает, что абсолютно все запросы будут переданы на адрес 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
. Ниже приведена минимальная конфигурация, необходимая для работы.
[DNS-TCP]
type = server
host = 256.257.258.259
port = 53
keys = hidden-dns.dat
[DNS-UDP]
type = udpserver
host = 256.257.258.259
port = 53
keys = hidden-dns.dat
В параметре keys
указываются ключи, которые образуют внутрисетевой адрес. По умолчанию они лежат в директории /var/lib/i2pd
. Если файл не обнаружен, создается новый.
Перезапустите i2pd, чтобы изменения вступили в силу. I2P-адрес туннеля можно увидеть в веб-консоли, во вкладке "I2P Tunnels". В моем случае это dnsgzxkak4zlrrs5tfh42ob57iley4xrp7srrltn2j2yl2ynbiaq.b32.i2p
.
Клиент
В моем случае на клиентской машине также используется i2pd и операционная система Debian, файл туннелей располагается в том же месте, что и на сервере - /etc/i2pd/tunnels.conf
. Клиентская конфигурация может выглядить так:
[DNS-CLIENT-TCP]
type = client
address = 127.0.0.1
port = 35353
inbound.length = 2
outbound.length = 2
destination = dnsgzxkak4zlrrs5tfh42ob57iley4xrp7srrltn2j2yl2ynbiaq.b32.i2p
keys = transient-dns
[DNS-CLIENT-UDP]
type = udpclient
address = 127.0.0.1
port = 35353
destination = dnsgzxkak4zlrrs5tfh42ob57iley4xrp7srrltn2j2yl2ynbiaq.b32.i2p
keys = transient-dns
Параметры inbound.length
и outbound.length
отвечают за длину входящих и исходящих туннелей. По умолчанию они составляют три транзитных узла, но я сократил эти значения до двух, чтобы немного минимизировать задержку. Аналогичные параметры применимы в том числе и для серверных туннелей. Дополнительные параметры указаны только в первой секции, так как в самом первом блоке определяются параметры, которые применяются для всех туннелей, использующих тот же ключ (в моем случае это transient-dns
). Ключи, начинающиеся со слова transient
являются временными - после каждого рестарта i2pd, клиент будет обращаться к серверу с нового внутрисетевого адреса.
Чтобы новые туннели были созданы, нужно перезапустить 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, я маг старой школы).
iptables -t nat -A PREROUTING -i lo -p udp --dport 53 -j REDIRECT --to-port 35353
iptables -t nat -I OUTPUT -p udp -d 127.0.0.1 --dport 53 -j REDIRECT --to-ports 35353
iptables -t nat -A PREROUTING -i lo -p tcp --dport 53 -j REDIRECT --to-port 35353
iptables -t nat -I OUTPUT -p tcp -d 127.0.0.1 --dport 53 -j REDIRECT --to-ports 35353
Слышите? Прислушайтесь, это звучат фанфары! Проверьте резолвинг любым удобным способом, я воспользуюсь утилитой nslookup
:
acetone@adeb:/home/acetone$ nslookup habr.com
Server: 127.0.0.1
Address: 127.0.0.1#53
Non-authoritative answer:
Name: habr.com
Address: 178.248.237.68
Послесловие
В ходе настройки я обратил внимание, что dnsmasq в режиме ожидания занимает только UDP-сокет, однако решил оставить и TCP-туннель согласно стандарту DNS, который предусматривает передачу некоторой информации по TCP. Однако, функциональность описанного отлично наблюдается даже при отсутствии TCP-туннелей.
У приведенной конфигурации уходит в среднем 1-2 секунды на запрос и ответ до DNS-сервера. Если ваш результат покажется вам слишком медленным, вы можете сократить длину серверных и клиентских туннелей до 2. Возможны варианты с туннелями в один транзитный узел, но это применимо только для устройств, за компрометацию которых вы не переживаете: например, если ваш DNS не является секретным, длина туннелей может быть равно единице или даже нулю! В таком случае вы даете возможность пользователю выстроить более длинный анонимизирующий туннель с его стороны. Главное, делать всё с умом и не лениться знакомиться с документацией, а также советоваться со знающими людьми.
В качестве демонстрации (а может быть и для постоянного использования), можете воспользоваться сервером DNS, пользовательские конфиги для которого приведены выше.
Оригинальная статья опубликована в блоге дата-центра ITSOFT.