Debian/Ubuntu: «Funciona en LAN, falla en WAN» — comprobaciones de enrutamiento/NAT que revelan la causa (caso #85)

¿Te fue útil?

Puedes acceder desde la oficina. Puedes acceder desde el rack de al lado. La comprobación de salud está en verde en la subred privada. Entonces un cliente en Internet lo prueba y todo se desmorona como una silla plegable barata.

Este es el clásico fallo «funciona en LAN, falla en WAN». Rara vez es la aplicación. Suele ser enrutamiento, NAT, estado del firewall, o un tropiezo de MTU/PMTUD. La buena noticia: puedes demostrar cuál es en minutos—si dejas de adivinar y comienzas a interrogar la ruta del paquete.

El modelo mental: el éxito en LAN no prueba la salud en WAN

Cuando algo «funciona en LAN», solo has demostrado una cosa: los hosts en el mismo dominio de enrutamiento pueden completar un viaje de ida y vuelta. Eso es todo. El tráfico WAN introduce:

  • IPs de origen diferentes (redes públicas frente a RFC1918). Tu servidor, firewall y upstream pueden tratarlas distinto.
  • Estado NAT (SNAT/DNAT/masquerade) que no existe en rutas puramente LAN.
  • Caminos de retorno diferentes (enrutamiento asimétrico) cuando tienes múltiples gateways, VPNs o enrutamiento por políticas “útil”.
  • MTUs diferentes (PPPoE, túneles, overlays) que pueden matar ciertos flujos silenciosamente.
  • Zonas ACL distintas (grupos de seguridad cloud, firewalls de borde, filtrado del ISP) que no se prueban con tráfico LAN.

En la práctica, «LAN OK, WAN roto» se reduce a unos pocos reincidentes:

  1. Ruta por defecto incorrecta (o métrica errónea) para el tráfico de retorno.
  2. Falta SNAT/masquerade para egress, o DNAT roto para ingress.
  3. El firewall permite subredes LAN pero descarta orígenes «desconocidos» o estado related/established.
  4. El filtrado de ruta inversa (rp_filter) descarta paquetes porque Linux piensa que el origen no debería llegar por esa interfaz.
  5. Agujeros negros de MTU/PMTUD: SYN funciona, TLS se queda, “es inestable”.

No empieces reiniciando servicios. Empieza demostrando cómo entra un paquete, cómo se traduce (si lo hace) y cómo sale. Si no puedes describir la ruta en una frase, no estás diagnosticando—estás esperando.

Hechos interesantes e historia (porque las redes traen equipaje)

  • Direcciones privadas RFC1918 (1996) convirtieron a NAT en la muleta por defecto para el agotamiento de IPv4; también normalizaron el consuelo engañoso de «funciona internamente».
  • Linux netfilter/iptables llegó en la era del kernel 2.4, reemplazando ipchains; el modelo mental de «tablas/cadenas/hooks» sigue importando incluso si usas nftables hoy.
  • Estado conntrack es la razón por la que «allow established/related» funciona—y por qué una tabla conntrack llena hace que un firewall sano parezca poseído.
  • Filtrado de ruta inversa (rp_filter) fue diseñado para reducir el spoofing; en sistemas multi-homed puede descartar tráfico legítimo y crear fallos exclusivos de WAN.
  • Path MTU Discovery depende de mensajes ICMP “Fragmentation needed”; filtrar ICMP puede romper flujos grandes mientras que pings pequeños siguen funcionando.
  • Ajuste de MSS de TCP se volvió un workaround común para problemas de MTU en túneles; es útil, pero también oculta causas raíz y puede reducir rendimiento.
  • Enrutamiento asimétrico es común en el mundo real (uplinks duales, SD-WAN, ECMP), pero los firewalls stateful suelen asumir simetría y te penalizan por ser creativo.
  • Reflexión NAT (hairpin NAT) es la razón por la que clientes internos a veces alcanzan un servicio por su IP pública; cuando falta, obtienes un confuso «LAN roto, WAN bien» también.
  • nftables unificó las semánticas IPv4/IPv6 de filtrado y mejoró rendimiento/expresividad, pero el periodo de transición dejó muchos sistemas con herramientas mixtas y expectativas desajustadas.

Una cita para recordar en una nota adhesiva:

«La esperanza no es una estrategia.» — Gen. Gordon R. Sullivan

Esa frase se repite en operaciones porque es dolorosamente cierta. No «sientes» el enrutamiento. Lo mides.

Guion de diagnóstico rápido (primero/segundo/tercero)

Primero: confirma que el síntoma es realmente específico de WAN

  • Prueba desde fuera de tu red (hotspot móvil, sonda externa, VM en la nube).
  • Prueba por IP y por nombre (DNS puede hacerse pasar por enrutamiento).
  • Prueba TCP e ICMP por separado (los firewalls los tratan distinto).

Segundo: demuestra el enrutamiento y la ruta de retorno en el servidor

  • ip route get <client_ip> desde el servidor: la interfaz de salida elegida y la IP de origen deben tener sentido.
  • Revisa rutas y métricas; la ruta por defecto “correcta” no sirve si no es la preferida.
  • Si es multi-homed o tiene VPN: inspecciona ip rule y las rutas por tabla.

Tercero: demuestra NAT y estado en el borde (o en el host, si hace NAT)

  • Busca DNAT/SNAT faltantes, coincidencias de interfaz erróneas o reglas que solo afectan subredes LAN.
  • Inspecciona entradas conntrack mientras pruebas; si los paquetes llegan pero no se crea estado, el orden de hooks/reglas es incorrecto.
  • Valida rp_filter y el comportamiento MTU/PMTUD antes de culpar al “ISP”.

Si solo haces una cosa: ejecuta tcpdump en las interfaces de ingreso y egreso durante una prueba externa. Los paquetes no mienten; los humanos sí.

Tareas prácticas: comandos, salidas y decisiones (12+)

Estas están pensadas para ejecutarse en servidores Debian/Ubuntu y/o en el gateway Linux que realiza enrutamiento/NAT. Cada tarea incluye qué significa la salida y qué decisión tomar a continuación.

Task 1 — Confirma interfaces y direcciones (sanidad primero)

cr0x@server:~$ ip -br addr
lo               UNKNOWN        127.0.0.1/8 ::1/128
ens160           UP             10.20.0.10/24 fe80::a00:27ff:fe12:3456/64
ens192           UP             203.0.113.10/29 fe80::a00:27ff:fe98:7654/64

Significado: Esta máquina tiene varias interfaces: LAN privada en ens160, WAN pública en ens192. Los sistemas multi-homed son el terreno fértil donde nace «LAN funciona, WAN falla».

Decisión: Asume riesgo de ruta de retorno y rp_filter. Continúa con enrutamiento y reglas, no con los logs de la aplicación.

Task 2 — Lee la tabla de enrutamiento como si importara

cr0x@server:~$ ip route
default via 10.20.0.1 dev ens160 proto dhcp metric 100
default via 203.0.113.9 dev ens192 proto static metric 200
10.20.0.0/24 dev ens160 proto kernel scope link src 10.20.0.10 metric 100
203.0.113.8/29 dev ens192 proto kernel scope link src 203.0.113.10 metric 200

Significado: Dos rutas por defecto. La ruta LAN tiene métrica más baja (100), así que gana. Clientes WAN podrían alcanzar la IP pública, pero las respuestas pueden intentar salir por el gateway LAN. Eso es asimetría.

Decisión: Corrige la preferencia de la ruta por defecto o implementa enrutamiento por políticas para que el tráfico que entra por WAN vuelva por WAN.

Task 3 — Pregunta al kernel: “¿cómo alcanzarías a este cliente WAN?”

cr0x@server:~$ ip route get 198.51.100.77
198.51.100.77 via 10.20.0.1 dev ens160 src 10.20.0.10 uid 0
    cache

Significado: Las respuestas a un cliente público saldrían por la interfaz privada con una dirección privada de origen. Eso no es «un poco mal». Es una explicación completa de tu outage.

Decisión: Añade enrutamiento por políticas o elimina la ruta por defecto en conflicto. No toques la app.

Task 4 — Identifica enrutamiento por políticas que secuestran tráfico silenciosamente

cr0x@server:~$ ip rule show
0:      from all lookup local
1000:   from 203.0.113.10 lookup wan
32766:  from all lookup main
32767:  from all lookup default

Significado: Existe una regla para tráfico originado desde la IP pública que usa la tabla wan. Eso ayuda, pero solo si el tráfico realmente tiene origen 203.0.113.10.

Decisión: Asegúrate de que las conexiones entrantes a la IP pública conserven esa IP de origen para las respuestas (sin SNAT a LAN), y comprueba que los servicios se enlacen correctamente. Valida ip route show table wan.

Task 5 — Inspecciona la tabla de enrutamiento WAN usada por el enrutamiento por políticas

cr0x@server:~$ ip route show table wan
default via 203.0.113.9 dev ens192
203.0.113.8/29 dev ens192 scope link src 203.0.113.10

Significado: La tabla es razonable. Si WAN sigue fallando, lo probable es que las respuestas no estén coincidiendo con esta regla (IP de origen incorrecta) o que los paquetes se estén descartando (rp_filter/firewall/NAT).

Decisión: Valida la IP de origen real usada en las respuestas con tcpdump.

Task 6 — Comprueba el filtrado de ruta inversa (el “anti-spoofing” que te arruina)

cr0x@server:~$ sysctl net.ipv4.conf.all.rp_filter net.ipv4.conf.ens160.rp_filter net.ipv4.conf.ens192.rp_filter
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.ens160.rp_filter = 1
net.ipv4.conf.ens192.rp_filter = 1

Significado: rp_filter estricto (1) en un host multi-homed puede descartar paquetes cuando la “mejor ruta de retorno” no coincide con la interfaz de ingreso. Exactamente tu situación con dos rutas por defecto.

Decisión: Pon rp_filter en modo laxo (2) en las interfaces relevantes, o arregla la simetría de enrutamiento para poder mantener modo estricto.

Task 7 — Verifica el reenvío de IP (si el host es un router/box NAT)

cr0x@server:~$ sysctl net.ipv4.ip_forward
net.ipv4.ip_forward = 0

Significado: Si esta máquina debe enrutar entre LAN y WAN, actualmente se niega.

Decisión: Habilita el reenvío y luego valida firewall/NAT. Si no debe enrutar, detente y replantea el diseño (puede que estés depurando la máquina equivocada).

Task 8 — Inspecciona el ruleset de nftables (predeterminado moderno en Debian/Ubuntu)

cr0x@server:~$ sudo nft list ruleset
table inet filter {
  chain input {
    type filter hook input priority 0; policy drop;
    ct state established,related accept
    iif "ens160" ip saddr 10.20.0.0/24 accept
    tcp dport 22 accept
  }
  chain forward {
    type filter hook forward priority 0; policy drop;
    ct state established,related accept
    iif "ens160" oif "ens192" accept
  }
}
table ip nat {
  chain postrouting {
    type nat hook postrouting priority 100; policy accept;
    oif "ens192" masquerade
  }
}

Significado: La política de input es drop. Acepta established/related y cualquier cosa desde la subred LAN. También permite SSH desde cualquier lugar. Pero no permite que la WAN alcance el puerto de tu servicio. Esa es una explicación clara y aburrida.

Decisión: Añade reglas explícitas de aceptación desde WAN para los puertos necesarios, y mantenlas lo más restrictivas posible. No “aceptes por política” y luego informes incidentes.

Task 9 — Si usas iptables, revisa tablas filter y nat

cr0x@server:~$ sudo iptables -S
-P INPUT DROP
-P FORWARD DROP
-P OUTPUT ACCEPT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A INPUT -s 10.20.0.0/24 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 22 -j ACCEPT

Significado: La misma historia que con nft: el tráfico WAN hacia el puerto de la app no está permitido. LAN funciona porque la subred LAN de origen está permitida.

Decisión: Añade una regla de permitir para el puerto del servicio, acotada a los orígenes esperados si es posible. Si el servicio está detrás de DNAT, también necesitas reglas en la cadena FORWARD.

Task 10 — Valida reglas DNAT/port-forwarding (en el borde o en el host)

cr0x@gateway:~$ sudo nft list table ip nat
table ip nat {
  chain prerouting {
    type nat hook prerouting priority -100; policy accept;
    iif "ens192" tcp dport 443 dnat to 10.20.0.10:443
  }
  chain postrouting {
    type nat hook postrouting priority 100; policy accept;
    oif "ens192" masquerade
  }
}

Significado: El puerto 443 desde WAN se reenvía a un host interno. Si WAN no puede conectar, o los paquetes no llegan a ens192, o la cadena FORWARD lo bloquea, o la ruta de retorno del host interno/NAT de respuesta es incorrecta.

Decisión: Captura tráfico en ambas interfaces y comprueba los contadores de la cadena FORWARD.

Task 11 — Observa conntrack mientras pruebas desde WAN

cr0x@gateway:~$ sudo conntrack -E -p tcp --dport 443
    [NEW] tcp      6 120 SYN_SENT src=198.51.100.77 dst=203.0.113.10 sport=51234 dport=443 [UNREPLIED] src=10.20.0.10 dst=198.51.100.77 sport=443 dport=51234

Significado: El gateway ve un SYN entrante y ha creado una conexión NATeada, pero aparece [UNREPLIED]. El servidor interno no respondió, o la respuesta no regresó por este gateway.

Decisión: tcpdump en la interfaz interna para ver si el SYN llega al servidor; tcpdump en el servidor para ver si responde; verifica que la ruta por defecto del servidor apunte a este gateway.

Task 12 — tcpdump en WAN: ¿los paquetes llegan?

cr0x@gateway:~$ sudo tcpdump -ni ens192 tcp port 443
tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
listening on ens192, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:04:21.123456 IP 198.51.100.77.51234 > 203.0.113.10.443: Flags [S], seq 1234567890, win 64240, options [mss 1460,sackOK,TS val 1 ecr 0,nop,wscale 7], length 0

Significado: El SYN entrante alcanza el gateway. Esto no es un bloqueo del ISP. Ahora es tu problema (felicidades).

Decisión: Captura también en la interfaz LAN para confirmar que el reenvío y el DNAT funcionan.

Task 13 — tcpdump en LAN: ¿el SYN reenviado alcanza el servidor?

cr0x@gateway:~$ sudo tcpdump -ni ens160 host 10.20.0.10 and tcp port 443
listening on ens160, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:04:21.124001 IP 198.51.100.77.51234 > 10.20.0.10.443: Flags [S], seq 1234567890, win 64240, options [mss 1460,sackOK,TS val 1 ecr 0,nop,wscale 7], length 0

Significado: El DNAT funciona; el servidor ve tráfico con la IP original del cliente (bien). Ahora el servidor debe responder a través del gateway para que SNAT y el seguimiento de estado completen el handshake.

Decisión: Revisa la ruta del servidor de vuelta al cliente y ejecuta tcpdump en el egreso del servidor.

Task 14 — tcpdump en el servidor: ¿responde y desde qué IP de origen?

cr0x@server:~$ sudo tcpdump -ni ens160 tcp port 443 and host 198.51.100.77
listening on ens160, link-type EN10MB (Ethernet), snapshot length 262144 bytes
12:04:21.124050 IP 198.51.100.77.51234 > 10.20.0.10.443: Flags [S], seq 1234567890, win 64240, options [mss 1460,sackOK,TS val 1 ecr 0,nop,wscale 7], length 0
12:04:21.124090 IP 10.20.0.10.443 > 198.51.100.77.51234: Flags [R.], seq 0, ack 1234567891, win 0, length 0

Significado: El servidor está rechazando (RST) en 443, así que la app/servicio no está escuchando o está enlazada a otra dirección. «Funciona en LAN» podría estar alcanzando un VIP/puerto distinto, o un proxy local.

Decisión: Valida los sockets en escucha y las direcciones de enlace. Si fuera un SYN-ACK, entonces verifica que la respuesta salga por el gateway (siguiente tarea).

Task 15 — Comprueba sockets en escucha y direcciones bind

cr0x@server:~$ sudo ss -lntp | egrep ':443|:80'
LISTEN 0      4096       127.0.0.1:443       0.0.0.0:*    users:(("nginx",pid=2031,fd=7))

Significado: El servicio está ligado solo a loopback. Funcionará en pruebas locales y quizá desde un proxy LAN, pero fallará para tráfico reenviado WAN que llegue a 10.20.0.10.

Decisión: Reconfigura el bind a la interfaz correcta (0.0.0.0 o la IP específica) y vuelve a probar desde WAN.

Task 16 — Comprueba MTU rápidamente cuando «SYN funciona, TLS se queda»

cr0x@server:~$ ping -M do -s 1472 198.51.100.77 -c 2
PING 198.51.100.77 (198.51.100.77) 1472(1500) bytes of data.
ping: local error: message too long, mtu=1492
ping: local error: message too long, mtu=1492

--- 198.51.100.77 ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1026ms

Significado: Tu MTU efectiva es 1492 (clásico PPPoE). Si asumes 1500 y bloqueas ICMP, puedes crear un fallo exclusivo de WAN donde los paquetes pequeños funcionan y los grandes se pierden.

Decisión: Corrige el MTU de extremo a extremo o aplica MSS clamp en el túnel/borde. No «abras puertos al azar».

Chiste #1: NAT es como la política de oficina—nadie admite que existe, pero decide quién puede hablar con quién.

Patrones de enrutamiento/NAT que causan éxito solo en LAN

1) El servidor tiene dos rutas por defecto y gana la incorrecta

