curl --resolve и SNI: проверка виртуального хоста без /etc/hosts
Когда нужно проверить виртуальный хост на конкретном IP, но править /etc/hosts нет желания — ни из-за прав, ни из-за конфликтов с другими сервисами — curl --resolve решает обе задачи: подменяет DNS-запись и корректно отправляет SNI в TLS-хендшейке.
Проблема: виртуальный хост без правки /etc/hosts
На одном IP может висеть десяток виртуальных хостов, и сервер выбирает нужный по Host-заголовке (HTTP/1.1) и по SNI (TLS). Если в /etc/hosts нет записи, curl сначала попробует резолвить имя через DNS — и получит не тот IP, или вовсе не получит ответ.
Правка /etc/hosts работает, но требует sudo, засоряет файл и может сломать другие сервисы, которые завязаны на ту же запись.
curl –resolve: синтаксис и пример
Флаг --resolve перехватывает разрешение имени на уровне curl и подменяет его:
| Компонент | Значение |
|---|---|
HOST | Имя виртуального хоста |
PORT | Порт (обычно 443 для HTTPS) |
ADDR | Целевой IP-адрес |
Пример:
curl отправит запрос на 203.0.113.50:443, но в HTTP-заголовке Host будет example.com.
SNI в связке с –resolve
--resolve не меняет имя, которое curl отправляет в SNI. SNI берётся из URL.
Это ключевой момент. Если в URL указано https://example.com, curl в TLS ClientHello отправит example.com как SNI — даже если IP подменён через --resolve. Сервер по SNI выберет правильный сертификат и виртуальный хост.
Проверить, что SNI действительно отправляется, можно с помощью openssl:
Если SNI пустой или неверный, сервер вернёт дефолтный сертификат — и curl выдаст ошибку SSL: certificate subject name does not match.
Практический пример проверки виртуального хоста
Допустим, на сервере 198.51.100.10 крутится несколько виртуальных хостов, и нужно проверить app.local без правки /etc/hosts:
В выводе -v видно:
Connected to 198.51.100.10 (198.51.100.10) port 443— подключение на нужный IP.> Host: app.local— правильный Host-заголовок.TLS SNI extension: "app.local"— SNI отправлен корректно.
Для массовой проверки нескольких хостов на одном IP:
--resolve действует только для текущего процесса curl. После завершения команды подмена исчезает — файл /etc/hosts остаётся нетронутым.
Если нужно, чтобы подмена работала для всех инструментов в терминале, а не только для curl, тогда nsupdate или локальный DNS-резолвер (dnsmasq, stubby) — более подходящий вариант. Но для разовой проверки виртуального хоста --resolve быстрее и безопаснее.