← Назад к проектам

Провайдер подменяет DNS, и полный туннель это не лечит

В части клубов провайдер подменял ответы DNS: домены целей резолвились в адрес заглушки. Полное туннелирование проблему не снимало — локальные сети всегда вычитаются из туннеля, иначе ломается клубный софт, а клубный резолвер живёт как раз в локальной сети.

Сделал DNS-прокси на петле: слушатель на UDP и TCP, каждый запрос своей задачей, перенос запроса на DoH байт в байт по RFC 8484 — прокси переносит, а не разбирает, поэтому в нём нет ни разбора флагов, ни сжатия имён, ни TTL, ни целого класса ошибок вместе с ними. Если DoH не ответил, тот же пакет уходит клубному резолверу: не лучше, чем было, но и не хуже.

Имена уводятся на прокси правилами NRPT. Свои правила помечаются и снимаются по метке, а не по совпадению со списком — состав целей к моменту уборки уже другой, а в клубе может стоять доменная политика, которую сносить нельзя.

Фактура

  • TCP не роскошь: при усечённом ответе резолвер Windows повторяет запрос по нему, и отсутствие слушателя выглядело бы как «имя не резолвится изредка и невоспроизводимо».
  • Из списка клубных резолверов выбрасывается вся сеть 127/8: после постановки правил там может оказаться сам прокси, и он спросил бы себя по кругу до таймаута.
  • Слушателем владеет порт правил: правило, пережившее прокси, кладёт насмерть ровно те домены, которые чинили. Отсюда правило «оставшееся правило опаснее оставшегося маршрута» — маршрут рвёт интернет целиком и это видно сразу, а правило выглядит как «VPN не помог».
  • Уборка правил идёт на трёх путях: старт, штатный выход и сторож — синхронно, без исполнителя tokio, потому что сторож это отдельный процесс.
  • Нормализация имён: варианты имени из каталога с ведущей и с завершающей точкой приводятся к одной форме, иначе получаются два правила, ни одно из которых не сработает.
  • Живой тест ставит правило на имя в зоне .invalid (RFC 2606) — если уборка сорвётся, такое правило не уведёт ни один настоящий запрос.
  • Попутно найдено: русская Windows пишет ошибки в кодировке OEM, а поток читался как UTF-8 — текст отказа, ради которого его и пробрасывали админу, приезжал кракозябрами.