Este es el patrón nº1 en sistemas multi-homed: una interfaz para gestión/LAN, otra para ingreso público/WAN, a veces una tercera para VPN. Linux elige la ruta con la métrica más baja. Si DHCP te da un gateway por defecto en la NIC LAN y añades una estática para WAN, has creado una lotería donde la ruta “incorrecta” se elige consistentemente.

La petición WAN entra por la interfaz WAN, pero la respuesta sale por el gateway LAN. El upstream la descarta porque la IP de origen es incorrecta, o porque el firewall stateful en medio nunca ve la respuesta.

Qué hacer: elige una ruta por defecto en main, y usa enrutamiento por políticas para las excepciones. Si debes mantener múltiples por defecto, sé explícito con métricas y direcciones de origen.

2) DNAT funciona, pero FORWARD está descartando

En un gateway Linux, DNAT en PREROUTING puede ser perfecto y aun así no funciona nada porque la cadena FORWARD tiene política drop y no hay regla de permitir para el servicio reenviado. La gente revisa «las reglas NAT» y se detiene ahí. Así es como pasas una noche de martes con tcpdump y arrepentimiento.

Qué hacer: trata NAT y filtrado como capas separadas. Necesitas ambas: la traducción y el permiso.

3) Falta SNAT/masquerade para egress

