Компания Cloudflare представила публичные ДНС на адресах:
- 1.1.1.1
- 1.0.0.1
- 2606:4700:4700::1111
- 2606:4700:4700::1001
Утверждается, что используется политика "Privacy first", так что пользователи могут быть спокойны за содержание своих запросов.
Сервис интересен тем, что кроме обычного DNS предоставляет возможность использовать технологий DNS-over-TLS и DNS-over-HTTPS, что здорово помешает провайдерам по пути запросов подслушивать ваши запросы — и собирать статистику, следить, управлять рекламой. Cloudflare утверждает, что дата анонса (1 апреля 2018, или 04/01 в американской нотации) была выбрана не случайно: в какой еще день года представить "четыре единицы"?
Поскольку аудитория Хабра технически подкована, традиционный раздел "зачем нужен DNS?" я помещу под конец поста, а здесь изложу более практически полезные вещи:
Как использовать новый сервис?
Самое простое — в своем DNS-клиенте (или в качестве upstream в настройках используемого вами локального DNS-сервера) указываем приведенные выше адреса DNS-cерверов. Имеет ли смысл заменить привычные значения гугловских DNS (8.8.8.8 и т.д.), либо чуть менее распространенных яндексовских публичных серверов DNS (77.88.8.8 и иже с ними) на сервера от Cloudflare — решат вам, но за новичка говорит график скорости ответов, согласно которому Cloudflare работает быстрее всех конкурентов (уточню: замеры сделаны стронним сервисом, и скорость до конкретного клиента, конечно, может отличаться).
Гораздо интереснее работа с новыми режимами, в которых запрос улетает на сервер по шифрованному соединению (собственно, ответ возвращается по нему же), упомянутыми DNS-over-TLS и DNS-over-HTTPS. К сожалению, "из коробки" они не поддерживаются (авторы верят, что это "пока"), но организовать в своем ПО (либо даже на своей железке) их работу несложно:
DNS over HTTPs (DoH)
Как и следует из названия, общение идет поверх HTTPS-канала, что предполагает
- наличие точки приземления (endpoint) — он находится по адресу https://cloudflare-dns.com/dns-query, и
- клиента, который умеет отправлять запросы, и получать ответы.
Запросы могут быть либо в формате DNS Wireformat, определенном в RFC1035 (отправляться HTTP-методами POST и GET), либо в формате JSON (используется HTTP-метод GET). Лично для меня идея делать DNS-запросы через HTTP-запросы показалась неожиданной, однако рациональное зерно в ней есть: такой запрос пройдет многие системы фильтрации трафика, парсить ответы достаточно просто, а формировать запросы — ещё проще. За безопасность ответчают привычные библиотеки и протоколы.
Примеры запросов, прямо из документации:
GET-запрос в формате DNS Wireformat
$ curl -v "https://cloudflare-dns.com/dns-query?ct=application/dns-udpwireformat&dns=q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB" | hexdump
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x7f968700a400)
GET /dns-query?ct=application/dns-udpwireformat&dns=q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB HTTP/2
Host: cloudflare-dns.com
User-Agent: curl/7.54.0
Accept: */*
* Connection state changed (MAX_CONCURRENT_STREAMS updated)!
HTTP/2 200
date: Fri, 23 Mar 2018 05:14:02 GMT
content-type: application/dns-udpwireformat
content-length: 49
cache-control: max-age=0
set-cookie: __cfduid=dd1fb65f0185fadf50bbb6cd14ecbc5b01521782042; expires=Sat, 23-Mar-19 05:14:02 GMT; path=/; domain=.cloudflare.com; HttpOnly
server: cloudflare-nginx
cf-ray: 3ffe69838a418c4c-SFO-DOG
{ [49 bytes data]
100 49 100 49 0 0 493 0 --:--:-- --:--:-- --:--:-- 494
* Connection #0 to host cloudflare-dns.com left intact
0000000 ab cd 81 80 00 01 00 01 00 00 00 00 03 77 77 77
0000010 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 01 00
0000020 01 c0 0c 00 01 00 01 00 00 0a 8b 00 04 5d b8 d8
0000030 22
0000031
POST-запрос в формате DNS Wireformat
$ echo -n 'q80BAAABAAAAAAAAA3d3dwdleGFtcGxlA2NvbQAAAQAB' | base64 -D | curl -H 'Content-Type: application/dns-udpwireformat' --data-binary @- https://cloudflare-dns.com/dns-query -o - | hexdump
{ [49 bytes data]
100 49 100 49 0 0 493 0 --:--:-- --:--:-- --:--:-- 494
* Connection #0 to host cloudflare-dns.com left intact
0000000 ab cd 81 80 00 01 00 01 00 00 00 00 03 77 77 77
0000010 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 01 00
0000020 01 c0 0c 00 01 00 01 00 00 0a 8b 00 04 5d b8 d8
0000030 22
0000031
То же, но с использованием JSON
$ curl 'https://cloudflare-dns.com/dns-query?ct=application/dns-json&name=example.com&type=AAAA'
{
"Status": 0,
"TC": false,
"RD": true,
"RA": true,
"AD": true,
"CD": false,
"Question": [
{
"name": "example.com.",
"type": 1
}
],
"Answer": [
{
"name": "example.com.",
"type": 1,
"TTL": 1069,
"data": "93.184.216.34"
}
]
}
Очевидно, что редкий (если вообще хоть один) домашний роутер умеет так работать с DNS, но это не означает, что поддержка не появится завтра — причем, что интересно, здесь мы вполне можем реализовать работу с DNS в своем приложении (как уже собирается сделать Mozilla, как раз на серверах Cloudflare).
DNS over TLS
По умолчанию, DNS запросы передаются без шифрованния. DNS over TLS — это способ отправлять их по защищенному соединению. Cloudflare поддерживает DNS over TLS на стандартном порту 853, как предписывается RFC7858. При этом используется сертификат, выписанный для хоста cloudflare-dns.com, поддерживаются TLS 1.2 и TLS 1.3.
Установление связи и работа по протоколу происходит примерно так:
- До установления соединения с DNS клиент сохраняет закодированный в base64 SHA256-хеш TLS-сертификата cloudflare-dns.com’s (называемый SPKI)
- DNS клиент устанавливает TCP соединение с cloudflare-dns.com:853
- DNS клиент инициирует процедуру TLS handshake
- В процессе TLS handshake, хост cloudflare-dns.com предъявляет свой TLS сертификат.
- Как только TLS соединение установлено, DNS клиент может отправлять DNS запросы поверх защищенного канала, что предотвращает подслушивание и подделку запросов и ответов.
- Все DNS запросы, отправляемые через TLS-соединение, должны соответствовать спецификации по отправке DNS поверх TCP.
Пример запроса через DNS over TLS:
$ kdig -d @1.1.1.1 +tls-ca +tls-host=cloudflare-dns.com example.com
;; DEBUG: Querying for owner(example.com.), class(1), type(1), server(1.1.1.1), port(853), protocol(TCP)
;; DEBUG: TLS, imported 170 system certificates
;; DEBUG: TLS, received certificate hierarchy:
;; DEBUG: #1, C=US,ST=CA,L=San Francisco,O=Cloudflare, Inc.,CN=*.cloudflare-dns.com
;; DEBUG: SHA-256 PIN: yioEpqeR4WtDwE9YxNVnCEkTxIjx6EEIwFSQW+lJsbc=
;; DEBUG: #2, C=US,O=DigiCert Inc,CN=DigiCert ECC Secure Server CA
;; DEBUG: SHA-256 PIN: PZXN3lRAy+8tBKk2Ox6F7jIlnzr2Yzmwqc3JnyfXoCw=
;; DEBUG: TLS, skipping certificate PIN check
;; DEBUG: TLS, The certificate is trusted.
;; TLS session (TLS1.2)-(ECDHE-ECDSA-SECP256R1)-(AES-256-GCM)
;; ->>HEADER<<- opcode: QUERY; status: NOERROR; id: 58548
;; Flags: qr rd ra; QUERY: 1; ANSWER: 1; AUTHORITY: 0; ADDITIONAL: 1
;; EDNS PSEUDOSECTION:
;; Version: 0; flags: ; UDP size: 1536 B; ext-rcode: NOERROR
;; PADDING: 408 B
;; QUESTION SECTION:
;; example.com. IN A
;; ANSWER SECTION:
example.com. 2347 IN A 93.184.216.34
;; Received 468 B
;; Time 2018-03-31 15:20:57 PDT
;; From 1.1.1.1@853(TCP) in 12.6 ms
Этот вариант, похоже, лучше подойдет для локальных DNS-серверов, обслуживающих нужды локальной сети либо одного пользователя. Правда, с поддержкой стандарта не очень хорошо, но — будем надеяться!
Два слова пояснений, о чём разговор
Аббревиатура DNS расшифровывается как Domain Name Service (так что говорить "сервис DNS" — несколько избыточно, в аббревиатуре уже есть слово "сервис"), и используется для решения простой задачи — понять, какой IP-адрес у конкретного имени хоста. Каждый раз, когда человек щёлкает по ссылке, либо вводит в адресной строке браузера адрес (скажем, что-то вроде "https://habrahabr.ru/post/346430/"), компьютер человека пытается понять, к какому серверу следует направить запрос на получение содержимого страницы. В случае habrahabr.ru ответ от DNS будет будет содержать указание на IP-адрес веб-сервера: 178.248.237.68, и далее браузер уже попробует связаться с сервером с указанным IP-адресом.
В свою очередь, сервер DNS, получив запрос "какой IP-адрес у хоста с именем habrahabr.ru?", определяет, знает ли он что-либо об указанном хосте. Если нет, он делает запрос к другим серверам DNS в мире, и, шаг за шагом, пробует выяснить ответ на заданный вопрос. В итоге, по нахождению итогового ответа, найденные данные отправляются всё ещё ждучему их клиенту, плюс сохраняются в кеше самого DNS-сервера, что позволит в следующий раз ответить на подобный вопрос гораздо быстрее.
Обычная проблема состоит в том, что, во-первых, данные DNS-запросов передаются в открытом виде (что дает всем, кто имеет доступ к потоку трафика, вычленить DNS-запросы и получаемые ответы, а затем проанализировать их для своих целей; это дает возможность таргетирования рекламы с точностью для клиента DNS, а это совсем немало!). Во-вторых, некоторые интернет-провайдеры (не будем показывать пальцем, но не самые маленькие) имеют тенденцию показа рекламы вместо той или иной запрошенной страницы (что реализуется весьма просто: вместо указанного IP-адреса для запроса по имени хоста habranabr.ru человеку случайным образом возвращается адрес веб-сервера провайдера, где отдается страница, содержащая рекламу). В-третьих, существуют провайдеры интернет-доступа, реализующие механизм выполнения требований о блокировке отдельных сайтов, через подмену правильных DNS-ответов про IP-адресов блокируемых веб-ресурсов на IP-адрес своего сервера, содержащего страницы-заглушки (в результате доступ к таким сайтам заметно усложняется), либо на адрес своего прокси-сервера, осуществляющего фильтрацию.
Здесь, вероятно, нужно поместить картинку с сайта http://1.1.1.1/, служащего для описания подключения к сервису. Авторы, как видно, совершенно уверены в качестве работы своего DNS (впрочем, от Cloudflare трудно ждать другого):
Можно вполне понять компанию Cloudflare, создателя сервиса: они зарабатывают свой хлеб, поддерживая и развивая одну из самых популярных CDN-сетей в мире (среди функций которой — не только раздача контента, но и
Автор: achekalin