Punch2027: Radda urges Katsina residents to repay Tinubu with votesInquirerBFAR gears up for sardine fishing ban in northeastern MindanaoThe Jerusalem Post‘Not particularly prudent’: Trump’s Israel aid cutoff draws criticism from RepublicansZDF heuteAktuelle Pressemitteilungen des ZDFWirtualna PolskaUkraina osiąga swój cel. Problemy paliwowe paraliżują rosyjski rynekIl Fatto QuotidianoFrattura il cranio e accoltella la compagna dopo una lite: arrestato 35enne per tentato omicidio20 Minuten«Harry Potter» sagte Nein – jetzt startet Reggie (14) durchSportstarLa Liga 2026-27: Garcia, Christensen return for Barcelona’s Atletico Madrid clash, confirms FlickComplete SportsAFCON 2027Q: Chelle Names 25-Man Super Eagles Squad For Tanzania Double-HeaderANSATaglia degli hacker sul dark web su Tajani e Lo Voi. Cyberattacco alla Galleria del BrenneroANSA SportSerie A: Torino-Lecce in campo sabato alle 15 DIRETTAESPN DeportesAtlético Madrid vs Barcelona: ¿Cómo están las apuestas?
The Daily Newsstand · Free, Always
Saturday, November 7, 2026

dig находит адрес, а приложение — нет: как одна строка ломает разрешение имён в Linux

Translate

Платёжный шлюз отвечает по IP. DNS возвращает правильный адрес. Но приложение пишет Could not resolve host, и платежи не проходят. Если после успешного dig вычеркнуть разрешение имён из списка подозреваемых, расследование уйдёт в сторону.

В моём тренажёре Prod is Down есть кейс «Платёжный шлюз недоступен». Один из его вариантов построен именно на таком расхождении. Ниже - отдельный воспроизводимый эксперимент с настоящими dig, getent, curl и glibc. Это учебный стенд в изолированном контейнере.

Две команды, которые будто бы спорят

На стенде подняты локальный DNS и HTTP-шлюз. Имя gateway.pay.internal должно вести на 127.0.0.20. Шлюз слушает порт 8443, здесь на нём намеренно обычный HTTP, чтобы TLS не добавлял ещё одну переменную.

Сначала спрашиваем DNS:

dig +short gateway.pay.internal A

Ответ:

127.0.0.20

Затем обращаемся к шлюзу по этому же имени:

curl --noproxy '*' -4 -sS --max-time 2 http://gateway.pay.internal:8443/health

Получаем:

curl: (6) Could not resolve host: gateway.pay.internal

Обе команды запущены внутри одного контейнера. У них одинаковый /etc/resolv.conf, нет внешней сети, а прокси для запроса отключён. DNS всё время отдаёт один и тот же IP.

На снимке xterm виден весь эксперимент: сначала ошибка, затем изменение одной строки и успешный запрос.

dig проверил ровно то, о чём его попросили

dig послал DNS-запрос и получил A-запись. Это полезный результат: выбранный DNS доступен и знает нужное соответствие имени и адреса. Но команда не проверяла, каким способом имя ищет приложение.

В нашем окружении curl использует системный резолвер glibc. На его пути находится Name Service Switch — NSS. В /etc/nsswitch.conf задано, из каких источников и в каком порядке получать сведения об именах. Для этого служит строка hosts:.

На сломанном стенде там осталось:

hosts: files

Для поиска хоста разрешён только локальный файл /etc/hosts. Записи нашего шлюза в нём нет. Источника dns в порядке поиска тоже нет - поэтому наличие правильного DNS-сервера в /etc/resolv.conf ничего не меняет. До него этот поиск не доходит.

Пути получились такими:

dig → DNS → 127.0.0.20
curl → системный поиск → NSS → /etc/hosts → имя не найдено

Никакого противоречия: команды проверяли разные цепочки. dig не повторяет системный поиск имён через NSS, по умолчанию он выбирает DNS из /etc/resolv.conf и обращается к нему сам.