Los hosts LAN pueden alcanzar el gateway, pueden alcanzar servicios internos, incluso resolver DNS. Pero no pueden acceder a Internet porque los paquetes salen con IPs privadas y mueren upstream. Localmente, todo parece bien.

Qué hacer: confirma que exista SNAT/masquerade en POSTROUTING y que coincida con la interfaz de salida correcta. Luego confirma que el tráfico de retorno esté permitido y que conntrack no esté agotado.

4) rp_filter descarta paquetes solo de orígenes “raros”

El filtrado de ruta inversa estricto está bien en hosts de una sola interfaz. En sistemas multi-homed o con enrutamiento por políticas, puede descartar paquetes legítimos porque el kernel dice: «si yo enrutara de vuelta a ese origen, no usaría esta interfaz, así que debe ser spoofing».

Es una postura de seguridad razonable, hasta que eres tú quien explica por qué solo falla la WAN. El modo laxo (2) suele ser el compromiso correcto en sistemas de borde con múltiples uplinks.

5) Agujero negro MTU/PMTUD

Los paquetes pequeños funcionan. Los pings funcionan. SYN/SYN-ACK funcionan. Luego el handshake TLS se queda, las subidas HTTP cuelgan o streams gRPC se reinician. El culpable suele ser PMTUD roto por ICMP filtrado, más una MTU reducida por PPPoE o túneles.

