Файл hosts живёт в Windows дольше, чем большинство служб современной системы, и при этом остаётся одним из самых недопонятых механизмов разрешения имён. Администраторы открывают его, чтобы подменить адрес домена для отладки, собирающие блоклисты авторы вписывают туда тысячи рекламных доменов, а новички искренне удивляются, почему строка с маской "*.example.com" не работает. Эта статья разбирает устройство hosts, порядок разрешения имён в Windows, практические ловушки формата и те случаи, когда вместо hosts нужен настоящий DNS-сервер с воронкой. Всё написано с позиции практикующего сетевика, который не раз вычищал последствия неправильно составленных hosts и поднимал собственные резолверы там, где таблица имён бессильна.

Устройство hosts и его синтаксис

Файл hosts расположен по адресу C:\Windows\System32\drivers\etc\hosts. Обратите внимание на последнюю часть: у файла нет расширения, и это не опечатка. Проводник Windows по умолчанию скрывает расширения, из-за чего через него легко случайно создать файл hosts.txt, который система будет игнорировать, сколько бы строк туда ни вписали. Правильный файл создаётся программой вроде Блокнота, запущенной от имени администратора, через диалог сохранения с типом "Все файлы" и именем hosts без какого-либо суффикса.

Синтаксис строки до обидного прост: сначала IPv4 или IPv6 адрес, затем один или несколько пробелов либо табуляция, затем одно или несколько имён, отдельных записей. Всё, что идёт после символа решётки, считается комментарием. Классический пример выглядит так: "127.0.0.1 mysite.local". Одна строка может содержать несколько имён для одного адреса, что удобно для псевдонимов. Пустые строки допустимы и игнорируются.

Парсер hosts реализован внутри DNS-клиентской службы Windows и читает файл буквально, дословно, без всякой грамматики шаблонов. Каждая строка это одна точная запись "адрес пробел имя". Никаких регулярных выражений, никакого сопоставления по образцу, никакой интерполяции переменных. Парсер берёт имя после пробела и кладёт его в хеш-таблицу как ключ целиком. Если там звёздочка, то ключ и будет содержать звёздочку как обычный символ.

Почему wildcard в hosts невозможен

Итак, вопрос десятилетия: почему нельзя написать "127.0.0.1 *.example.com" и заблокировать все поддомены разом. Ответ лежит в генеалогии формата. Файл HOSTS.TXT появился ещё в раннем ARPANET, когда вся сеть умещалась в один текстовый файл, который администраторы скачивали по FTP с центрального сервера. Тогда имён было несколько сотен, и каждая запись описывала ровно один хост. Задачи сопоставления шаблонов в принципе не существовало, потому что файл был ручным реестром машин, а не механизмом политики. Когда ARPANET перерос себя и появился DNS, hosts остался как локальный запасной вариант, и его формат заморозили ради совместимости. С тех пор прошло более сорока лет, а грамматика файла не изменилась ни на йоту.

С точки зрения реализации это тоже осмысленный выбор. Хеш-таблица с точными ключами даёт поиск за константное время. Добавьте сюда шаблоны, и каждый запрос придётся прогонять по всем строкам с масками, сравнивая суффиксы и префиксы, а это уже совсем другая сложность и другой источник ошибок. Звёздочка в доменных именах вообще штука непростая даже в настоящем DNS, где wildcard записи описаны стандартом и всё равно порождают гору недоразумений. Разработчики Windows сознательно не тащили эту сложность в примитивный текстовый файл.

Поэтому любой инструмент, обещающий "поддержку wildcard в hosts", на деле либо генерирует сотни конкретных строк вместо одной маски, либо вообще работает не с hosts, а с собственным резолвером.

Приоритет hosts в цепочке разрешения имён

Windows решает, куда отправить пакет, проходя по упорядоченной цепочке источников имён. Первым обычно читается hosts: система смотрит таблицу до любого обращения к сети. Если имя найдено, ответ возвращается немедленно, и никакой DNS-сервер запрос не видит. Именно поэтому hosts ценят разработчики: строка "127.0.0.1 api.example.com" мгновенно перенаправляет браузер на локальный сервер без малейшего трафика наружу.

Дальше идёт кэш DNS-клиентской службы. Результаты прошлых запросов и загруженный при старте hosts складываются в кэш, и его содержимое можно посмотреть командой ipconfig /displaydns. Затем, если совпадения нет, запрос уходит настроенным DNS-серверам, а полный порядок в современной Windows включает ещё мультикаст протоколы LLMNR и mDNS, а также NetBIOS broadcast для старых имен без точек. Практический вывод: hosts выигрывает всегда, но кэш способен отдать устаревший ответ, поэтому после правки файла полезно выполнить ipconfig /flushdns.

Важный нюанс для групповой политики: в доменной среде администраторы порой отключают чтение hosts через политику или ограничивают его размер, рассуждая, что большой файл это и угроза, и источник тормозов. Ведите себя соответственно на корпоративных машинах и проверяйте, действительно ли ваш строка попала в оборот.

