Has asegurado el servidor. Al menos eso crees. IPv4 parece limpio, UFW dice “active” y la solicitud de cambio está cerrada. Entonces un escáner alcanza tu dirección IPv6 y encuentra SSH, un endpoint de métricas y algo que habías olvidado que existía.
Este es el modo silencioso de fallo en pilas duales: endureces la vieja Internet y accidentalmente dejas la nueva en el porche con una llave de repuesto bajo el felpudo. Ubuntu 24.04 no es “malo” de forma única aquí. Simplemente es lo bastante moderno como para que IPv6 esté presente, mientras que las prácticas operativas en torno a él siguen ancladas en 2012.
El problema real: “el firewall está activado” no es una afirmación
Los firewalls no son binarios. Son un conjunto de reglas en distintas capas:
- Filtro de paquetes del kernel (nftables en Ubuntu 24.04; iptables heredado puede seguir presente).
- Envoltorio de firewall en el host (UFW es común, pero no es mágico).
- Comportamiento de enlace de servicios (escuchar en
0.0.0.0vs::importa). - Sockets de systemd que arrancan demonios bajo demanda.
- Grupos de seguridad de la nube / ACL de red / firewalls perimetrales que pueden tratar IPv6 de forma distinta.
- Direcciones IPv6 reales (globales, temporales, direcciones de privacidad, SLAAC, RA).
Cuando los equipos dicen “habilitamos UFW”, a menudo quieren decir “habilitamos filtrado IPv4 para los puertos que recordamos”. Mientras tanto, el host tiene una dirección IPv6 global alcanzable, y tu política IPv6 está ausente, permisiva o simplemente no se aplica a la tabla/hook correcta.
Consejo de opinión: si ejecutas un host público con Ubuntu 24.04, debes tratar IPv6 como de primera clase. O lo aseguras explícitamente o lo desactivas con un plan. “Ignorarlo” es simplemente una versión más lenta de “ser comprometido”.
Hechos y contexto: por qué IPv6 sigue sorprendiendo a los equipos
Algo de historia ayuda, porque muchos de los errores operativos de hoy son decisiones de diseño de ayer encontrándose con configuraciones por defecto de hoy.
- IPv6 se estandarizó a finales de los 90 (era RFC 2460), pero su despliegue operativo amplio tardó décadas, así que muchos equipos construyeron memoria operativa en controles solo IPv4.
- IPv6 restauró la dirección de extremo a extremo como patrón “normal”; NAT no es un requisito de diseño. Eso significa que “NAT como límite de seguridad” desaparece.
- La mayoría de los servicios Linux tratan
::como “escuchar en todas las interfaces”, lo que incluye IPv6 y a menudo comportamiento mapeado IPv4 según sysctls y valores por defecto de las aplicaciones. - Dual-stack no es un detalle de transición; es el estado estable en muchas empresas. Desactivar IPv6 suele romper servicios internos (SSO, telemetría, mirrors de paquetes) de formas sorprendentes.
- nftables reemplazó a iptables como el marco moderno de firewall en Linux; los envoltorios y migraciones pueden dejar “reglas que existen” pero no coinciden con el tráfico que crees.
- Los proveedores cloud asignan IPv6 por defecto o lo ponen a un clic. Los grupos de seguridad pueden tener secciones separadas para IPv6 que nadie completa.
- IPv6 tiene múltiples alcances de dirección (link-local, ULA, global). Link-local siempre está presente; global puede aparecer automáticamente vía Router Advertisements o configuración de la nube.
- Existen direcciones IPv6 de privacidad/temporales que pueden rotar, lo que rompe las suposiciones de “fijar este host a una IP conocida” para clientes y monitorización.
- Algunas herramientas de escaneo y scripts de cumplimiento todavía usan IPv4 por defecto. Eso crea “paneles verdes” mientras la exposición real vive en v6.
Una cita que debería colgar en todo equipo de operaciones, porque resume la historia del firewall IPv6 en una línea: “La esperanza no es una estrategia.”
— Gene Kranz
Modelo de amenazas en palabras llanas: cómo ocurre la brecha
La configuración más común que veo en auditorías se parece a esto:
- UFW activado, reglas añadidas para puertos IPv4: 22, 80, 443, quizá 9100 bloqueado.
- IPv6 habilitado por defecto (porque lo está), y el host tiene una dirección IPv6 global.
- O bien:
- IPv6 en UFW está desactivado, por lo que nunca escribe reglas v6, o
- UFW escribe reglas v6 pero nftables no las está aplicando como esperas (menos común, pero real), o
- Tienes una regla v6 “permitir todo” temporal que se volvió permanente.
- Los servicios se enlazan a
::y son accesibles en v6 incluso si solo probaste v4.
Los atacantes no necesitan creatividad. Necesitan que seas predecible. Y “aseguramos IPv4” es predecible.
Broma #1: IPv6 es como una segunda puerta principal que no sabías que tenía tu casa—excepto que viene con un letrero de neón que dice “BIENVENIDOS”.
Guion de diagnóstico rápido (haz esto primero)
Cuando sospechas “se olvidó el firewall IPv6”, quieres respuestas en minutos, no un debate filosófico sobre redes. Este es el orden que encuentra el cuello de botella más rápido.
Primero: demuestra que el host realmente tiene IPv6 alcanzable
- ¿El servidor tiene una dirección IPv6 global?
- ¿Hay una ruta por defecto para IPv6?
- ¿Puedes alcanzar Internet por IPv6?
Segundo: lista lo que está escuchando en IPv6
- Identifica sockets enlazados a
::o a una IPv6 global. - Revisa unidades de socket de systemd que pueden crear listeners incluso cuando el “servicio está detenido”.
Tercero: verifica que el filtro de paquetes aplica la política IPv6
- Estado de UFW para v6 y si existen sus reglas.
- Reglas de nftables: ¿hay una cadena
ip6para input? ¿Hay policy drop por defecto? - Mira contadores mientras generas tráfico (los packets deberían incrementarse en la regla esperada).
Cuarto: prueba externamente, dual-stack, desde una red real
- Escanea la dirección IPv6 desde un host fuera de tu perímetro de red.
- Confirma que “cerrado” realmente significa filtrado/bloqueado, no solo “sin servicio en IPv4”.
Tareas prácticas: comandos, salida esperada y decisiones (dual-stack)
A continuación hay tareas reales de operador. Cada una incluye el comando, qué significa la salida y qué decisión tomar. Hazlas en orden si estás diagnosticando; elige entre ellas si ya sabes dónde está la putrefacción.
Task 1: Confirmar direcciones IPv6 y alcance
cr0x@server:~$ ip -6 addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 state UNKNOWN qlen 1000
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: enp1s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 state UP qlen 1000
inet6 fe80::5054:ff:fe12:3456/64 scope link
valid_lft forever preferred_lft forever
inet6 2001:db8:1234:5678:5054:ff:fe12:3456/64 scope global dynamic
valid_lft 86395sec preferred_lft 14395sec
Significado: Si ves una dirección con scope global, eres alcanzable por IPv6 asumiendo que el enrutamiento lo permite. Link-local (fe80::) no implica por sí misma exposición a Internet.
Decisión: Si existe una global y no está prevista, o bien (a) asegura ahora las reglas IPv6 del firewall, o (b) desactiva IPv6 correctamente (sección posterior) con análisis de impacto.
Task 2: Comprobar enrutamiento IPv6 y ruta por defecto
cr0x@server:~$ ip -6 route show
2001:db8:1234:5678::/64 dev enp1s0 proto ra metric 100 pref medium
fe80::/64 dev enp1s0 proto kernel metric 256 pref medium
default via fe80::1 dev enp1s0 proto ra metric 100 pref medium
Significado: Una ruta default via significa que el host puede enviar tráfico IPv6 hacia afuera. Si no hay ruta por defecto, el inbound aún puede funcionar en algunos entornos, pero por lo general no desde Internet.
Decisión: Ruta por defecto presente → trata la exposición como real e inmediata.
Task 3: Verificar conectividad IPv6
cr0x@server:~$ ping -6 -c 2 ipv6.google.com
PING ipv6.google.com(2607:f8b0:4005:80a::200e) 56 data bytes
64 bytes from 2607:f8b0:4005:80a::200e: icmp_seq=1 ttl=117 time=12.3 ms
64 bytes from 2607:f8b0:4005:80a::200e: icmp_seq=2 ttl=117 time=12.1 ms
--- ipv6.google.com ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
Significado: IPv6 saliente funciona. En muchas redes reales, si el saliente funciona, el entrante está a solo un mal ajuste de firewall de distancia.
Decisión: Continúa con las auditorías de listeners y firewall; no asumas que el upstream te bloquea.
Task 4: Listar sockets escuchando con visibilidad IPv6
cr0x@server:~$ sudo ss -lntup
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port Process
tcp LISTEN 0 4096 0.0.0.0:22 0.0.0.0:* users:(("sshd",pid=1123,fd=3))
tcp LISTEN 0 4096 [::]:22 [::]:* users:(("sshd",pid=1123,fd=4))
tcp LISTEN 0 4096 [::]:9100 [::]:* users:(("node_exporter",pid=1337,fd=3))
tcp LISTEN 0 4096 127.0.0.1:8080 0.0.0.0:* users:(("grafana",pid=1450,fd=9))
tcp LISTEN 0 4096 [::]:80 [::]:* users:(("nginx",pid=1200,fd=6))
Significado: Cualquier listener [::]:PUERTO es alcanzable por IPv6 (sujeto a firewall). Observa que 127.0.0.1:8080 es solo loopback y no está expuesto.
Decisión: Para cada listener [::], decide: ¿debe ser público, privado o solo local? Si no debe ser público, corrige el binding y el firewall.
Task 5: Comprobar la configuración IPv6 en UFW
cr0x@server:~$ sudo grep -n '^IPV6=' /etc/default/ufw
7:IPV6=yes
Significado: Si IPV6=no, UFW no gestionará reglas v6. Si es yes, UFW generará conjuntos de reglas tanto v4 como v6.
Decisión: Si está en no y necesitas IPv6: cámbialo a yes, luego recarga UFW y valida. Si quieres desactivar IPv6 totalmente, no solo cambies UFW; maneja sysctls/netplan y bindings de aplicaciones.
Task 6: Inspeccionar estado de UFW con verbosidad
cr0x@server:~$ sudo ufw status verbose
Status: active
Logging: on (low)
Default: deny (incoming), allow (outgoing), disabled (routed)
New profiles: skip
To Action From
-- ------ ----
22/tcp ALLOW IN 203.0.113.0/24
80/tcp ALLOW IN Anywhere
443/tcp ALLOW IN Anywhere
22/tcp (v6) ALLOW IN 2001:db8:feed::/48
80/tcp (v6) ALLOW IN Anywhere (v6)
443/tcp (v6) ALLOW IN Anywhere (v6)
Significado: La presencia de reglas “(v6)” es buena; significa que UFW al menos emite política IPv6. Pero “Anywhere (v6)” es una decisión real, no un valor por defecto que debas aceptar sin más.
Decisión: Si no pretendías IPv6 público en 80/443/22, limita las reglas ahora. Si UFW no muestra entradas v6, trátalo como alerta roja.
Task 7: Verificar que nftables tiene reglas y cobertura IPv6
cr0x@server:~$ sudo nft list ruleset
table inet ufw {
chain input {
type filter hook input priority filter; policy drop;
iif "lo" accept
ct state established,related accept
ip protocol icmp accept
ip6 nexthdr ipv6-icmp accept
tcp dport 22 ip saddr 203.0.113.0/24 accept
tcp dport 22 ip6 saddr 2001:db8:feed::/48 accept
tcp dport { 80, 443 } accept
counter packets 12345 bytes 987654
reject with icmpx type admin-prohibited
}
chain forward {
type filter hook forward priority filter; policy drop;
}
chain output {
type filter hook output priority filter; policy accept;
}
}
Significado: Una sola table inet con coincidencias tanto ip como ip6 es un buen patrón. Observa la policy drop por defecto en input. También observa las concesiones explícitas para ICMP/ICMPv6.
Decisión: Si solo ves table ip y nada para IPv6, probablemente estás filtrando solo IPv4. Arregla habilitando IPv6 en UFW o escribiendo reglas nftables explícitas para ip6 / inet.
Task 8: Comprobar contadores de nftables mientras generas tráfico IPv6
cr0x@server:~$ sudo nft -a list chain inet ufw input
table inet ufw {
chain input {
type filter hook input priority filter; policy drop;
iif "lo" accept
ct state established,related accept
ip6 nexthdr ipv6-icmp accept
tcp dport 22 ip6 saddr 2001:db8:feed::/48 accept # handle 14
tcp dport { 80, 443 } accept # handle 15
reject with icmpx type admin-prohibited # handle 16
}
}
Significado: El # handle te permite vigilar contadores si añades sentencias counter o si tu cadena ya las incluye. Si no ves contadores incrementarse cuando pruebas, puede que estés viendo el conjunto de reglas equivocado o que el tráfico esté siendo evitado (raro, pero posible con enrutamiento por políticas u otros hooks).
Decisión: Si los contadores no se mueven durante un intento entrante conocido, confirma qué backend de firewall está activo y si otro sistema gestiona nftables.
Task 9: Confirmar qué backend de firewall usa UFW
cr0x@server:~$ sudo ufw version
ufw 0.36.2
Copyright 2008-2023 Canonical Ltd.
Backend: nf_tables
Significado: Si dice Backend: nf_tables, UFW está generando reglas nftables. Si ves iptables legacy en juego, puedes tener filtrado de cerebro dividido.
Decisión: Estandariza: elige nf_tables y elimina/detén scripts legados que sigan llamando iptables directamente.
Task 10: Detectar reglas legacy de iptables que dan confianza falsa
cr0x@server:~$ sudo iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
Significado: Si las políticas legacy de iptables son ACCEPT mientras crees que “niegas por defecto”, no es necesariamente incorrecto—porque nftables puede estar haciendo el filtrado real. Pero es una pista de que estás a un error de migración de un incidente.
Decisión: Si usas nftables, deja de fiarte de la salida de iptables para seguridad. Si algo aún instala reglas iptables, migra o elimínalo.
Task 11: Comprobar sysctls IPv6 que afectan binding y aceptación
cr0x@server:~$ sysctl net.ipv6.conf.all.disable_ipv6 net.ipv6.conf.default.disable_ipv6 net.ipv6.bindv6only
net.ipv6.conf.all.disable_ipv6 = 0
net.ipv6.conf.default.disable_ipv6 = 0
net.ipv6.bindv6only = 0
Significado: IPv6 está habilitado. net.ipv6.bindv6only=0 significa que los sockets IPv6 pueden aceptar tráfico mapeado IPv4 en algunos casos; varía según la aplicación y opciones de socket.
Decisión: No “arregles” la exposición cambiando sysctls a menos que hayas probado el comportamiento de las apps. Prefiere correcciones de firewall y binding.
Task 12: Identificar servicios que escuchan en todas las interfaces y no deberían
cr0x@server:~$ systemctl status node_exporter.service --no-pager
● node_exporter.service - Prometheus Node Exporter
Loaded: loaded (/lib/systemd/system/node_exporter.service; enabled; preset: enabled)
Active: active (running) since Mon 2025-12-30 10:18:42 UTC; 2h 11min ago
Main PID: 1337 (node_exporter)
Tasks: 4 (limit: 9382)
Memory: 9.8M
CPU: 2.1s
CGroup: /system.slice/node_exporter.service
└─1337 /usr/bin/node_exporter --web.listen-address=:9100
Significado: --web.listen-address=:9100 es “escuchar en todas las interfaces”, lo que incluye IPv6 en muchos sistemas. Frecuentemente no es lo que quieres en un host expuesto a Internet.
Decisión: Enlaza exporters a una IP del VLAN de gestión, localhost con un proxy inverso, o protégelos con firewall para tus scrapers—tanto en IPv4 como en IPv6.
Task 13: Confirmar que la activación por sockets de systemd no crea listeners sorpresa
cr0x@server:~$ systemctl list-sockets --all --no-pager
LISTEN UNIT ACTIVATES
[::]:22 ssh.socket ssh.service
127.0.0.53%lo:53 systemd-resolved.socket systemd-resolved.service
/var/run/dbus/system_bus_socket dbus.socket dbus.service
Significado: Si ves una unidad socket escuchando en [::], el kernel acepta conexiones incluso si el servicio parece detenido; systemd lo lanzará bajo demanda.
Decisión: Si pensabas apagar un puerto, deshabilita la unidad socket, no solo el servicio.
Task 14: Escaneo IPv6 externo desde otro host (chequeo de realidad del operador)
cr0x@server:~$ nmap -6 -Pn -p 22,80,443,9100 2001:db8:1234:5678:5054:ff:fe12:3456
Starting Nmap 7.94 ( https://nmap.org ) at 2025-12-30 12:35 UTC
Nmap scan report for 2001:db8:1234:5678:5054:ff:fe12:3456
Host is up (0.021s latency).
PORT STATE SERVICE
22/tcp open ssh
80/tcp open http
443/tcp open https
9100/tcp filtered jetdirect
Nmap done: 1 IP address (1 host up) scanned in 3.11 seconds
Significado: open significa alcanzable y respondiendo. filtered significa que un firewall está bloqueando (bueno, si es lo previsto). Si esperabas que 22 estuviera restringido, verlo abierto es todo el problema.
Decisión: Trata los resultados de escaneo externos como la verdad. Ahora alinea reglas de firewall y enlaces de servicio hasta que el escaneo coincida con la exposición intencionada.
Task 15: Revisión rápida de procesos escuchando y paquetes propietarios
cr0x@server:~$ sudo lsof -nP -iTCP -sTCP:LISTEN | head
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
sshd 1123 root 3u IPv4 32249 0t0 TCP *:22 (LISTEN)
sshd 1123 root 4u IPv6 32251 0t0 TCP *:22 (LISTEN)
nginx 1200 root 6u IPv6 32999 0t0 TCP *:80 (LISTEN)
node_expo 1337 node 3u IPv6 33301 0t0 TCP *:9100 (LISTEN)
Significado: lsof te da nombre de proceso y PID; no hay que adivinar qué servicio está detrás de qué puerto.
Decisión: Si un listener es desconocido, no solo le pongas un firewall. Identifícalo, elimínalo o aíslalo—los demonios misteriosos son cómo “debug temporal” se vuelve “incidente permanente”.
UFW, nftables y la realidad de Ubuntu 24.04
Ubuntu 24.04 vive en el mundo de nftables. Eso es bueno. nftables es más consistente, soporta la familia inet (conjunto único de reglas para v4+v6) y es lo que quieres para hosts modernos.
UFW sigue siendo válido—si lo tratas como un compilador de políticas y validas la salida. Donde la gente falla es al asumir que la salida de estado de UFW equivale a aplicación. Generalmente lo hace, pero “generalmente” no es un SLO.
Haz explícita la política IPv6 (incluso si no permites nada)
Si usas UFW, no dejes IPv6 como un valor implícito. En la práctica, quieres tres cosas:
- IPV6=yes en
/etc/default/ufwpara que UFW emita reglas v6. - Denegar por defecto el tráfico entrante para ambas pilas.
- Reglas de permitir explícitas para los puertos y orígenes que pretendes en ambas pilas.
Prefiere reglas “allow from” sobre permisos globales
En IPv6, la tentación es permitir ampliamente porque “es complicado”. No es complicado; solo es desconocido.
Si SSH es para administradores, entonces SSH es para redes administrativas. Eso aplica también a IPv6. Si no tienes rangos IPv6 administrativos estables, resuélvelo usando VPN/bastión, no abriendo SSH al planeta.
ICMPv6 no es un cableado opcional
La gente ama bloquear ICMP. Oyen “ping” y piensan “reconocimiento”. Con IPv6, bloquear ICMPv6 rompe mecanismos reales del protocolo: descubrimiento de Path MTU, Neighbor Discovery, Router Advertisements en algunos entornos. Tu postura “sigilosa” se convierte en “fallos aleatorios”.
Broma #2: Bloquear ICMPv6 para “estar seguro” es como cortar las líneas de freno para prevenir exceso de velocidad.
Cuando escribir nftables directamente
Si tienes un entorno complejo—contenedores, múltiples interfaces, routing por políticas, segmentación estricta—puedes superar UFW. Eso no es un fracaso moral. Es madurez.
Pero si escribes nftables directamente, responsabilízate del ciclo de vida completo: despliegue de reglas, carga atómica, backups y chequeos CI. “Editar reglas de firewall en vivo a las 2 a.m.” es una tradición que deberíamos acabar.
Sockets de systemd: la mentira de “el servicio no está en ejecución”
En Ubuntu, systemd puede escuchar un puerto en nombre de un servicio y arrancar ese servicio solo cuando llega una conexión. Eso es activación por sockets. Es eficiente. También es fuente de confusión durante auditorías de seguridad.
Modo de fallo: alguien para ssh.service y piensa que SSH está apagado. Pero ssh.socket sigue escuchando. El puerto sigue siendo alcanzable. El escáner sigue sin impresionarse.
Regla operativa: si un puerto está abierto, está abierto. “Pero el servicio estaba detenido” no es una defensa, es admitir que no revisaste la capa de sockets.
Usa systemctl list-sockets, identifica listeners en [::] y deshabilítalos si el puerto no debería existir.
Nube y filtrado ascendente: no externalices tu pensamiento
En el mundo corporativo, la exposición IPv6 suele venir de controles ascendentes con cerebro dividido:
- El grupo de seguridad tiene reglas IPv4 correctamente configuradas.
- Las reglas IPv6 están vacías (lo que a veces significa “permitir todo” según la plataforma), o las gestiona otro equipo, o simplemente se olvidaron.
- El firewall del host asume que el upstream bloquea cosas; el upstream asume que el host bloquea cosas.
La única estrategia estable es defensa en profundidad con controles v6 explícitos en cada capa. El firewall del host debe ser correcto incluso si el upstream falla, porque el upstream eventualmente fallará.
Además: si usas balanceadores gestionados, revisa cómo tratan la terminación IPv6 y la conectividad hacia los backends. Puedes tener un host perfectamente endurecido y seguir exponiendo un servicio administrativo a través de un listener IPv6 en la interfaz equivocada si tu red interna es dual-stack.
Tres microhistorias corporativas (anonimizadas, dolorosamente plausibles)
1) Incidente causado por una suposición equivocada: “Aquí no usamos IPv6”
La empresa ejecutaba una flota de VMs Ubuntu detrás de un firewall perimetral. Todo era “solo IPv4” según el diagrama de red. La postura de seguridad se construyó alrededor de eso: reglas UFW centradas en IPv4 y escaneos de cumplimiento que verificaban solo registros A.
Durante una prueba de penetración rutinaria, el tester preguntó por los rangos IPv6. La respuesta fue un encogimiento de hombros. “No usamos IPv6”. El tester no necesitaba rangos; necesitaba un hostname y un resolvedor que devolviera registros AAAA.
Resultó que la VPC de la nube había habilitado IPv6 meses antes para un proyecto separado. Algunas subredes asignaban direcciones IPv6 automáticamente. Nadie avisó al equipo de ops porque el cambio “no afectó a producción”. No lo hizo—hasta que alguien miró.
Los hallazgos fueron mundanos y brutales: SSH abierto al mundo en IPv6, un panel de administración de staging enlazado a ::, y un endpoint de métricas sin autenticación. Nada se explotó; no hacía falta. El informe fue suficiente.
La solución no fue heroica. Hicieron que UFW soportara IPv6, duplicaron las listas de permitidos, ajustaron bindings de servicios y añadieron escaneo dual-stack al CI. Lo difícil fue cultural: admitir que “no usamos IPv6” nunca fue un hecho—solo una creencia sin comprobar.
2) Optimización que salió mal: “Simplifiquemos las reglas del firewall”
Un equipo de plataforma quería menos partes móviles. Estaban cansados de UFW como “otra abstracción”, así que migraron a un conjunto mínimo de nftables. Una tabla, una cadena, accept por defecto. Confiarían en los grupos de seguridad upstream. Limpio. Elegante. Rápido.
Luego sufrieron un incidente en producción: fallos de conectividad esporádicos para un subconjunto de clientes que usaban IPv6. El on-call asumió que era problema del balanceador. No lo era. El firewall permitía inbound, pero el tráfico de retorno saliente se veía afectado por un cambio de policy routing separado, y ICMPv6 necesario para PMTU se estaba descartando upstream.
La “optimización” eliminó el logging local y la costumbre de mirar contadores. El equipo no tenía forma rápida de demostrar qué hacía el host. Tuvieron que depurar a ciegas, desde capturas de paquetes, bajo presión.
Finalmente revirtieron a un firewall hostil más estricto: drop por defecto inbound, allows explícitos, manejo explícito de ICMPv6 y logging a ritmo sensato. La lección irónica: menos reglas no significó menos complejidad. Solo la movió a un lugar con peor visibilidad.
3) Práctica aburrida pero correcta que salvó el día: “Escaneamos ambas pilas, siempre”
Otra organización tenía una costumbre aburrida: cada pipeline de build ejecutaba un escaneo externo contra el host candidato, en IPv4 e IPv6, desde un runner fuera de la VPC de producción. No era elegante. Era consistente.
Un día, una actualización de imagen base cambió la dirección por defecto de bind de un servicio de 127.0.0.1 a ::. El servicio debía ser interno, scrapeado por un proxy sidecar. En IPv4, seguía pareciendo correcto por el enrutamiento interno. En IPv6, de pronto era alcanzable desde sitios donde no debía.
El escaneo dual-stack falló el build. El ticket nunca llegó a producción. Nadie tuvo que escribir un informe de incidente ni explicar a dirección por qué “solo interno” estaba en Internet público.
Ese es el valor de prácticas aburridas: no evitan cada fallo, pero hacen que los fallos sean baratos. Quieres fallos baratos.
Errores comunes: síntomas → causa raíz → solución
1) Síntoma: “Los puertos IPv4 están cerrados, pero el escaneo IPv6 los muestra abiertos”
Causa raíz: Reglas IPv6 ausentes o permisivas (UFW IPv6 deshabilitado, o nftables sin cobertura ip6/inet).
Solución: Habilita IPv6 en UFW (IPV6=yes), recarga y verifica que nftables tenga table inet o cadenas ip6 con drop por defecto. Re-escanea externamente por IPv6.
2) Síntoma: “UFW está activo pero IPv6 sigue alcanzable”
Causa raíz: Herramientas de firewall con cerebro dividido; UFW gestiona nftables pero otra herramienta carga un conjunto permisivo después, o estás mirando iptables mientras nftables aplica.
Solución: Inspecciona nft list ruleset. Asegura que tus reglas se carguen en el arranque y que nada las sobreescriba. Estandariza en un administrador.
3) Síntoma: “Detuve el servicio, pero el puerto sigue abierto”
Causa raíz: Activación por sockets de systemd; la unidad socket sigue escuchando.
Solución: Deshabilita la unidad .socket: systemctl disable --now name.socket. Verifica con ss y escaneo externo.
4) Síntoma: “Tras endurecer IPv6, conexiones aleatorias se cuelgan”
Causa raíz: ICMPv6 bloqueado con demasiada agresividad, rompiendo PMTU o Neighbor Discovery.
Solución: Permite tipos esenciales de ICMPv6. Si usas UFW, asegúrate de que permita IPv6-ICMP. Si escribes nftables, acepta explícitamente ip6 nexthdr ipv6-icmp y luego refina reglas.
5) Síntoma: “El servicio está ligado a 0.0.0.0, ¿por qué está en IPv6?”
Causa raíz: El servicio se enlaza por separado a IPv6 :: o usa un socket dual-stack según runtime y sysctls.
Solución: Confirma con ss -lntup. Configura direcciones de escucha explícitas en la app (v4 y v6 según necesidad), o enlaza a una interfaz/IP específica.
6) Síntoma: “El escaneo de cumplimiento está en verde, pero un investigador externo nos avisó de exposición IPv6”
Causa raíz: Las herramientas de escaneo solo probaron IPv4 (o solo registros DNS A).
Solución: Añade descubrimiento de activos AAAA y escaneo IPv6 al control. Trata dual-stack como base.
7) Síntoma: “Deshabilitamos IPv6 y ahora apt o servicios internos fallan”
Causa raíz: Tu entorno usa IPv6 para algunas rutas (mirrors, proxies, SSO, descubrimiento de servicios). Desactivar IPv6 no siempre es “seguro”.
Solución: Prefiere firewall sobre desactivar. Si debes desactivar, prueba en staging con la misma configuración DNS y proxy.
Listas de verificación / plan paso a paso
Checklist A: Respuesta de emergencia (encontraste exposición IPv6 hoy)
- Identifica las direcciones IPv6 expuestas:
ip -6 addr. Decide cuáles son globales. - Lista listeners:
ss -lntup. Anota[::]:PUERTO. - Bloquea inbound IPv6 en el firewall del host de inmediato: si dudas, establece deny por defecto inbound y permite solo SSH desde tus rangos administrativos.
- Confirma la aplicación:
nft list rulesety escaneo externo connmap -6. - Arregla bindings: reconfigura servicios para escuchar solo en las interfaces previstas.
- Deja logging activado (moderado): suficiente para ver si estás bloqueando tráfico legítimo.
Checklist B: Endurecimiento correcto (que persista tras reinicios y actualizaciones)
- Elige un gestor de firewall: UFW sobre nftables, o nftables directo. No ejecutes dos “propietarios”.
- Haz reglas dual-stack simétricas: cada allow inbound debería existir para IPv4 e IPv6 salvo divergencia con justificación.
- Mantén ICMPv6 funcional: permítelo apropiadamente.
- Audita sockets de systemd:
systemctl list-sockets; deshabilita listeners inesperados. - Añade escaneo dual-stack al pipeline: desde un punto externo, guarda resultados, falla builds si hay aperturas inesperadas.
- Documenta la exposición prevista: puerto, protocolo, rangos fuente y justificación. Trátalo como un contrato de API.
Checklist C: Si insistes en desactivar IPv6 (hazlo como adulto)
- Inventario de dependencias: uso de AAAA en DNS, servicios internos, proxies, monitorización. No supongas.
- Desactívalo via sysctl con persistencia: establece
net.ipv6.conf.all.disable_ipv6=1ydefaulten/etc/sysctl.d/, luego reinicia y prueba. - Verifica que esté realmente desactivado:
ip -6 addrdebería mostrar solo::1o nada en las interfaces. - Re-verifica servicios: algunas apps se comportan distinto cuando IPv6 desaparece; prueba health checks y conectividad cliente.
Mi sesgo: firewallear suele ser más seguro que desactivar. Desactivar IPv6 es un martillo grande que suele golpearte los propios pulgares después.
Preguntas frecuentes
1) ¿Por qué mi servidor tiene IPv6 si nunca lo configuré?
Porque las redes modernas lo suministran automáticamente (configuración de la nube, Router Advertisements, DHCPv6). Ubuntu lo usará gustoso cuando esté disponible.
2) Si no publico registros AAAA, ¿estoy a salvo?
No. Los atacantes pueden descubrir direcciones IPv6 por muchos medios: logs, certificados, descubrimiento de vecinos en redes internas, metadata de la nube o simplemente escaneando prefijos conocidos en algunos entornos.
3) ¿UFW bloquea IPv6 por defecto?
Sólo si el soporte IPv6 está habilitado en UFW y se generan reglas para v6. Comprueba /etc/default/ufw y ufw status verbose para ver reglas “(v6)”.
4) ¿Debo reflejar exactamente mis reglas IPv4 para IPv6?
Casi siempre, sí. La divergencia es una elección arquitectónica consciente. Si no puedes explicar por qué IPv6 está más abierto que IPv4, es un accidente.
5) ¿Por qué algunos puertos aparecen “filtered” en escaneos IPv6?
Eso indica típicamente que el firewall está descartando paquetes (bueno para “bloqueado”). También puede indicar filtrado upstream. Valida comprobando contadores y logs del firewall del host.
6) ¿Puedo poner IPV6=no en UFW para arreglar la exposición?
Eso suele empeorar las cosas: le dices a UFW que deje de gestionar IPv6, no que desactive la red IPv6. Seguirás teniendo direcciones IPv6 y listeners; simplemente tendrás menos protecciones.
7) ¿Cuál es la postura IPv6 más segura y simple para un servidor web público?
Denegar por defecto inbound. Permitir 80/443 desde cualquier lugar en ambas pilas. Permitir SSH solo desde rangos administrativos o mediante VPN/bastión. Permitir ICMPv6 esencial.
8) Estoy detrás de un balanceador cloud. ¿Necesito firewall en el host?
Sí. Los balanceadores se configuran mal y las rutas internas pueden evitarlos. Los firewalls en el host son un seguro barato y capturan errores como “me enlacé a ::”.
9) ¿Cómo sé si una app está escuchando en IPv6?
Usa ss -lntup y busca [::]:PUERTO o una dirección IPv6 específica. No confíes en la documentación de la app; confía en la lista de sockets.
10) ¿Es aceptable bloquear ICMPv6?
No como política global. Puedes restringir ciertos tipos con cuidado más adelante, pero debes preservar la funcionalidad básica o crearás fallos que parecen “flakiness” de red aleatoria.
Próximos pasos que puedes ejecutar
Haz tres cosas esta semana y eliminarás la mayoría de los incidentes por “firewall IPv6 olvidado”:
- Audita listeners con
ss -lntupy mata o rebindea cualquier cosa que no deba ser pública en[::]. - Haz la política de firewall dual-stack: confirma que UFW IPv6 está habilitado (o escribe reglas nftables en
inet), y asegúrate de un drop inbound por defecto en IPv4 e IPv6. - Valida desde fuera con un escaneo IPv6 real y guarda el resultado. Si no lo pruebas externamente, no lo sabes.
Ubuntu 24.04 no intenta engañarte. Simplemente hace lo que hacen los sistemas modernos: incluir IPv6 listo para usar. Tu trabajo es hacer que “listo” signifique “seguro”, no “sorpresivamente alcanzable”.