Qué hacer: mide la MTU, permite tipos ICMP esenciales y aplica MSS clamp cuando sea necesario.

6) Confusión por hairpin NAT

A veces el informe es «funciona desde Internet, falla desde dentro de la oficina al usar el hostname público». Eso es hairpin NAT (reflexión NAT). Es el laberinto de espejos del NAT: útil cuando lo necesitas, desorientador cuando no lo tienes.

Qué hacer: implementa DNS de horizonte dividido (split-horizon) o configura hairpin NAT correctamente en el dispositivo de borde.

Chiste #2: Si crees que tu enrutamiento es «simple», o eres afortunado o no has mirado ip rule aún.

Tres mini-historias corporativas (anonimizadas, plausibles, dolorosamente familiares)

Mini-historia #1 — El outage causado por una suposición equivocada

Migraron un servicio orientado al cliente desde una VM con una sola NIC a una VM con dos NICs: una interfaz para «tráfico interno east-west» y otra para «ingreso público». El ingeniero tenía la intuición correcta: “separa el tráfico, reduce riesgo”.

La suposición errónea fue sutil: asumieron que la NIC pública se convertiría automáticamente en la ruta por defecto para las respuestas a clientes públicos. No lo hizo. DHCP en la red interna proporcionó un gateway por defecto con métrica más baja, y Linux lo usó felizmente.

