Служба DNS или Domain Name System является базовым сервисом сети Интернет, а также иных сетей работающих на базе семейства протоколов TCP/IP, и используется для получение соответствия имени узла в сети соответствующему ему цифровому адресу.
Несмотря на столь простое описание DNS является, пожалуй, самой сложной по своей структуре и набору взаимодействий сетевой службой от надёжной работы которой зависит надёжная работа всех и вся.
Автор уже затрагивал вопросы функционирования DNS в цикле статей в разрезе наиболее современных и актуальных практических вопросов внедрения DNSSEC. Напомню, что DNSSEC обеспечивает удостоверение записей DNS при помощи цифровых подписей, чем защищает их от возможной подмены. Однако, при этом, все данные всегда передаются в открытом виде и никак не защищены от просмотра в процессе транзита и, при отсутствии цифровой подписи, при желании с лёгкостью могут быть модифицированы в тех или иных целях — от криминальных до цензурных.
Данная статья посвещена практическим способам защиты DNS трафика.
Действительно, на момент своего создания более чем 30 лет назад вопрос защиты передаваемой через DNS информации. Поэтому несмотря на очевидность проблемы в силу исторических причин до сих пор все данные совершенно открыты в процессе транзита. Для примера можно взглянуть на них стандартными средствами операционной системы, к примеру, утилиты tcpdump.
root@my:~ # tcpdump -i tun0 -n -nn -ttt 'port 53'
tcpdump: verbose output suppressed, use -v or -vv for full protocol decode
listening on tun0, link-type NULL (BSD loopback), capture size 262144 bytes
00:00:00.000000 IP 89.39.107.72.19058 > 1.2.3.4.53: 19491% [1au] A? www.my.domain. (41)
00:00:00.016706 IP 1.2.3.4.53 > 89.39.107.72.19058: 19491*- 4/3/1 CNAME my.domain., RRSIG, A 46.4.120.253, RRSIG (435)
00:01:17.233741 IP 1.2.3.4.22679 > 68.142.255.16.53: 28165% [1au] AAAA? ns4.yahoo.com. (42)
00:00:00.000054 IP 1.2.3.4.37567 > 203.84.221.53.53: 32770% [1au] AAAA? ns5.yahoo.com. (42)
00:00:00.036409 IP 68.142.255.16.53 > 1.2.3.4.22679: 28165*- 0/1/1 (103)
00:00:00.002475 IP 1.2.3.4.63693 > 68.142.254.15.53: 11422% [1au] AAAA? mta5.am0.yahoodns.net. (50)
00:00:00.029746 IP 68.142.254.15.53 > 1.2.3.4.63693: 11422*- 0/1/1 (120)
00:00:00.000387 IP 1.2.3.4.28336 > 68.180.130.15.53: 16455% [1au] A? mta5.am0.yahoodns.net. (50)
00:00:00.029690 IP 68.180.130.15.53 > 1.2.3.4.28336: 16455*- 8/0/1 A 98.137.159.28, A 67.195.229.59, A 74.6.137.65, A 67.195.229.58, A 98.137.159.26, A 98.137.159.27, A 98.136.102.55, A 74.6.137.63 (178)
00:00:00.001624 IP 1.2.3.4.50387 > 68.142.254.15.53: 10530% [1au] AAAA? mta6.am0.yahoodns.net. (50)
00:00:00.028234 IP 68.142.254.15.53 > 1.2.3.4.50387: 10530*- 0/1/1 (120)
00:00:00.000280 IP 1.2.3.4.10490 > 68.142.254.15.53: 26126% [1au] A? mta6.am0.yahoodns.net. (50)
00:00:00.022699 IP 203.84.221.53.53 > 1.2.3.4.37567: 32770*- 0/1/1 (103)
00:00:00.017178 IP 68.142.254.15.53 > 1.2.3.4.10490: 26126*- 8/0/1 A 66.218.85.52, A 74.6.137.64, A 67.195.229.59, A 67.195.229.58, A 98.137.159.24, A 98.137.159.26, A 98.137.159.28, A 98.136.101.117 (178)
00:00:00.000915 IP 1.2.3.4.46574 > 68.180.130.15.53: 14314% [1au] AAAA? mta7.am0.yahoodns.net. (50)
00:00:00.028844 IP 68.180.130.15.53 > 1.2.3.4.46574: 14314*- 0/1/1 (120)
00:00:00.000335 IP 1.2.3.4.7539 > 68.142.254.15.53: 9379% [1au] A? mta7.am0.yahoodns.net. (50)
00:00:00.029458 IP 68.142.254.15.53 > 1.2.3.4.7539: 9379*- 8/0/1 A 98.137.159.27, A 98.136.102.54, A 66.218.85.52, A 98.137.159.25, A 98.136.102.55, A 98.137.159.24, A 74.6.137.63, A 74.6.137.64 (178)
00:00:02.160590 IP 206.190.33.24.51154 > 1.2.3.4.53: 19088% [1au] A? foo.my.domain. (41)
00:00:00.000106 IP 1.2.3.4.53 > 206.190.33.24.51154: 19088*- 2/3/3 A 1.2.3.4, RRSIG (367)
00:00:00.004227 IP 206.190.33.24.53589 > 1.2.3.4.53: 47712% [1au] AAAA? foo.my.domain. (41)
00:00:00.000045 IP 1.2.3.4.53 > 206.190.33.24.53589: 47712*- 2/3/3 AAAA 2001:470:28:26f::1, RRSIG (367)
00:00:00.054647 IP 206.190.33.24.55240 > 1.2.3.4.53: 20459 [1au] TXT? key.kostikov.co.my.domain. (53)
00:00:00.000106 IP 1.2.3.4.53 > 206.190.33.24.55240: 20459*- 2/3/5 TXT "v=DKIM1; k=rsa; p=" "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw8VlaalK7d44lwAqHc4u" "zBz+o6bO9g+ZwkoAKP0cyTMxaCIE2khjs5w8iAfkK6gNpO7j9LGn3Iel3MGVSfGi" "pUEvWhjx/b0UUdQOrDejUz3vcb8szWRuTxCp73zwX9HopdA1BllMdf0VrHfBboPU" "Qdm6XWn+fygRDnuyBpvlut3B75bV6//cpXc/sLiQwI50YpZ54artcXK9/4e0qCgY" "i+bBNZpgIvY3T/WTjSsPqwTLiWOT29XBavkAVUAvBaSzQkgLWM0Y0LkEeSLhfaHd" "Y7EJeUIIsP8TVsTiyYlVj0OJBtfodWwPXyTZsWpuWuud8UXEs8tOJmnB1QCf2LyA" "dQIDAQAB", RRSIG (894)
...
Здесь прекрасно видны как запросы к удалённым серверам, так и их ответы.
Имея исключительно эти данные нетрудно получить полное представление о том, к каким именно ресурсам и с какой целью вы обращались. Также эти данные могут быть подменены при невозможности использования по тем или иным причинам DNSSEC, переадресовав вас, к примеру, на поддельный сайт или заблокировав доступ к определённой информации по цензурным соображениям.
Данная проблема DNS давно и широко известна интернет-сообществу. В качестве её решения было предложено к использованию два наиболее распространённых решения — DNScrypt и DNS-over-TLS, которые представляют собой инкапсуляцию DNS трафика в шифрованный канал.
Протокол DNScrypt является первым реализованным решением для защиты DNS трафика от просмотра и намеренной модификации при транзите. По сути он представляет собой упрощённую версию TLS, где вместо цепочки доверенных сертификатов используется лишь один, который удостоверяет сервер к которому производится защищённое подключение.
DNScrypt может использовать сетевые протоколы UPD и TCP обычно используя в качестве порта 443 который является стандартным и для HTTPS.
Подробное описание как он работает есть на официальном сайте. Вкратце, вначале по имени сервера производится обращение к специальной TXT-записи DNS формата 2.dnscrypt-cert.domain.name для получения текущего ключа публичного сертификата. Например, для сервера cisco, который является псевдонимом приобретённого некоторое время назад этой компанией сервиса OpenDNS, она на момент написания статьи выглядит следующим образом.
root@my:~ # host -t txt 2.dnscrypt-cert.opendns.com
2.dnscrypt-cert.opendns.com descriptive text "DNSC\000\001\000\000;\200\196\196\240\012\002\219\217\012\192\172/\223\024\240on\171\012\209\140d\128\189\211B\1962D{\1294j\006lg}\020\178\019a\210@\180*a\004\162^\167\165\149:d\211\157\025\228)\183\1400\007$\011\017\183\173\002\250\192b\133\030\136n\170D\231\174[\173/\146\031\149wQM\226&\213Rh6qNzimeuUZy\250\165Zy\250\165\\[.%"
Далее производятся соответствующие процедуры обмена и генерация сессионных ключей и начинается работа с данными в шифрованном виде.
Стандартным способом использования DNScrypt является установка специального клиента dnscrypt-proxy, который доступен для множества платформ. Он выступает в качестве транслятора стандартных запросов DNS через защищённый канал к поддерживающим DNScrypt серверам (см. список публичных серверов).
Поскольку это именно прокси, он не имеет функции кэширования запросов что может негативно сказываться на производительности всех использующих Интернет приложений. В этой связи целесообразно использовать его в связке с локальных кэширующим DNS сервером.
Рассмотрим пример такой настройки совместно с популярным DNS сервером Unbound который уже ранее установлен в среде FreeBSD.
root@my:~ # uname -v
FreeBSD 11.1-RELEASE-p8 #0: Tue Mar 13 17:07:05 UTC 2018 root@amd64-builder.daemonology.net:/usr/obj/usr/src/sys/GENERIC
root@my:~ # cd /usr/ports/dns/unbound/
root@my/usr/ports/dns/unbound # make showconfig
===> The following configuration options are available for unbound-1.7.0:
DNSCRYPT=on: Enable dnscrypt support
DNSTAP=off: Enable dnstap logging support
DOCS=on: Build and/or install documentation
ECDSA=on: Enable ECDSA (elliptic curve) support (OpenSSL >= 1.0)
EVAPI=off: (Experimental) pluggable event based libunbound API support
FILTER_AAAA=off: Build with AAAA filter functionality (contrib)
GOST=off: Enable GOST support (requires OpenSSL >= 1.0)
LIBEVENT=on: Build against libevent
MUNIN_PLUGIN=off: Install Munin plugin
PYTHON=off: Python bindings or support
SUBNET=off: Enable client subnet support
TFOCL=on: Enable TCP Fast Open for client mode
TFOSE=on: Enable TCP Fast Open for server mode
THREADS=on: Threading support
Установим прокси-сервер DNScrypt.
root@my/usr/ports/dns/unbound # cd /usr/ports/dns/dnscrypt-proxy/
root@my:/usr/ports/dns/dnscrypt-proxy # make install clean
===> License MIT accepted by the user
===> dnscrypt-proxy-1.9.5_3 depends on file: /usr/local/sbin/pkg - found
=> dnscrypt-proxy-1.9.5.tar.gz doesn't seem to exist in /usr/ports/distfiles/.
=> Attempting to fetch http://distcache.FreeBSD.org/local-distfiles/dbaio/dnscrypt-proxy/dnscrypt-proxy-1.9.5.tar.gz
dnscrypt-proxy-1.9.5.tar.gz 100% of 1624 kB 7160 kBps 00m00s
===> Fetching all distfiles required by dnscrypt-proxy-1.9.5_3 for building
===> Extracting for dnscrypt-proxy-1.9.5_3
=> SHA256 Checksum OK for dnscrypt-proxy-1.9.5.tar.gz.
...
root@my:/usr/ports/dns/dnscrypt-proxy # sysrc dnscrypt_proxy_enable=YES
root@my:/usr/ports/dns/dnscrypt-proxy # sysrc dnscrypt_proxy_flags="-a 127.0.0.1:8053"
root@my:/usr/ports/dns/dnscrypt-proxy # service dnscrypt-proxy start
Starting dnscrypt_proxy.
Sat Mar 24 21:41:33 2018 [INFO] Randomly chosen resolver: [d0wn-is-ns1]
Sat Mar 24 21:41:33 2018 [INFO] + DNS Security Extensions are supported
Sat Mar 24 21:41:33 2018 [INFO] + Provider supposedly doesn't keep logs
root@my:/usr/ports/dns/dnscrypt-proxy # cat /var/log/dnscrypt-proxy.log
Sat Mar 24 21:41:33 2018 [NOTICE] Starting dnscrypt-proxy 1.9.5
Sat Mar 24 21:41:33 2018 [INFO] Generating a new session key pair
Sat Mar 24 21:41:33 2018 [INFO] Done
Sat Mar 24 21:41:33 2018 [INFO] Server certificate with serial #1521918421 received
Sat Mar 24 21:41:33 2018 [INFO] This certificate is valid
Sat Mar 24 21:41:33 2018 [INFO] Chosen certificate #1521918421 is valid from [2018-03-24] to [2018-03-25]
Sat Mar 24 21:41:33 2018 [INFO] Server key fingerprint is BB32:C1B4:04A3:D25F:A52C:CF36:CAC8:FAEE:B83C:D95D:8A47:96C3:BDDF:D58E:E745:7B4B
Sat Mar 24 21:41:33 2018 [NOTICE] Proxying from 127.0.0.1:8053 to 107.181.168.52:443
В данном случае будет использоваться случайный DNScrypt-сервер из списка /usr/local/share/dnscrypt-proxy/dnscrypt-resolvers.csv, включённого в дистрибутив прокси-сервера. Можно также принудительно указать предпочтительный сервер путём включения нужной опции в файл инициализации /etc/rc.conf, к примеру, вышеупомянутый сервер OpenDNS.
root@my:~ # sysrc dnscrypt_proxy_resolver="cisco"
Сервис запущен и доступен на локальном адресе 127.0.0.1 используя порт 8053.
root@my:/usr/ports/dns/dnscrypt-proxy # sockstat -46 | grep 53
unbound unbound 18404 3 udp6 ::1:53 *:*
unbound unbound 18404 4 tcp6 ::1:53 *:*
unbound unbound 18404 5 udp4 127.0.0.1:53 *:*
unbound unbound 18404 6 tcp4 127.0.0.1:53 *:*
_dnscrypt-proxy dnscrypt-p18375 7 udp4 127.0.0.1:8053 *:*
_dnscrypt-proxy dnscrypt-p18375 9 tcp4 127.0.0.1:8053 *:*
Теперь перенаправим запросы Unbound к работающем прокси-серверу DNScrypt. Для этого достаточно лишь добавить адрес, который использует прокси в качестве форвардера в секции forward-zone файла конфигурации /usr/local/etc/unbound/unbound.conf.
root@my:/usr/ports/dns/dnscrypt-proxy # cat /usr/local/etc/unbound/unbound.conf
server:
...
do-not-query-localhost: no
...
forward-zone:
name: "."
forward-addr: 127.0.0.1@8053
...
Unbound имеет возможность выступать и в качестве сервера обслуживающего DNScrypt запросы.
Однако, ввиду относительной сложности работы с ключами DNScrypt, а именно необходимости генерации, ротации и контроля срока действия ключей при помощи сторонней утилиты dnscrypt-wrapper, автор не видит смысла в такой схеме использования Unbound.
Исключительно для информации лишь упомянем, что для соответствующих настроек используется специальная секция dnscrypt в файле конфигурации Unbound.
root@my:~ # cat /usr/local/etc/unbound/unbound.conf
server:
...
interface: 0.0.0.0@5443
interface: ::0@5443
...
dnscrypt:
dnscrypt-enable: yes
dnscrypt-port: 443
dnscrypt-provider: 2.dnscrypt-cert.my.domain.
dnscrypt-secret-key: /usr/local/etc/unbound/1st.key
dnscrypt-secret-key: /usr/local/etc/unbound/2nd.key
dnscrypt-provider-cert: /usr/local/etc/unbound/1st.cert
dnscrypt-provider-cert: /usr/local/etc/unbound/2nd.cert
...
Здесь Unbound открыт для обслуживания DNScrypt запросов на порту 5443 (во избежание конфликтов использующим 443 порт HTTP-сервером) используя два набора ключей с различными сроками действия во избежание временных разрывов в работе.
Другим более современным способом защиты DNS трафика явился протокол DNS-over-TLS описанный в стандарте RFC7858, который представляет собой инкапсуляцию данных в стандартный TLS. Для доступа рекомендуется использовать порт 853.
Также как и в случае с DNScrypt предполагается, что клиент DNS, каковым обычно выступает тот же локальный кэширующий DNS, обращается к поддерживающим DNS-over-TLS удалённым серверам (см. актуальный список).
Вышеупомянутый Unbound имеет встроенную поддержку данного протокола, поэтому никакой дополнительной программной прослойки для использования, как это было в случае с DNScrypt, не требуется.
Для работы в качестве клиента DNS-over-TLS Unbound требует лишь список серверов в той же секции forward-zone файла конфигурации.
root@my:~ # cat /usr/local/etc/unbound/unbound.conf
server:
...
forward-zone:
name: "."
# Quad9
forward-addr: 9.9.9.9@853
forward-addr: 2620:fe::fe@853
...
forward-ssl-upstream: yes
...
Не составлят труда и настройка Unbound в качестве сервера обслуживающего DNS-over-TLS запросы. Для этого можно использовать уже имеющиеся сертификаты TLS, например от Let's Encrypt.
root@my:~ # cat /usr/local/etc/unbound/unbound.conf
server:
...
interface: 127.0.0.1
interface: ::1
interface: 0.0.0.0@853
interface: ::0@853
tls-service-key: "/usr/local/etc/letsencrypt/live/my.domain/privkey.pem"
tls-service-pem: "/usr/local/etc/letsencrypt/live/my.domain/cert.pem"
tls-port: 853
...
В данном случае Unbound по умолчанию обслуживает стандартные нешифрованные DNS запросы на локальном интерфейсе 127.0.0.1 и ::1, однако в данном случае понадобилось это указать в конфигурации в явном виде. Теперь также он доступен и для внешних запросов доступен исключительно по протоколу DNS-over-TLS на порту 853.
root@my:~ # sockstat -46 | grep unbound
unbound unbound 18533 3 udp4 127.0.0.1:53 *:*
unbound unbound 18533 4 tcp4 127.0.0.1:53 *:*
unbound unbound 18533 5 udp6 ::1:53 *:*
unbound unbound 18533 6 tcp6 ::1:53 *:*
unbound unbound 18533 7 udp4 *:853 *:*
unbound unbound 18533 8 tcp4 *:853 *:*
unbound unbound 18533 9 udp6 *:853 *:*
unbound unbound 18533 10 tcp6 *:853 *:*
Статья была полезной? Тогда прошу не стесняться и поддерживать деньгами через PayPal или Яндекс.Деньги.