En curl, socks5:// resuelve el nombre de host del destino en tu máquina y socks5h:// le entrega el nombre al proxy. Otros clientes no siguen esa regla: en esta prueba, tres de seis enviaron el nombre de host con un socks5:// normal, y dos de ellos rechazaron socks5h:// antes de conectarse.
| Cliente (versión probada) | socks5:// envía al proxy | socks5h:// |
|---|---|---|
| curl 8.22.0 | una dirección IPv4 (resuelta en local) | el nombre de host |
| Requests 2.34.2 + PySocks 1.7.1 | una dirección IPv4 (resuelta en local) | el nombre de host |
| HTTPX 0.28.1 + socksio 1.0.0 | el nombre de host | el nombre de host |
| aiohttp 3.14.3 + aiohttp-socks 0.12.0 | el nombre de host | ValueError, sin conexión |
| Playwright 1.63.0 (Chromium 153.0.8010.12) | el nombre de host | net::ERR_NO_SUPPORTED_PROXIES, sin conexión |
| Node.js 24.20.0 + socks-proxy-agent 10.1.0 | una dirección IPv4 (resuelta en local) | el nombre de host |
Cada celda es lo que recibió un servidor SOCKS5 con registro en 127.0.0.1 cuando se le pidió al cliente http://dnsprobe.example/, un nombre que solo existe en el archivo hosts local como 127.0.0.2. «Una dirección IPv4» significa que el proxy vio 127.0.0.2 y nunca conoció el nombre. «El nombre de host» significa que recibió dnsprobe.example y tendría que resolverlo él. Todos los clientes dieron el mismo resultado con un destino https://.
Por qué importa el tipo de dirección
Una petición SOCKS5 lleva una sola dirección de destino, y su byte ATYP indica de qué tipo es: X'01' para IPv4, X'03' para un nombre de dominio, X'04' para IPv6. RFC 1928, sección 4 Un cliente que envía un nombre de dominio deja el DNS en manos del proxy. Un cliente que envía una dirección IP ya hizo la consulta por su cuenta. Eso tiene tres consecuencias:
- Tu propio resolvedor ve la consulta. La consulta DNS del destino va al resolvedor configurado en tu máquina, fuera de la conexión con el proxy. La documentación de Requests lo dice directamente:
socks5«causes the DNS resolution to happen on the client, rather than on the proxy server». Requests: SOCKS - La respuesta puede ser para otro lugar. El RFC 7871 señala que muchos servidores de nombres autoritativos «return different responses based on the perceived topological location of the user», y la deducen de la dirección desde la que llega la consulta, que normalmente es tu resolvedor. RFC 7871, sección 1 Por eso un nombre de CDN resuelto en local puede apuntar a un servidor elegido para tu red, y el proxy se conecta exactamente a esa dirección. La IP de salida está en la región que pediste, pero el servidor al que llegó se eligió para la tuya, así que el contenido puede ser el de otra región. Esto se deduce de cómo se construye la petición; la prueba en loopback no midió ninguna CDN.
- Los nombres que solo el proxy puede resolver fallan. Con un nombre que no se resuelve en local, curl 8.22.0 se detuvo en
curl: (6) Could not resolve host: dnsprobe-missing.example, Requests lanzó unConnectionErrorque contenía[Errno -2] Name or service not known, y socks-proxy-agent falló congetaddrinfo ENOTFOUND dnsprobe-missing.example. Ninguno envió una petición al proxy. Consocks5h://, los tres enviaron el nombre al proxy.
La guía de HTTP frente a SOCKS5 explica dónde encaja la ubicación del DNS al elegir un protocolo de proxy. El resto de este artículo trata de acertar con el esquema en cada cliente.
Qué poner en tu configuración
| Cliente | Envía el nombre de host al proxy | Evita |
|---|---|---|
| curl | socks5h:// o --socks5-hostname | socks5:// y --socks5 resuelven en local |
| Requests + PySocks | socks5h:// | socks5:// resuelve en local |
| HTTPX + socksio | socks5:// o socks5h:// | socks:// lanza ValueError |
| aiohttp + aiohttp-socks | socks5:// | socks5h:// lanza ValueError |
| Playwright Chromium | socks5:// | socks5h:// falla al navegar |
| Node socks-proxy-agent | socks5h:// o socks:// | socks5:// resuelve en local |
No hay una única URL correcta para los seis. Si un mismo ajuste PROXY_URL alimenta varias herramientas, socks5h:// rompe aiohttp-socks y Playwright, y socks5:// hace que curl, Requests y socks-proxy-agent resuelvan en local. Define el esquema por cliente.
Los dos clientes que rechazan socks5h:// fallan en momentos distintos. aiohttp-socks lanza la excepción desde ProxyConnector.from_url(), antes de abrir ningún socket:
ValueError: Invalid scheme component: socks5hPlaywright acepta el proxy en chromium.launch() y falla en la primera navegación, sin contactar con el proxy:
page.goto: net::ERR_NO_SUPPORTED_PROXIES at http://dnsprobe.example/La documentación de Playwright da socks5://myproxy.com:3128 como la forma SOCKS de la opción server. Playwright: opción proxy La guía de proxy en Playwright recoge el resto de ajustes de lanzamiento y de contexto.
El esquema socks:// a secas es igual de inconsistente. Chromium y socks-proxy-agent lo trataron como SOCKS5 y enviaron el nombre de host. curl abrió con un saludo SOCKS4 (primer byte 0x04), que un servidor solo SOCKS5 no puede responder. Requests lanzó ValueError: Unable to determine SOCKS version from socks://127.0.0.1:11080, HTTPX lanzó ValueError: Unknown scheme for proxy URL URL('socks://127.0.0.1:11080') y aiohttp-socks lanzó ValueError: Invalid scheme component: socks.
Dos detalles de instalación en Python: Requests necesita el extra requests[socks] y HTTPX necesita httpx[socks]. Sin ellos Requests lanza Missing dependencies for SOCKS support y HTTPX lanza un ImportError que nombra socksio; la solución para ambos cubre también el caso en que la URL del proxy viene de ALL_PROXY. La guía de proxy con Python Requests y la guía de proxy asíncrono con HTTPX muestran el código completo del cliente.
En esta prueba la URL del proxy se pasó a cada cliente de forma explícita. Si la tuya viene de ALL_PROXY o HTTPS_PROXY, confirma primero qué variable lee el cliente; la guía de variables de entorno de proxy lo detalla por cliente, y NO_PROXY matching, tested muestra que las reglas de exclusión también difieren entre clientes.
Cómo comprobar tu propia configuración
No necesitas una cuenta de proxy para ver qué envía tu cliente. Descarga socks5_log.py, un script de Python de 42 líneas sin dependencias. Completa el saludo SOCKS5, imprime el tipo de dirección y la dirección de cada petición y después responde «general SOCKS server failure», así que no se reenvía nada.
Dale a tu máquina un nombre de prueba que solo conozca el archivo hosts. No uses localhost: Chromium envía las peticiones a nombres de localhost directamente en lugar de pasarlas por el proxy. Chromium: implicit bypass rules Añade esta línea a /etc/hosts:
127.0.0.2 dnsprobe.exampleArranca el servidor en una terminal y envía una petición por esquema desde otra:
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/Con curl 8.18.0 el servidor imprimió:
LISTENING 127.0.0.1:1080
CMD=1 IPv4 127.0.0.2 port=80
CMD=1 DOMAIN dnsprobe.example port=80La primera petición llegó como dirección IP, así que curl resolvió el nombre en local. La segunda llegó como nombre. Los dos comandos de curl terminan con curl: (97) cannot complete SOCKS5 connection to dnsprobe.example. (1), que es la negativa del servidor y es lo esperado. Sustituye curl por tu propio cliente y tu ajuste de proxy, y lee los mismos dos campos. Si no aparece ninguna línea, el cliente rechazó el esquema o se saltó el proxy.
Opciones de DNS remoto además del esquema
Algunos clientes ofrecen la misma elección como opción, normalmente llamada rdns:
- curl: en la prueba,
--socks5-hostname host:portse comportó comosocks5h://y--socks5 host:portcomosocks5://. curl man page - Requests: no hay una opción aparte. El gestor SOCKS de urllib3 fija el indicador
rdnsde PySocks según el esquema:Falseparasocks5,Trueparasocks5h. Código fuente de urllib3 El propio PySocks, usado directamente, aceptardnsenset_proxy()y documentaTruecomo valor por defecto. PySocks README - aiohttp-socks:
ProxyConnectoraceptardns, y su README indica «default is True for socks5». aiohttp-socks README En la prueba,ProxyConnector.from_url("socks5://127.0.0.1:11080", rdns=False)envió127.0.0.2yrdns=Trueenvió el nombre de host. - HTTPX: la versión 0.28.1 dirige
socks5ysocks5hal mismo transporte SOCKS, así que el esquema no cambia nada. Código fuente de HTTPX - socks-proxy-agent: solo el esquema fija su indicador
lookup:socks5ysocks4resuelven en local;socks5h,socks4aysocksno. Código fuente de socks-proxy-agent - Chromium: no hay opción. Su documentación dice que para SOCKSv5 «name resolution is always done proxy side». Documentación de red de Chromium
Método y límites
Registrado el 4 de octubre de 2026 en Ubuntu 26.04 (x86_64) con Python 3.14.4 y Node.js 24.20.0. Las versiones son las de la primera tabla, más urllib3 2.8.0, httpcore 1.0.9, python-socks 3.1.1 y el paquete socks 2.8.10. curl 8.18.0 se ejecutó junto a 8.22.0 y envió las mismas direcciones. Un nombre que solo se resuelve a IPv6 llegó como dirección IPv6 desde curl, Requests y socks-proxy-agent, y como nombre de host desde los otros tres.
El laboratorio es un único servidor en loopback que rechaza todas las peticiones. No dice nada sobre ningún servicio de proxy, sobre SOCKS5 con autenticación o UDP, ni sobre macOS, Windows, Firefox o WebKit. Los valores por defecto de las bibliotecas cambian, así que comprueba las versiones que uses. El archivo del laboratorio contiene el servidor, los seis scripts de cliente, el ejecutor y un README; la salida en bruto de los 62 casos está en results.json.
Relacionado
- HTTP frente a SOCKS5, para elegir el protocolo y decidir dónde se ejecuta el DNS.
- Variables de entorno de proxy, para saber qué variable lee cada cliente.
- NO_PROXY matching, tested, el mismo tipo de prueba para las reglas de exclusión.
- Proxy en Playwright, proxy asíncrono con HTTPX y proxy con Python Requests, para la configuración completa de cada cliente.
ipvolt está construyendo infraestructura de proxies para desarrolladores y agentes. Únete a la lista de espera para recibir un correo cuando se abra el acceso.
Fuentes
- 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