Desde la red interna, el servicio parecía perfecto. El monitoreo interno estaba en verde. El on-call rotó, vio las comprobaciones internas pasando y dijo al equipo de producto que el problema era “probablemente propagación DNS”. No lo era. Los clientes externos veían SYN-ACKs viniendo de la IP de origen errónea o no los veían, dependiendo de dónde el camino asimétrico fuese filtrado.

La solución no fue heroica. Eliminaron el gateway por defecto interno, usaron una ruta específica para subredes internas y añadieron enrutamiento por políticas para las pocas llamadas salientes que necesitaban la interfaz interna. La lección real del postmortem: una prueba LAN pasada no es una prueba WAN, y las métricas de ruta son configuración operativa, no trivia.

Mini-historia #2 — La optimización que salió mal

Un equipo de plataforma quiso “estandarizar reglas de firewall” en las flotas. Pasaron de una política permisiva por defecto a drop por defecto con una pequeña lista de permitidos. Eso suele ser lo correcto—hasta que lo despliegas sin entender las fuentes de tráfico.

Permitieron puertos de aplicación desde el espacio RFC1918 corporativo y desde una subred de partner. Olvidaron que los clientes reales no vienen de esos rangos. En staging, todo pasó porque las pruebas de staging se ejecutaban dentro de la red. En producción, el tráfico WAN llegaba al borde, se reenviaba correctamente y luego moría en la cadena input del firewall del host.

