Что случилось?
В России что-то происходит с DNS (системой получения информации о доменах) — и происходит давно.
Например, 8 сентября 2021 года Роскомнадзор заблокировал у нескольких крупных операторов, с помощью ТСПУ (техсредства «противодействия угрозам»), на час с 21:00 до 22:00 публичные DNS 1.1.1.1 и 8.8.8.8, это задокументировали независимые специалисты. Через несколько дней «Ростелеком» разослал внутреннее предложение закрепить эту блокировку на постоянной основе. В октябре 2024 года Cloudflare включил по умолчанию расширение TLS ECH, скрывающее домен назначения (SNI) при установке соединения; с 5 ноября 2024 года зафиксирована блокировка TLS-сессий с этой сигнатурой не через TCP RST, а через тихий дроп пакета после ее обнаружения, что вынуждает браузер откатываться на обычное, открытое соединение.
Мы решили самостоятельно проверить, как работают разные DNS в России на разных ресурсах и какую роль в их ограничении играет ТСПУ.
Что мы решили измерить?
Узлы фильтрации
Для изоляции узлов фильтрации (ТСПУ) измерительная инфраструктура развернута на пяти независимых точках:
- Эталонная нода (Испания, Residential ШПД).
- Эталонная нода (Германия, магистральный уровень Tier-1).
- Измерительные ноды внутри РФ (Москва и Санкт-Петербург, уровень дата-центров Tier-2/Tier-3).
- Измерительная нода внутри РФ (Санкт-Петербург, уровень конечного ШПД-пользователя).
Домены
Сделали опрос резолверов по нескольким группам доменов.:
- Заблокированные мессенджеры: whatsapp.com, telegram.org, signal.org.
- Заблокированные СМИ: meduza.io, bbc.com, novayagazeta.eu.
- Технические ресурсы: protonvpn.com, te-st.org, github.com.
- Эталонные иностранные (не заблокированые): microsoft.com, nvidia.com.
- Деградирующие: youtube.com, apple.com.
- Локальные российские (работающие): ya.ru, vk.ru.
- Инфраструктура CDN: cdnjs.cloudflare.com (Cloudflare), fastly.net, ajax.googleapis.com (Google), cdn.jsdelivr.net . (Цель: выявление блокировок подсетей хостинг-провайдеров на уровнях L3/L4 в противовес точечной L7-фильтрации)
DNS-серверы (резолверы)
- BigTech & Публичные резолверы: Cloudflare, Google, Quad9, Cisco Umbrella, OpenDNS.
- Специализированные и приватные DoH/DoT: NextDNS, Control D, AdGuard DNS, Mullvad DNS, LibreDNS.
- Российские: «Яндекс DNS», НСДИ (Национальная система доменных имен), не как тестируемые «внешние» DNS, а как ориентир, что отвечает DNS, заведомо работающий под российской юрисдикцией
Чем мы измеряли
- kdig — для запросов по обычному DNS, DoT, DoH и DoQ; ъ
- dig — для ручного управления полем EDNS Client Subnet при проверке гипотезы про географическую маршрутизацию;
- curl — чтобы проверить напрямую, что отдает конкретный IP-адрес по HTTPS с заданным SNI, независимо от резолвера и его ответа.
Что мы хотели найти
- L3/L4: IP Blackholing подсетей известных резолверов, веерная блокировка порта 853, отправка поддельных пакетов TCP RST для сброса соединений на этапе установки сессии. (Порт 853 общий для DoT и DoQ, сравнение поведения этих двух протоколов на одном порту позволяет определить, режется ли порт целиком, либо фильтр различает конкретный протокол/сигнатуру внутри.)
- Active Intercept: Подмена A/AAAA-ответов серверами ТСПУ (DNS Hijacking). Для верификации точки перехвата и доказательства подмены именно на ТСПУ применяется трассировка сетевых маршрутов.
«Испорченный» DNS-ответ в этом исследовании может возникать по одной из двух разных причин, которые нельзя смешивать в одной таблице:
- In-path перехват (ТСПУ). Модификация/сброс трафика на маршруте между клиентом и резолвером. Наблюдается только если запрос физически проходит через сеть российского оператора. Признак: результат меняется в зависимости от точки наблюдения при одном и том же резолвере (РФ-нода видит подмену/сброс, зарубежная нода к тому же резолверу — честный ответ).
- Resolver-side compliance. Оператор резолвера сам встраивает blocklist в логику ответа на своих серверах. Признак: результат идентичен независимо от геолокации клиента, потому что фильтруется не маршрут, а сама точка ответа.
Различать два эти случая важно, так как для каждого нужны разные меры противодействия: VPN/обфускация трафика решает первое, но бессильна против второго — там нужна смена DNS.
Что мы нашли
Сразу скажем: классической блокировки, сброса соединений или недоступности целых подсетей, на наших тестовых узлах мы не нашли. Зато мы обнаружили необъясненную подмену DNS-ответа у части резолверов для части доменов. Мы делали разбор этих адресов.
Тогда мы назвали эти адреса «заглушками РКН». Но при более подробной проверке оказалось, что это не совсем точное описание. По этим адресам отдается настоящий, рабочий контент Cloudflare, а не пустой отбойник, мы проверили это напрямую curl’ом с явным SNI на signal.org через адрес 8.47.69.6, причём не только с VPS, но и через обычный домашний интернет в России.
Как мы отличали «шум» от реальных аномалий
Первый проход по логам показал: для части доменов ответ на российском узле отличался от ответа на всех проверенных зарубежных узлах. Прежде чем что-либо интерпретировать, эту выборку нужно было очистить от шума, иначе метод «повтор IP там, где его не должно быть» дает ложные срабатывания на любом anycast/CDN-сервисе
Важное методологическое наблюдение: стабильность, высокая повторяемость, сама по себе еще не признак вмешательства. Например, whatsapp.com и youtube.com дают воспроизводимые, узло-зависимые ответы со 100%-й повторяемостью и это ровно то, что можно объяснить штатной географической балансировкой нагрузки у самих провайдеров, а не подменой. Отличать «аномалию» от «шума» позволяет только сопоставление с контрольной группой: если то же самое происходит и с nvidia.com/microsoft.com, которые пока не блокируют и не собираются блокировать, дело может быть не в цензуре.
После вычитания «шума »в данных остается одно заметное семейство ответов: 8.47.69.N / 8.6.112.N, где N ∈ {0, 6, 8}. 8.6.112.0/24 по данным ARIN зарегистрирован за Cloudflare, Inc. (origin AS13335). При этом сеть не входит в публикуемый Cloudflare список IP Ranges, который предназначен для настройки allowlist на origin-серверах и не покрывает весь внутренний/продуктовый диапазон компании. Иными словами, обнаружение адреса вне публичного списка не означает, что адрес принадлежит кому-то другому.
Как мы нашли признаки подмены
Для автоматического выявления подмены использовался простой принцип: если один и тот же IP-ответ повторяется у нескольких доменов, которые физически не связаны общей инфраструктурой (например, signal.org — собственные сервера Signal, meduza.io — за Cloudflare, te-st.org — за Cloudflare), это статистически аномально и указывает на общий источник подмены, а не на совпадение.
Метод не использует внешние базы данных о владельцах IP и не делает предположений о «правильных» адресах заранее — он просто ищет повторы там, где их не должно быть, что позволяет находить аномалии без необходимости заранее знать, что именно искать. Легитимность или нелегитимность каждого найденного совпадения мы проверяли дополнительно вручную. Домены за одним CDN-провайдером могут законно делить общий IP, такие случаи мы засчитывали как совпадение, а не подмену. Отличить одно от другого помогло то, какие конкретно домены оказались в одной группе.
Как мы исключили MITM
Проверка TLS-сертификата показала, что соединение к 8.8.8.8/1.1.1.1 устанавливается с подлинной инфраструктурой Google/Cloudflare (сертификаты действительны, выпущены легитимными CA Google Trust Services и SSL.com соответственно), что исключает классический MITM-перехват с подменой сертификата на пути к самому резолверу. Трассировка подтверждает, что трафик из российских узлов действительно попадает в собственную сеть этих провайдеров (AS15169 для Google), а не перенаправляется на посторонний адрес.
Отсюда следует вывод: аномальный ответ по адресам 8.47.69.x/8.6.112.x не является результатом перехвата трафика на маршруте между клиентом и DNS Google/Cloudflare, соединение до самого резолвера подлинное. Если подмена и происходит, то она встроена в логику ответа на стороне резолвера (см. классификацию 2.4), либо является легитимным поведением инфраструктуры, которое имитирует подмену внешне.
Почему ответ похож на настоящий Cloudflare
Схема адресации Cloudflare для доменов под ее защитой, две A-записи в двух соседних /24 с одинаковым последним октетом:
signal.org 104.18.10.47 , 104.18.11.47 → октет 47
meduza.io 104.18.0.79 , 104.18.1.79 → октет 79
cdnjs.cloudflare.com 104.17.24.14 , 104.17.25.14 → октет 14
аномалия (класс B/C) 8.47.69.0 , 8.6.112.0 → октет 0
аномалия (класс A) 8.47.69.6 , 8.6.112.6 → октет 6
аномалия (AdGuard) 8.47.69.8 , 8.6.112.8 → октет 8
Аномальный ответ во всех трех вариантах воспроизводит внутреннее соглашение Cloudflare (парные /24 с общим последним октетом), а не выглядит как произвольная подстановка IP, типичная для инжектора на пути (ТСПУ в таких случаях обычно отдает один фиксированный IP-заглушку без такой структуры). Это аргумент в пользу происхождения ответа от инфраструктуры Cloudflare, а не от стороннего перехватчика, но это не окончательное доказательство.
Три разных сценария, которые мы нашли
Класс A. Дифференциальный сигнал, только заблокированные домены, вне зависимости от протокола шифрования
| резолвер | узлы | протоколы | ответ | заблокированных | контрольных задето |
| RU-msk, RU-spb, EU-vpn-SPB | udp_53, dot_853, doh_443 | 8.47.69.6, 8.6.112.6 | 4 | 0 | |
| AdGuard | RU-spb | udp_53, dot_853, doq_853, doh_443 | 8.47.69.8, 8.6.112.8 | 4 | 0 |
Повторяемость внутри класса A от 53.3% до 100%, у Google на RU-spb/doh_443 — 100%. Ключевая деталь: у Google этот ответ появляется на RU-Msk, RU-SPb и EU-vpn-SPb (VPN-выход через домашний ШПД в Санкт-Петербурге) и не появляется ни на одном из узлов без РФ-маршрута, то есть эффект зависит именно от маршрута, а не от DNS как такового. При этом cdnjs.cloudflare.com, включенный в ту же матрицу тестирования, ответ не меняет, задет только заблокированный набор. Это единственный класс, где дифференциальный тест (реакция только на заблокированные домены, при чистом контроле) пройден полностью.
Данные по DoT и DoH здесь важны отдельно: ответ 8.47.69.6 приходит и по каналам, где контент запроса зашифрован (DoT/DoH). Внутри TLS-сессии ТСПУ не может подменить DNS-ответ, не разрушив сессию (это привело бы к ошибке валидации на клиенте, а не к тихой подстановке IP), значит этот конкретный ответ сформирован на стороне, которая владеет приватным ключом сессии, то есть самим резолвером Google (или тем, кто отвечает ему как источник ответа для самого резолвера). Это сужает круг возможных причин появления аномалий класса A до действий Google/Cloudflare, реагирующей на маршрут запроса. Но зачем по такой логике исключать cdnjs.cloudflare.com — открытый вопрос.
Класс B. Resolver-side, ответ не зависит от узла-наблюдателя, но задевает контроль
«Яндекс» и НСДИ отдают этот ответ 8.47.69.0, 8.6.112.0 со всех измерительных узлов. Затронуты 4 заблокированных домена и cdnjs.cloudflare.com, который не входит в блокировочные списки. Повторяемость от 53.3% до 100% (максимум у NSDI/FI-VPS — 100%).
Отсутствие зависимости от маршрута здесь ожидаемо и объяснимо инфраструктурно: «Яндекс» и НСДИ всегда обращаются к серверам из России, независимо от того, откуда вы сами их спрашиваете, поэтому «одинаковый ответ с любого узла» не отличает пока resolver-side цензуру от resolver-side не-цензурной особенности (например, ECS/anycast-роутинга самого вышестоящего сервера). Единственное, что не укладывается в нейтральную версию — участие cdnjs.cloudflare.com, домена, который не блокируется.
Гипотеза о «списке РКН» не подтверждается. Возможно, речь об инфраструктурной особенности ответа Cloudflare для upstream-запросов из РФ. Важное уточнение: мы пока не проверяли напрямую, ведет ли себя вышестоящий сервер «Яндекса»/НСДИ так же, как Cloudflare.
Класс C. РФ-специфично, зависимость от маршрута, но задевает тот же контроль
Cloudflare (RU-Msk, все протоколы включая DoH/DoT) и NextDNS (RU-Msk + RU-SPb, все 4 протокола) отдают тот же 8.47.69.0, 8.6.112.0 только с РФ-узлов, при этом cdnjs.cloudflare.com снова затронут. Повторяемость у Cloudflare/RU-Msk 100% по всем трем протоколам.
Формально класс C ближе к «признаку in-path перехвата» из методологии (результат меняется в зависимости от точки наблюдения), но структура ответа и участие DoH/DoT делают версию in-path-инжекции маловероятной по той же логике, что и в классе A. ТСПУ не может модифицировать шифрованный ответ незаметно для клиента. Более вероятное объяснение – то, что географическая маршрутизация запроса до вышестоящего сервера (edns-client-subnet или anycast-нода) приводит к тому же результату, что и у «Яндекса» и НСДИ, но проявляется только при РФ-адресе клиента, а не при РФ-адресе резолвера.
Что все это значит
- Класс A (Google, AdGuard). Дифференциальный тест пройден полностью, зависимость от маршрута подтверждена, ответ приходит и по шифрованным транспортам. Наиболее вероятное объяснение — логика на стороне резолвера/источника ответа для самого резолвера, зависит от маршрута запроса, а не in-path инжекция.
- Класс B (Яндекс, НСДИ). Воспроизводит структуру адресации Cloudflare, но затрагивает cdnjs.cloudflare.com, это противоречит версии со списком Роскомнадзора. Проверить, зависит ли ответ этих резолверов от поля ECS так же, как у Cloudflare, мы пока не успели.
- Класс C (Cloudflare, NextDNS). Тот же ответ, но только с российских узлов, причем затрагивает и cdnjs.cloudflare.com. Прямая проверка показала: смена заявленной подсети (российская против немецкой) ответ не меняет, значит, дело не в содержимом ECS, а в конкретном сетевом пути от узла до Cloudflare. У Cloudflare аномалия проявляется только на московском узле. Это отличается от класса A, где аномалия одинаково цепляет оба российских узла, скорее всего, у Google и Cloudflare делают это по-разному, и одно с другим не связано.
Что мы еще не изучили
- Покрытие протоколов неравномерно. НСДИ не поддерживает шифрованные транспорты (NOT_SUPPORTED для DoH/DoT/DoQ); сравнения по НСДИ валидны только для udp_53. У Яндекс DoH возвращает 100% таймаутов, DoQ также не работает, сравнения по Яндекс корректны для udp_53 и dot_853, но не для DoH/DoQ.
- Мы лишь частично понимаем, почему подмена происходит именно для этих доменов. Для Cloudflare (класс C) причину нашли в подразделе 3.7. Показывают ли Google, AdGuard, «Яндекс» и НСДИ такую же нечувствительность к содержимому ECS не проверяли, их избирательность непонятна.
- cdnjs.cloudflare.com остается необъясненным расхождением между классами. Если бы за этим стояла одна общая причина, участие контрольного домена должно быть либо постоянным, либо отсутствовать везде, вместо этого оно зависит от DNS. Это единственная находка, которая не укладывается ни в версию «чистая цензура», ни в версию «чистая инфраструктурная особенность». Ее объяснение — вопрос для дальнейшего исследования.
Что в итоге? Есть ли блокировка?
Мы пока не знаем и продолжаем копать дальше. Три класса найденной аномалии объясняются по-разному, и общего объяснения для всех трех не нашлось: у Google эффект одинаково цепляет оба российских узла независимо от протокола шифрования; у Cloudflare как резолвера — только один из двух российских узлов, и смена заявленной подсети клиента ответ не меняет.
Содержимое по подставленному адресу оказалось настоящим и полным. При этом обычная загрузка той же страницы в браузере через то же домашнее подключение (без ручного указания IP) прошла медленно, с потерей части картинок и верстки, то есть что-то все же мешает работе сайта, но не полностью и не для всех запросов.
Похоже, часть запросов при обычной загрузке страницы не проходит, хотя основной адрес и основной документ загружаются полностью. Есть ли в этом признаки блокировки, мы не можем утверждать стопроцентно. Ранее мы уже писали о похожем поведении, блокировке уже настоящего адреса на уровне SNI (Разбор #20), увиденная нами аномалия подтверждает наш разбор.
За рамками этого исследования остались децентрализованные системы (OpenNIC, Namecoin, Emercoin, GNU Name System), альтернативные протоколы (DNSCrypt, ODoH) и малоизвестные региональные резолверы, они требуют другого инструментария и отдельной проверки.
Что можно сделать с этими аномалиями? Технические рекомендации
Администраторам сайтов и разработчикам
- Self-Hosted DoH через Reverse Proxy. Маршрутизация запросов через собственную VPS. Трафик проксируется через веб-сервер (Nginx или Caddy) на порту 443 с легитимным TLS-сертификатом к локально запущенному dnscrypt-proxy. Для сигнатурного анализа ТСПУ такое соединение неотличимо от обычного веб-серфинга.
- Альтернативные протоколы (ODoH). Развертывание протокола Oblivious DoH. Эта технология использует промежуточный прокси-сервер, гарантируя криптографическое разделение: прокси знает IP-адрес клиента, но не видит сам DNS-запрос, а конечный резолвер видит запрос, но не знает IP-адрес клиента.
- Инкапсуляция трафика (XTLS/Обфускация). Упаковка системных DNS-запросов (порт 53) в туннели с маскировкой под TLS 1.3 хэндшейк (протоколы VLESS+Reality). Это скрывает от DPI не только конечный домен, но и сам отпечаток (ALPN) протокола DNS, делая L7-фильтрацию невозможной.
Пользователям
- Локальные резолверы и раздельное туннелирование. Для обхода гео-блокировок российских ресурсов (банков, госуслуг) и одновременного обхода цензуры рекомендуется использование dnsmasq на домашних роутерах (OpenWrt, Keenetic). Запросы к зоне .ru принудительно направляются на DNS провайдера, а все остальные — в зашифрованный локальный туннель (DoH/DNSCrypt).
- Отказ от открытого DNS. Базовые запросы через порт 53 перехватываются ТСПУ для подмены ответов (Слой 3). Настройка DoH (DNS over HTTPS) в современных браузерах или на уровне ОС — минимальный базовый шаг. Это не скрывает SNI, но исключает выдачу IP-заглушек.
Список источников и полезных материалов:
- RFC 9230 (Oblivious DNS over HTTPS): Технический стандарт IETF, описывающий архитектуру ODoH — datatracker.ietf.org/doc/rfc9230/
- DNSCrypt & dnscrypt-proxy: Официальный репозиторий проекта с инструкциями по развертыванию защищенного клиента и сервера — github.com/DNSCrypt/dnscrypt-proxy
- dnsmasq: Документация легковесного кэширующего DNS-сервера для настройки раздельного туннелирования на роутерах — thekelleys.org.uk/dnsmasq/doc.html
- Nginx Reverse Proxy: Официальная документация модуля ngx_http_proxy_module для проксирования DoH-трафика — nginx.org/en/docs/http/ngx_http_proxy_module.html