Как поймать расхождение без гадания

Следующая проверка - getent. Она обращается к базам NSS, а не заменяет их прямым DNS-запросом:

getent hosts gateway.pay.internal
echo $?

На сломанном стенде вывода нет, код завершения - 2: ключ не найден. Вместе с успешным dig это уже указывает, что надо исследовать системный путь поиска имени, а не ограничиваться содержимым DNS-зоны.

Для более близкой проверки современного API полезен getent ahosts: он использует getaddrinfo(). У getent hosts другие функции поиска, поэтому считать его точной копией любого приложения нельзя. Различия описаны в getent. В эксперименте я дополнительно проверил IPv4-вызов socket.getaddrinfo() из отдельного процесса Python: до исправления он тоже возвращает ошибку, после - адрес шлюза.

Есть и независимая улика. У локального dnsmasq включён журнал запросов. Прямой вызов dig оставляет там запрос. Сломанные getent, Python и curl - ни одного. После исправления запросы от системного поиска появляются. Здесь проблема подтверждается на двух сторонах: приложение не получает адрес, а DNS даже не спрашивают.

Отделяем поиск имени от подключения

До исправления конфигурации полезно проверить сам шлюз, сохранив имя в URL:

curl --noproxy '*' -4 -sS --max-time 2 \
  --resolve gateway.pay.internal:8443:127.0.0.20 \
  http://gateway.pay.internal:8443/health

На стенде ответ - gateway: ok. Опция --resolve задаёт адрес для конкретной пары хост-порт внутри curl. Она позволяет отдельно проверить соединение с выбранным адресом и обработку запроса с исходным именем. Для HTTPS исходное имя сохраняется также для SNI и проверки сертификата.

Это диагностический обход: он показывает, что выбранный IP и HTTP-обработчик доступны. Он не исправляет системное разрешение имени и не доказывает исправность всех маршрутов или реплик. По этой же причине успешный запрос по IP нельзя считать проверкой полной пользовательской цепочки.

Исправление короче расследования

В нашем минимальном окружении ожидаемый порядок - сначала локальный файл, затем DNS:

hosts: files dns

После изменения повторяем обычные команды, уже без --resolve:

getent hosts gateway.pay.internal
curl --noproxy '*' -4 -sS --max-time 2 http://gateway.pay.internal:8443/health

Теперь getent показывает 127.0.0.20 gateway.pay.internal, а шлюз отвечает gateway: ok. DNS-запись не менялась. /etc/hosts не менялся. HTTP-шлюз не перезапускался. Исправился выбор источников для системного поиска имени.

Строка files dns подходит этому стенду. На рабочем сервере нельзя вслепую заменять ею всю настройку: там могут использоваться resolve, myhostname, mDNS и условия досрочного завершения поиска. Восстанавливать нужно ожидаемую конфигурацию конкретной машины, затем проверять запрос из окружения приложения.

Перезапуск всей машины для нашего исправления не понадобился. Но отдельное приложение может держать собственный кеш или старое соединение. Проверка новым процессом и проверка работающего сервиса отвечают на разные вопросы — после правки нужны обе.

Что именно доказала каждая проверка

Проверка

Что мы узнали на этом стенде

dig … A

DNS доступен и возвращает правильную A-запись

getent hosts …

Поиск через NSS не находит имя

Python getaddrinfo()

Системный API тоже не находит адрес

curl --resolve …

С выбранным IP и исходным именем HTTP-запрос проходит

Обычный curl после правки

Для этого запроса восстановлена вся проверяемая цепочка

Оговорка про окружение существенна. У curl бывают разные resolver backend, включая c-ares, а приложение может использовать свой DNS-клиент или DoH. В контейнере нужно проверять его конфиги, а не только конфиги хоста. Поэтому результат getent - проверка системного пути на данной машине, а не универсальная модель любого приложения.

View the original on Хабр →

KioskNews shows a cleaned-up reading view extracted from the publisher’s page — the original always lives on their site, not ours.