El on-call pasó horas revisando salud del load balancer y certificados TLS porque “funciona internamente”. Finalmente alguien ejecutó nft list ruleset y notó que la regla de allow estaba acotada a orígenes internos únicamente. La “optimización” era correcta en espíritu pero incompleta en alcance.

Lo arreglaron definiendo zonas explícitas: internal, partner, internet. Internet recibió una lista mínima de puertos públicos permitidos, con limitación de tasa, registro y monitoreo. También añadieron una comprobación sintética externa como puerta de liberación. El verdadero revés no fue la seguridad. Fue asumir que las pruebas internas representaban al mundo.

Mini-historia #3 — La práctica aburrida que salvó el día

Una compañía financiera tenía un pequeño pero estricto runbook: cada vez que se desplegaba un nuevo endpoint público, el ingeniero debía adjuntar tres artefactos al ticket: ip route get hacia una sonda pública, un snippet de tcpdump mostrando SYN/SYN-ACK y el diff de la regla de firewall.

La gente se quejaba. Parecía burocrático. Entonces un despliegue de un nuevo cliente VPN cambió prioridades de enrutamiento en un subconjunto de hosts. La VPN empujó una nueva ruta por defecto con mejor métrica. Internamente, todo seguía funcionando. Externamente, los endpoints quedaron intermitentemente oscuros—solo para tráfico originado desde ciertas redes, dependiendo de qué egress se elegía.

Puesto que tenían “artefactos aburridos”, el on-call comparó el ip route y ip rule de hoy con el ticket de la semana pasada. La diferencia fue obvia: la ruta por defecto de la VPN ahora ganaba. Añadieron una regla de política para la IP del servicio y fijaron el tráfico de retorno a la tabla correcta. Sin conjeturas, sin superstición.

La práctica no fue glamorosa. Fue evidencia reproducible. Eso salvó el día, no una sala de guerra.

Errores comunes: síntomas → causa raíz → solución

1) Síntoma: funciona desde la IP LAN, falla desde la IP pública

Cause raíz: servicio ligado a 127.0.0.1 o solo a la dirección LAN.

Solución: cambia la dirección de bind/listen a 0.0.0.0 o al VIP/pública, y confirma con ss -lntp. Si está detrás de DNAT, liga al address interno al que DNAT dirige.

2) Síntoma: llega SYN externo, pero no vuelve SYN-ACK

Cause raíz: ruta de retorno asimétrica (ruta por defecto errónea, métrica equivocada, falta enrutamiento por políticas) o rp_filter descarta respuestas/solicitudes.

Solución: ejecuta ip route get <client_ip>, ajusta rutas/métricas o añade ip rule + default por tabla. Pon rp_filter en modo laxo donde corresponda.

3) Síntoma: DNAT parece correcto; aún sin conectividad

