В curl схема socks5:// резолвит имя целевого хоста на вашей машине, а socks5h:// передаёт имя прокси. Другие клиенты этому правилу не следуют: в этом тесте три из шести отправили имя хоста с обычным socks5://, а два из них отказались принимать socks5h:// ещё до подключения.
| Клиент (проверенная версия) | socks5:// отправляет прокси | socks5h:// |
|---|---|---|
| curl 8.22.0 | IPv4-адрес (резолвинг локальный) | имя хоста |
| Requests 2.34.2 + PySocks 1.7.1 | IPv4-адрес (резолвинг локальный) | имя хоста |
| HTTPX 0.28.1 + socksio 1.0.0 | имя хоста | имя хоста |
| aiohttp 3.14.3 + aiohttp-socks 0.12.0 | имя хоста | ValueError, соединения нет |
| Playwright 1.63.0 (Chromium 153.0.8010.12) | имя хоста | net::ERR_NO_SUPPORTED_PROXIES, соединения нет |
| Node.js 24.20.0 + socks-proxy-agent 10.1.0 | IPv4-адрес (резолвинг локальный) | имя хоста |
В каждой ячейке записано, что получил логирующий SOCKS5-сервер на 127.0.0.1, когда клиента просили открыть http://dnsprobe.example/ — имя, которое существует только в локальном файле hosts и указывает на 127.0.0.2. «IPv4-адрес» значит, что прокси увидел 127.0.0.2 и так и не узнал имя. «Имя хоста» значит, что прокси получил dnsprobe.example и резолвить его пришлось бы ему. Для цели https:// каждый клиент дал тот же результат.
Почему тип адреса важен
Запрос SOCKS5 содержит один адрес назначения, и байт ATYP сообщает его тип: X'01' — IPv4, X'03' — доменное имя, X'04' — IPv6. RFC 1928, раздел 4 Клиент, который отправляет доменное имя, оставляет DNS прокси. Клиент, который отправляет IP-адрес, уже выполнил поиск сам. Из этого следуют три вещи:
- Запрос видит ваш собственный резолвер. DNS-запрос для целевого хоста уходит на резолвер, настроенный на вашей машине, мимо соединения с прокси. В документации Requests это сказано прямо:
socks5«causes the DNS resolution to happen on the client, rather than on the proxy server». Requests: SOCKS - Ответ может оказаться не для того места. RFC 7871 отмечает, что многие авторитетные серверы имён «return different responses based on the perceived topological location of the user» и судят о нём по адресу, с которого пришёл запрос, — обычно это ваш резолвер. RFC 7871, раздел 1 Поэтому имя CDN, разрешённое локально, может указывать на сервер, выбранный для вашей сети, и прокси подключится именно к этому адресу. Выходной IP находится в нужном вам регионе, но сервер, до которого он дошёл, был выбран для вашего, так что контент может оказаться от другого региона. Это следует из того, как строится запрос; loopback-тест никакой CDN не измерял.
- Имена, которые может разрешить только прокси, не работают. С именем, которое не резолвится локально, curl 8.22.0 остановился на
curl: (6) Could not resolve host: dnsprobe-missing.example, Requests бросилConnectionErrorс текстом[Errno -2] Name or service not known, а socks-proxy-agent упал сgetaddrinfo ENOTFOUND dnsprobe-missing.example. Ни один из них не отправил прокси запрос. Сsocks5h://все три отправили имя прокси.
В руководстве «HTTP или SOCKS5» разобрано, какое место занимает DNS при выборе протокола прокси. Дальше речь о том, как выбрать правильную схему для каждого клиента.
Что писать в конфигурации
| Клиент | Отправляет прокси имя хоста | Чего избегать |
|---|---|---|
| curl | socks5h:// или --socks5-hostname | socks5:// и --socks5 резолвят локально |
| Requests + PySocks | socks5h:// | socks5:// резолвит локально |
| HTTPX + socksio | socks5:// или socks5h:// | socks:// бросает ValueError |
| aiohttp + aiohttp-socks | socks5:// | socks5h:// бросает ValueError |
| Playwright Chromium | socks5:// | socks5h:// падает при навигации |
| Node socks-proxy-agent | socks5h:// или socks:// | socks5:// резолвит локально |
Единого URL, подходящего всем шести, нет. Если одна настройка PROXY_URL используется несколькими инструментами, то socks5h:// ломает aiohttp-socks и Playwright, а socks5:// заставляет curl, Requests и socks-proxy-agent резолвить локально. Задавайте схему отдельно для каждого клиента.
Два клиента, которые не принимают socks5h://, падают в разные моменты. aiohttp-socks бросает исключение из ProxyConnector.from_url(), до открытия сокета:
ValueError: Invalid scheme component: socks5hPlaywright принимает прокси в chromium.launch() и падает на первой навигации, не обращаясь к прокси:
page.goto: net::ERR_NO_SUPPORTED_PROXIES at http://dnsprobe.example/Документация Playwright приводит socks5://myproxy.com:3128 как SOCKS-форму параметра server. Playwright: параметр proxy Остальные настройки запуска и контекста — в руководстве по прокси в Playwright.
Голая схема socks:// ведёт себя так же непоследовательно. Chromium и socks-proxy-agent восприняли её как SOCKS5 и отправили имя хоста. curl начал с приветствия SOCKS4 (первый байт 0x04), на которое сервер, понимающий только SOCKS5, ответить не может. Requests бросил ValueError: Unable to determine SOCKS version from socks://127.0.0.1:11080, HTTPX — ValueError: Unknown scheme for proxy URL URL('socks://127.0.0.1:11080'), а aiohttp-socks — ValueError: Invalid scheme component: socks.
Две детали установки для Python: Requests нужен extra requests[socks], а HTTPX — httpx[socks]. Без них Requests бросает Missing dependencies for SOCKS support, а HTTPX бросает ImportError с упоминанием socksio; как исправить обе ошибки, включая случай, когда URL прокси приходит из ALL_PROXY, разобрано в отдельном руководстве. Полный код клиента есть в руководстве по прокси в Python Requests и в руководстве по асинхронному прокси в HTTPX.
В этом тесте URL прокси передавался каждому клиенту явно. Если у вас он берётся из ALL_PROXY или HTTPS_PROXY, сначала убедитесь, какую переменную читает клиент: в руководстве по переменным окружения прокси это расписано по клиентам, а NO_PROXY matching, tested показывает, что правила обхода тоже различаются от клиента к клиенту.
Как проверить свою настройку
Чтобы увидеть, что отправляет ваш клиент, учётная запись у прокси-провайдера не нужна. Скачайте socks5_log.py — Python-скрипт на 42 строки без зависимостей. Он завершает приветствие SOCKS5, печатает тип адреса и адрес каждого запроса, а затем отвечает «general SOCKS server failure», так что никуда ничего не пересылается.
Дайте машине тестовое имя, известное только файлу hosts. Не используйте localhost: Chromium отправляет запросы к localhost-именам напрямую, а не через прокси. Chromium: implicit bypass rules Добавьте в /etc/hosts строку:
127.0.0.2 dnsprobe.exampleЗапустите сервер в одном терминале и отправьте по одному запросу на схему из другого:
python3 socks5_log.py 1080
curl -x socks5://127.0.0.1:1080 http://dnsprobe.example/
curl -x socks5h://127.0.0.1:1080 http://dnsprobe.example/С curl 8.18.0 сервер напечатал:
LISTENING 127.0.0.1:1080
CMD=1 IPv4 127.0.0.2 port=80
CMD=1 DOMAIN dnsprobe.example port=80Первый запрос пришёл как IP-адрес, значит, curl разрешил имя локально. Второй пришёл как имя. Обе команды curl завершаются строкой curl: (97) cannot complete SOCKS5 connection to dnsprobe.example. (1) — это отказ сервера, так и должно быть. Замените curl своим клиентом и своей настройкой прокси и прочитайте те же два поля. Если строки нет вообще, клиент отверг схему или обошёл прокси.
Параметры удалённого DNS помимо схемы
Некоторые клиенты дают тот же выбор в виде параметра, обычно он называется rdns:
- curl: в тесте
--socks5-hostname host:portвёл себя какsocks5h://, а--socks5 host:port— какsocks5://. curl man page - Requests: отдельного параметра нет. SOCKS-менеджер urllib3 выставляет флаг
rdnsв PySocks по схеме:Falseдляsocks5,Trueдляsocks5h. Исходный код urllib3 Сам PySocks при прямом использовании принимаетrdnsвset_proxy()и документирует значение по умолчаниюTrue. PySocks README - aiohttp-socks:
ProxyConnectorпринимаетrdns, и в README указано «default is True for socks5». aiohttp-socks README В тестеProxyConnector.from_url("socks5://127.0.0.1:11080", rdns=False)отправил127.0.0.2, аrdns=True— имя хоста. - HTTPX: версия 0.28.1 направляет
socks5иsocks5hв один и тот же SOCKS-транспорт, так что схема ничего не меняет. Исходный код HTTPX - socks-proxy-agent: флаг
lookupзадаётся только схемой:socks5иsocks4резолвят локально,socks5h,socks4aиsocks— нет. Исходный код socks-proxy-agent - Chromium: параметра нет. В его документации сказано, что для SOCKSv5 «name resolution is always done proxy side». Документация Chromium
Метод и ограничения
Записано 4 октября 2026 года на Ubuntu 26.04 (x86_64) с Python 3.14.4 и Node.js 24.20.0. Версии — те, что в первой таблице, плюс urllib3 2.8.0, httpcore 1.0.9, python-socks 3.1.1 и пакет socks 2.8.10. curl 8.18.0 запускался рядом с 8.22.0 и отправил те же адреса. Имя, которое резолвится только в IPv6, пришло как адрес IPv6 от curl, Requests и socks-proxy-agent и как имя хоста от остальных трёх.
Лаборатория — это один loopback-сервер, который отклоняет каждый запрос. Она ничего не говорит ни о каком прокси-сервисе, о SOCKS5 с аутентификацией или UDP, о macOS, Windows, Firefox или WebKit. Значения по умолчанию в библиотеках меняются, поэтому проверяйте те версии, которые используете сами. Архив лаборатории содержит сервер, шесть клиентских скриптов, раннер и README; сырой вывод всех 62 случаев — в results.json.
Связанные материалы
- HTTP или SOCKS5 — выбор протокола и того, где выполняется DNS.
- Переменные окружения прокси — какую переменную читает каждый клиент.
- NO_PROXY matching, tested — такой же тест для правил обхода.
- Настройка прокси в Playwright, асинхронный прокси в HTTPX и прокси в Python Requests — полная конфигурация клиентов.
ipvolt строит прокси-инфраструктуру для разработчиков и агентов. Вступите в лист ожидания — одно письмо, когда откроется доступ.
Источники
- curl man page: --proxy (socks5:// and socks5h://)
- RFC 1928: SOCKS Protocol Version 5, section 4 (address types)
- Requests: SOCKS proxies
- urllib3 2.8.0 source: contrib/socks.py (scheme to rdns)
- PySocks README: set_proxy and rdns
- HTTPX: SOCKS proxies
- HTTPX 0.28.1 source: proxy schemes in _transports/default.py
- aiohttp-socks 0.12.0 README: ProxyConnector and rdns
- python-socks 3.1.1 source: parse_proxy_url schemes
- socks-proxy-agent source: parseSocksURL
- Chromium network docs: SOCKSv5 proxy scheme and implicit bypass rules
- Playwright: browserType.launch proxy option
- RFC 7871: Client Subnet in DNS Queries, section 1