Права, кодировка и практические ловушки формата

Каталог C:\Windows\System32\drivers\etc недоступен обычному пользователю на запись. Редактировать hosts нужно от имени администратора: запустите Блокнот или любой редактор с повышением прав, откройте файл, внесите изменения, сохраните. Антивирусы нередко следят за hosts, потому что классический сценарий вредоносной программы это перенаправление банковских доменов, поэтому защита может молча откатить правку. Проверяйте содержимое после сохранения.

Кодировка заслуживает отдельного абзаца. Исторически система читает hosts в системной ANSI кодировке, и UTF-8 с маркером BOM в начале файла способен испортить первую строку так, что она фактически перестаёт работать. Современные версии Windows стали терпимее, но инженеры, которые бились с этой проблемой на терминальных серверах, до сих пор сохраняют hosts в чистом ASCII или ANSI. Правило простое: если файл содержит только латиницу, цифры, пробелы и решётки, проблем не будет никогда.

Из ловушек формата стоит помнить три. Первая это IPv6: машина с отключённым IPv4 или браузер, предпочитающий IPv6, проигнорирует строку "127.0.0.1 example.com", если имя доступно по ::1, и наоборот, блокирующие списки часто дублируют записи для обоих стеков. Вторая это punycode: международные домены в hosts должны быть вписаны в ASCII представлении вида xn--..., иначе совпадения не произойдёт. Третья это длина имени и общий регистр парсера: слишком длинные строки и управляющие символы из случайного копирования превращают запись в мусор, который сложно заметить глазами.

Блокирующие списки и почему 0.0.0.0 лучше 127.0.0.1

Идея ставить нежелательные домены на петлю появилась сразу, как только рекламные сети обросли тысячами хостов. Логика проста: браузер просит banner.adnetwork.example, hosts отвечает 127.0.0.1, соединение идёт на локальную машину и умирает. Однако у этого приёма есть неочевидная цена. Если на локальной машине кто-то слушает восьмидесятый порт, запрос реально дойдёт до него, а если никто не слушает, стек начнёт честно ждать отказа соединения, и страница в браузере подвиснет на доли секунды, а при плохой реализации на секунды. Умножьте на десятки рекламных запросов на страницу и получите ощутимую задержку.

Адрес 0.0.0.0 ведёт себя выгоднее. Это немаршрутизируемый "этот хост" в смысле назначения; попытка соединения к нему отбрасывается сетевым стеком мгновенно, без прогулки до локального порта и ожидания таймаута. Поэтому зрелые блоклисты для hosts в большинстве своём используют именно 0.0.0.0. Разница измеряется миллисекундами на запись, но на странице с сотней заблокированных обращений эффект заметен невооружённым глазом.

У подхода есть и принципиальное ограничение: hosts резалит целые домены целиком и не умеет резать по URL пути. Рекламный скрипт с того же домена, что и контент, не убрать таблицей имён. Для этого существуют браузерные расширения и фильтры на уровне сетевых фильтров, о которых ниже.

Масштаб блоклистов и пределы производительности

Наборы вроде известных единых списков блокировки весят десятки тысяч строк, и вот тут hosts показывает свою ахиллесову пяту. Службе DNS-клиента нужно при старте прочитать файл, распарсить каждую строку и построить индекс. На машине с двадцатью тысячами записей старт службы заметно удлиняется, потребление памяти растёт, а у части версий Windows есть задокументированное поведение: при слишком большом hosts служба DNS Client начинает игнорировать файл частично или полностью, вплоть до рекомендации Microsoft отключать чтение больших hosts в реестре и политиках.

Владельцы домашних машин порой обходят это отключением службы DNS Client вовсе, что ломает кэширование, префетчинг и часть сетевых сценариев. Более разумная стратегия это ограничить список несколькими тысячами реально встречающихся доменов, а глобальную фильтрацию отдать DNS-уровню. Двадцать тысяч строк это ещё терпимо, сто тысяч почти наверняка превратят разрешение имён в узкое место.

Отсюда же вывод про производительность поиска: когда индекс построен, конкретный запрос бьёт по хешу и летит, поэтому обычный рабочий день от большого hosts не страдает. Страдают старт службы, перезагрузки и перечитывание файла, а ещё редакторы, которые падают при открытии многомегабайтного текста.

DNS sinkhole как взрослая альтернатива

DNS sinkhole, она же воронка, это резолвер, который для заданных доменов отвечает не реальным адресом, а адресом заглушки, обычно 0.0.0.0 или адресом локальной страницы-пояснения. Ключевое отличие от hosts в том, что это полноценный DNS-сервер, а значит, он понимает доменную грамматику. Правило "example.com и все его поддомены" выражается одной записью зоны, потому что DNS умеет wildcard и делегирование. Тысячу поддоменов рекламной сети воронка накрывает одной строкой конфигурации, тогда как hosts потребовал бы тысячу конкретных имён.