Cause raíz: cadena FORWARD descarta, o falta regla de permitir para tráfico reenviado.

Solución: añade un allow explícito en la cadena forward para iif wan oif lan y puerto de destino; mantén established/related permitidos.

4) Síntoma: hosts LAN no alcanzan Internet, pero el gateway sí

Cause raíz: falta SNAT/masquerade para egress LAN, o SNAT ligado al nombre de interfaz equivocado.

Solución: añade masquerade en postrouting para la interfaz WAN, confirma con tcpdump que los paquetes de salida usan la fuente pública.

5) Síntoma: ping funciona, HTTP funciona en páginas pequeñas, subidas/TLS cuelgan

Cause raíz: agujero negro MTU/PMTUD (a menudo ICMP bloqueado) sobre PPPoE/túneles.

Solución: permite ICMP “fragmentation needed”, reduce MTU en interfaces, o aplica MSS clamp en el borde.

6) Síntoma: algunas redes externas funcionan, otras fallan

Cause raíz: filtrado/peering upstream, o enrutamiento por políticas basado en prefijo de origen, o una ACL acotada a subredes “conocidas”.

Solución: prueba desde múltiples sondas externas; revisa reglas de firewall por coincidencias de origen demasiado específicas; revisa BGP/política de borde si aplica.

7) Síntoma: funciona en IPv4, falla en IPv6 (o viceversa)

Cause raíz: configuración dual-stack parcial: DNS devuelve AAAA pero firewall/rutas no están listas, o supuestos NAT64.

Solución: prueba explícita con -4/-6, asegura que nftables tenga reglas inet que cubran ambos, y confirma tablas de enrutamiento para v6.

8) Síntoma: clientes internos no alcanzan servicio por hostname público

Cause raíz: falta hairpin NAT o ausencia de DNS de horizonte dividido.

Solución: implementa DNS dividido o configura reflexión NAT; no lo “arregles” abriendo el firewall más.

Listas de verificación / plan paso a paso

Paso a paso: diagnosticar un servicio público que solo funciona en LAN

  1. Reproduce desde fuera. Usa un punto de vista verdaderamente externo. Si no puedes, para—a tu diagnóstico le faltará perspectiva.
  2. Confirma DNS vs enrutamiento. Compara dig desde dentro y fuera; prueba por IP directamente.
  3. Comprueba que el servicio realmente escucha. Usa ss -lntp y verifica que las direcciones de bind coincidan con la ruta del tráfico.
  4. Rastrea la llegada del paquete. tcpdump en la interfaz WAN: ¿llegan los SYNs?
  5. Rastrea reenvío/NAT. tcpdump en el lado LAN del gateway: ¿DNAT reenvía el SYN al servidor?
  6. Rastrea la respuesta del servidor. tcpdump en el egreso del servidor: ¿responde y por qué interfaz/IP?
  7. Confirma la decisión de enrutamiento. ip route get <client_ip> debe mostrar la interfaz de salida y la fuente correctas.
  8. Confirma decisiones del firewall. Los contadores de nftables/iptables deben incrementarse donde esperas. Si no lo hacen, tu regla no coincide con la realidad.
  9. Revisa rp_filter y conntrack. rp_filter para multi-homing; tamaño de tabla conntrack si falta estado o hay flapping.
  10. Sólo entonces mira la aplicación. A estas alturas sabrás si la app nunca vio paquetes, los rechazó o respondió a un vacío.

Paso a paso: arreglar problemas de ruta de retorno con seguridad (host multi-homed)

  1. Elige una ruta por defecto primaria en main. Hazla el egress para la mayoría del tráfico.
  2. Crea una tabla de enrutamiento dedicada (p. ej., wan) con su propio gateway por defecto.
  3. Añade una ip rule que concuerde con tráfico originado desde la IP pública (o fwmark) para usar esa tabla.
  4. Pon rp_filter en modo laxo donde el multi-homing lo requiera, o mantén modo estricto si puedes garantizar simetría.
  5. Valida con ip route get para IPs representativas de clientes.
  6. Valida con tcpdump: SYN entra, SYN-ACK sale por el mismo borde.

Paso a paso: validar NAT en un gateway Linux

  1. Confirma que el reenvío esté habilitado: sysctl net.ipv4.ip_forward.
  2. Confirma que existan reglas NAT (PREROUTING para DNAT, POSTROUTING para SNAT/masquerade).
  3. Confirma que la cadena FORWARD permita el flujo (nuevo y establecido).
  4. Confirma que las entradas conntrack cambien de UNREPLIED a replied durante una prueba.
  5. Confirma que la ruta por defecto del host interno apunte al gateway NAT (o tenga una ruta de retorno al cliente).

