¿Por qué puedo conectarme por SSH usando IPv4 si el socket aparece como tcp6? El misterio del dual-stack en Linux
![]()
Si alguna vez has ejecutado netstat -ptnoua | grep LISTEN en un servidor Linux, seguramente te habrá llamado la atención algo como esto:
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 179/nginx: master p
tcp 0 0 0.0.0.0:443 0.0.0.0:* LISTEN 179/nginx: master p
tcp6 0 0 :::22 :::* LISTEN 1/initNginx aparece escuchando en tcp (IPv4 puro), mientras que SSH aparece en tcp6. Y sin embargo, te conectas sin problema por ssh usuario@192.168.x.x, una dirección claramente IPv4. ¿Cómo es posible que un socket "IPv6" acepte tráfico IPv4?
La clave: los sockets dual-stack
La respuesta está en un comportamiento del kernel de Linux conocido como direcciones IPv4-mapeadas sobre IPv6 (IPv4-mapped IPv6 addresses).
Cuando un proceso abre un socket en modo AF_INET6 y hace bind a la dirección :: (el equivalente IPv6 de "todas las interfaces"), ese socket puede comportarse de dos maneras distintas, según un parámetro del kernel:
sysctl net.ipv6.bindv6only0(valor por defecto en Debian, Ubuntu y la mayoría de distros): el socket IPv6 es dual-stack, es decir, acepta tráfico tanto IPv6 como IPv4 en el mismo puerto.1: el socket es solo IPv6; el tráfico IPv4 necesitaría su propio socket independiente.
Con bindv6only=0, cuando llega una conexión IPv4, el kernel la traduce internamente a una dirección con el prefijo ::ffff:, por ejemplo ::ffff:192.168.1.10, y la entrega al mismo socket que está escuchando en ::. Por eso SSH, aunque aparece como tcp6, es perfectamente capaz de aceptar tu conexión IPv4: en realidad nunca ha dejado de escuchar IPv4, simplemente lo hace a través del "envoltorio" IPv6.
¿Por qué unos servicios aparecen como tcp y otros como tcp6?
Esto no depende de una regla global del sistema, sino de cómo cada aplicación decide crear sus sockets:
- Nginx hace bind explícito a
0.0.0.0, por lo que solo escucha IPv4 (tcp). Si quisiera escuchar también en IPv6, necesitarías añadir una directiva comolisten [::]:80;en su configuración. - OpenSSH (gestionado aquí vía socket activation de
init/systemd) hace bind por defecto a::, y al no forzarIPV6_V6ONLY, hereda el comportamiento dual-stack del kernel.
Es decir: el protocolo que ves en netstat refleja la decisión de diseño de cada aplicación, no una limitación real de conectividad.
Cómo comprobarlo tú mismo
Para confirmar el valor del parámetro del kernel:
sysctl net.ipv6.bindv6onlyY para verificar que una conexión IPv4 realmente está llegando "disfrazada" de IPv6:
ss -tnp | grep :22Verás la IP de origen representada como ::ffff:tu.ip.v4.origen, prueba directa de que el kernel está haciendo la traducción.
Por qué esto importa en producción
Más allá de la curiosidad técnica, este comportamiento tiene implicaciones prácticas reales:
- Firewalls e
iptables: si filtras tráfico solo con reglas IPv4 (iptables) pero el servicio escucha en un socket dual-stack, una conexión IPv4 mapeada podría evaluarse bajo las reglas deip6tablesen lugar deiptables, dependiendo de cómo la trate el kernel. Es fácil abrir una brecha sin darte cuenta si solo se protege una de las dos pilas. - Reverse proxies (Nginx/Apache): si en algún momento configuras un
listen [::]:80;sin especificaripv6only=on|offde forma explícita, puedes terminar con un comportamiento dual-stack no intencionado, lo cual puede complicar el logging de IPs reales o el filtrado por IP de origen (por ejemplo, en configuraciones donde solo se permite tráfico desde rangos de Cloudflare, o servicios definidos). - Auditoría y trazabilidad: si dependes de logs para saber "quién se conectó desde dónde", conviene saber que una IP IPv4 puede aparecer registrada como
::ffff:x.x.x.xen ciertos servicios, y las herramientas de análisis deben tenerlo en cuenta.
Conclusión
Ver tcp en un servicio y tcp6 en otro no significa que uno esté mal configurado y el otro no. Simplemente refleja si la aplicación abrió el socket en modo IPv4 puro o en modo IPv6 dual-stack. Gracias a net.ipv6.bindv6only=0, un socket tcp6 escuchando en :: puede aceptar conexiones IPv4 con total normalidad, traduciéndolas mediante direcciones mapeadas. Entender este mecanismo es clave para configurar correctamente firewalls, reverse proxies y reglas de filtrado en entornos donde conviven IPv4 e IPv6.