В корпоративных сетях воронки поднимают на внутренних резолверах, чтобы резать фишинговые и вредоносные домены централизованно, а не править hosts на каждой машине. В домашней сети популярны маленькие дешёвые устройства с резолвером внутри, работающие по тем же принципам: устройство получает запрос, сверяет домен со списками и либо форвардит запрос вышестоящему провайдеру, либо отвечает из воронки. Классические решения этого семейства строят на связке dnsmasq и списков доменов, обновляемых по расписанию.

У sinkhole есть побочный бонус: вся заблокированная активность падает в логи. Администратор видит, какие машины чаще всего стучались на отфильтрованные домены, и строит отчёты без установки агентов. Прозрачная статистика одна из главных причин, почему взрослые подразделения безопасности живут на воронках, а не на hosts.

Практический сценарий собственного sinkhole на RPZ или unbound

Быстрый путь домой выглядит так. Берите машину или контейнер с BIND либо unbound и делайте из неё рекурсивный резолвер для локальной сети. В BIND механизм воронки называется Response Policy Zones. RPZ файл описывает правила вида "рекламный-домен.example CNAME ." где точка означает NXDOMAIN, либо с явным адресом-заглушкой. RPZ хорош тем, что зоны политики можно подписывать у внешних поставщиков и получать обновления передачей зоны, минимум ручной работы.

В unbound похожий эффект достигается директивой local-zone. Запись вида local-zone: "ads.example" always_nxdomain режет домен со всеми поддоменами, а redirect позволяет подставить конкретный адрес заглушки. Списки доменов из готовых сборок конвертируются в этот формат одним коротким скриптом, целиком влезая в память маленькой виртуалки. После настройки резолвера машины сети получают его адрес через DHCP, и весь трафик имён проходит фильтрацию централизованно.

Напомню правила эксплуатации: держите резолвер в закрытом VLAN, включайте логирование запросов выборочно, чтобы не утонуть в дисковом вводе-выводе, и периодически пересобирайте списки, потому что рекламные домены умирают и рождаются быстрее, чем обновляется операционная система.

Альтернативы hosts за пределами DNS

Когда задача выходит за рамки "быстро подменить домен" и "отрезать рекламу", на сцену выходят другие инструменты. Групповые политики браузеров умеют блокировать списки URL, навязывать расширения и управлять разрешениями сайтов централизованно, что удобно в управляемом парке машин. Фильтрующие посредники, как локальные, так и сетевые, работают на уровне HTTP и способны резать по URL path, по типу контента и по сигнатурам, чего DNS-уровень не достигнет никогда. Сетевые фильтры с инспекцией SNI закрывают и HTTPS-трафик по имени сервера.

Выбор простой: hosts для точечной отладки и маленьких блоклистов, sinkhole для централизованной фильтрации доменов, фильтры-посредники и политики для гранулярного контроля содержимого. Натягивать hosts на сценарии сетевой фильтрации - это путь к боли.

Отладка и классические ловушки проверки

  1. После правки hosts выполните ipconfig /flushdns, чтобы сбросить кэш клиентской службы и гарантированно перечитать таблицу.
  2. Проверяйте результат командой ping имя или Test-NetConnection имя -Port 443: эти команды идут через клиентский резолвер Windows и учитывают hosts.
  3. Помните про nslookup: этот инструмент обращается к DNS-серверу напрямую и намеренно игнорирует hosts, поэтому "nslookup показывает настоящий адрес, а браузер ходит по hosts" это нормальное поведение, а не поломка.
  4. Смотрите ipconfig /displaydns, чтобы убедиться, что запись из hosts попала в кэш.
  5. Если правка не срабатывает, проверяйте имя файла на предмет скрытого .txt, права администратора при сохранении, кодировку без BOM, а также IPv6-вариант имени.

Из этих пунктов чаще всего подводит именно nslookup. Классическая сцена в любой поддержке: пользователь вписал домен в hosts, набрал nslookup, увидел реальный адрес провайдерского DNS и решил, что правка не работает. На деле резолвер приложений прекрасно видит запись, и ping с браузером это докажут. Запоминайте раз и навсегда: hosts проверяют через Test-NetConnection или ping, а nslookup используют только для проверки настоящего DNS.

Итог простой. Файл hosts это вечный карманный инструмент: статическая таблица имя-адрес с дословным парсингом, максимальным приоритетом над DNS и минимумом возможностей за пределами точного совпадения. Для отладки и маленьких списков он идеален. Для масштаба пользуйтесь воронкой на BIND или unbound, а гранулярный контроль отдавайте фильтрам-посредникам и политикам браузеров. Зная порядок разрешения имён, ловушки формата и правильные способы проверки, администратор без путаницы выбирает инструмент под задачу и не ждёт от hosts того, чего тот не умеет с рождения.