Preguntas frecuentes

1) Si funciona en LAN, ¿no prueba eso que el firewall está bien?

No. Muchos firewalls permiten fuentes RFC1918 ampliamente y tratan las fuentes de Internet como hostiles. El éxito en LAN a menudo solo prueba que tu regla de allow para LAN coincide.

2) ¿Por qué curl desde el propio servidor funciona, pero WAN falla?

Un curl local no atraviesa DNAT, no demuestra simetría de enrutamiento y puede alcanzar bindings de loopback. Siempre prueba desde un host externo y observa el flujo de paquetes.

3) ¿Cómo detecto rápidamente enrutamiento asimétrico?

Ejecuta ip route get <external_client_ip> y compáralo con la interfaz de ingreso. Si la respuesta saldría por una interfaz distinta, tienes riesgo de asimetría.

4) ¿Debería deshabilitar rp_filter?

Prefiere rp_filter=2 (laxo) en interfaces multi-homed en lugar de deshabilitarlo en todas. Si puedes hacer enrutamiento simétrico, el modo estricto (1) es seguro y preferible.

5) Uso nftables pero las herramientas aún muestran reglas iptables. ¿Cuál es la real?

En Debian/Ubuntu, iptables puede estar respaldado por nft (iptables-nft). El kernel evalúa nftables. Usa nft list ruleset para ver la verdad.

6) ¿Por qué veo UNREPLIED en conntrack?

Se vio el primer paquete y se creó estado, pero no hubo tráfico de retorno que completara el flujo. Eso apunta a que el servidor no respondió, la ruta de retorno es incorrecta, o la respuesta fue bloqueada/descartada.

7) ¿Puede el MTU realmente romper solo la WAN?

Sí. Las rutas LAN suelen quedarse en 1500. Los bordes WAN (PPPoE, VPNs, túneles) pueden reducir MTU. Con ICMP bloqueado, PMTUD falla y los paquetes grandes desaparecen.

8) ¿Cuál es la forma más segura de abrir un puerto para acceso WAN?

Añade una regla explícita de aceptación para el puerto del servicio en el camino de ingreso (host o gateway), mantén drop por defecto y añade registro/limitación de tasa donde corresponda.

9) Mi servicio está detrás de DNAT. ¿Dónde debo depurar primero: gateway o servidor?

Empieza en la interfaz WAN del gateway: ¿llegan los paquetes? Luego la interfaz LAN: ¿se reenvían? Finalmente el servidor: ¿responde? Esa secuencia evita soñar despierto.

10) Cambié rutas pero nada cambió. ¿Por qué?

La caché de rutas y el estado conntrack existente pueden mantener el comportamiento antiguo brevemente. Limpia la caché de rutas (ip route flush cache) y vuelve a probar con nuevas conexiones.

Conclusión: siguientes pasos prácticos

Si te enfrentas a «funciona en LAN, falla en WAN», deja de tratarlo como un misterio. Es un problema de ruta de paquetes hasta que se demuestre lo contrario.

  1. Ejecuta ip route y ip route get para una IP de cliente real. Corrige la simetría de la ruta de retorno o añade enrutamiento por políticas.
  2. Inspecciona nft list ruleset (o iptables) y confirma que el tráfico WAN esté permitido explícitamente donde debe (INPUT para servicios en host, FORWARD para DNAT).
  3. Usa tcpdump en interfaces de ingreso y egreso durante una prueba externa. Confirma: llegada, traducción, reenvío, respuesta.
  4. Revisa rp_filter y MTU cuando los síntomas sean selectivos o “flaky”.
  5. Convierte tus hallazgos en un pequeño runbook para tu equipo: los comandos, las salidas esperadas y la decisión que cada salida impulsa.

El objetivo no es memorizar cada hook de netfilter. Es crear el hábito: nunca adivines cuando el kernel te puede decir qué está haciendo.

← Anterior
MariaDB vs PostgreSQL: picos de CPU — quién quema núcleos más rápido bajo carga máxima
Siguiente →
WordPress «Se le está redirigiendo»: detener bucles de redirección por SSL y cookies

Deja un comentario