Conntrack no pudo realizar NAT en sus propios paquetes TCP desde otro VRF

Conntrack no pudo realizar NAT en sus propios paquetes TCP desde otro VRF

Me encontré con un problema complicado con la fuente NAT cuando usaba múltiples VRF en un enrutador basado en Debian. Es un poco complejo de explicar, así que intentaré ser claro, pero no será corto, lo siento. Sin embargo, el problema debería ser fácil de reproducir.

Para aislar la parte de "administración" del enrutador (ssh y otros servicios) de su trabajo de enrutador (paquetes de enrutamiento y NAT), intenté configurar el VRF "mgmt" en el VRF predeterminado (más fácil de manejar con sockets de servicios) y el de enrutamiento en un VRF llamado "firewall".

El diagrama se puede resumir así:

Diagrama de Red

La red de "administración" es 192.168.100.0/24 y está enrutada por un conmutador L3 que tiene un L3 con el VRF "firewall" del enrutador a través de la red 10.254.5.0/24. La tercera interfaz del enrutador es la de "Internet", y los paquetes que pasan a través de ella tienen origen NAT. Esta configuración funciona bastante bien para todo en la subred mgmt, excepto los paquetes propios del enrutador, causa de conntrack.

Acerca de las reglas de iptables:

# Table filter

# chain INPUT
-A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
(some INPUT rules, for ssh, snmp, etc)
-A INPUT -j DROP

# chain FORWARD
-A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -m conntrack --ctstate INVALID -j DROP
-A FORWARD -o eth2 -j ACCEPT
-A FORWARD -j DROP

# Table nat

# chain POSTROUTING
-A POSTROUTING -o eth2 -j SNAT --to-source 192.168.122.100

Acerca de la tabla de enrutamiento:

# default VRF
default via 192.168.100.1 dev eth0 proto static metric 20 
192.168.100.0/24 dev eth0 proto kernel scope link src 192.168.100.90

# firewall VRF
default via 192.168.122.1 dev eth2 proto static metric 20
10.254.5.0/24 dev eth1 proto kernel scope link src 10.254.5.2
192.168.100.0/24 proto bgp metric 20 nexthop via 10.254.5.10 dev eth1 weight 1 
192.168.122.0/24 dev eth2 proto kernel scope link src 192.168.122.100 

Entonces, cuando un paquete del VRF predeterminado intenta acceder a Internet, sale de eth0, es enrutado por el conmutador L3, ingresa al firewall VRF por eth1 y es enrutado y NAT a través de eth2. Dado que hago un seguimiento de las conexiones INPUT y FORWARD, conntrack está un poco confundido cuando el paquete regresa y no puede saber qué hacer con el paquete.

Pude solucionar este problema para ICMP y UDP usando la zona conntrack en la tabla sin formato

# Table raw
# chain PREROUTING
-A PREROUTING -i eth0 -j CT --zone 5
# chain OUTPUT
-A OUTPUT -o eth0 -j CT --zone 5

Con estas reglas, los paquetes que se originan en el enrutador y pasan eth0se etiquetan zone 5y cuando los paquetes ingresan eth0también se etiquetan zone 5.

Con un ping a 8.8.8.8, se ve así (con el comando conntrack -E):

    [NEW] icmp     1 30 src=192.168.100.90 dst=8.8.8.8 type=8 code=0 id=1999 [UNREPLIED] src=8.8.8.8 dst=192.168.100.90 type=0 code=0 id=1999 zone=5
    [NEW] icmp     1 30 src=192.168.100.90 dst=8.8.8.8 type=8 code=0 id=1999 [UNREPLIED] src=8.8.8.8 dst=192.168.122.100 type=0 code=0 id=1999
 [UPDATE] icmp     1 30 src=192.168.100.90 dst=8.8.8.8 type=8 code=0 id=1999 src=8.8.8.8 dst=192.168.122.100 type=0 code=0 id=1999
 [UPDATE] icmp     1 30 src=192.168.100.90 dst=8.8.8.8 type=8 code=0 id=1999 src=8.8.8.8 dst=192.168.100.90 type=0 code=0 id=1999 zone=5

Podemos ver aquí que la primera NEWconexión se crea cuando el paquete pasa eth0con la zone=5etiqueta, luego una nueva cuando ingresa al firewall VRF eth1sin la etiqueta. Cuando llega la respuesta, se actualiza primero la segunda conexión (ya que es la que da a Internet) y luego la primera.

Esto también funciona con UDP, por ejemplo con una consulta DNS a 8.8.8.8

    [NEW] udp      17 30 src=192.168.100.90 dst=8.8.8.8 sport=53369 dport=53 [UNREPLIED] src=8.8.8.8 dst=192.168.100.90 sport=53 dport=53369 zone=5
    [NEW] udp      17 30 src=192.168.100.90 dst=8.8.8.8 sport=53369 dport=53 [UNREPLIED] src=8.8.8.8 dst=192.168.122.100 sport=53 dport=53369
 [UPDATE] udp      17 30 src=192.168.100.90 dst=8.8.8.8 sport=53369 dport=53 src=8.8.8.8 dst=192.168.122.100 sport=53 dport=53369
 [UPDATE] udp      17 30 src=192.168.100.90 dst=8.8.8.8 sport=53369 dport=53 src=8.8.8.8 dst=192.168.100.90 sport=53 dport=53369 zone=5

Pero con TCP no funciona. Una consulta telnet al puerto 80 172.16.10.10 tiene este aspecto:

    [NEW] tcp      6 120 SYN_SENT src=192.168.100.90 dst=172.16.10.10 sport=60234 dport=80 [UNREPLIED] src=172.16.10.10 dst=192.168.100.90 sport=80 dport=60234 zone=5
    [NEW] tcp      6 120 SYN_SENT src=192.168.100.90 dst=172.16.10.10 sport=60234 dport=80 [UNREPLIED] src=172.16.10.10 dst=192.168.122.100 sport=80 dport=60234
 [UPDATE] tcp      6 58 SYN_RECV src=192.168.100.90 dst=172.16.10.10 sport=60234 dport=80 src=172.16.10.10 dst=192.168.122.100 sport=80 dport=60234
 [UPDATE] tcp      6 57 SYN_RECV src=192.168.100.90 dst=172.16.10.10 sport=60234 dport=80 src=172.16.10.10 dst=192.168.122.100 sport=80 dport=60234
(The last line repeat multiple times)

Si tcpdump eth2la respuesta allí:

IP 192.168.122.100.60236 > 172.16.10.10.80: Flags [S], seq 4203590660, win 62720, options [mss 1460,sackOK,TS val 1511828881 ecr 0,nop,wscale 7], length 0
IP 172.16.10.10.80 > 192.168.122.100.60236: Flags [S.], seq 3672808466, ack 4203590661, win 65535, options [mss 1430,sackOK,TS val 2474659117 ecr 1511828881,nop,wscale 8], length 0
IP 192.168.122.100.60236 > 172.16.10.10.80: Flags [S], seq 4203590660, win 62720, options [mss 1460,sackOK,TS val 1511829887 ecr 0,nop,wscale 7], length 0
IP 172.16.10.10.80 > 192.168.122.100.60236: Flags [S.], seq 3672808466, ack 4203590661, win 65535, options [mss 1430,sackOK,TS val 2474660123 ecr 1511828881,nop,wscale 8], length 0

Pero como el SIN ACK nunca se reconoce, el enrutador continúa enviando un nuevo SIN.

Ahora, si hago tcpdump eth1:

IP 192.168.100.90.60238 > 172.16.10.10.80: Flags [S], seq 3124513394, win 62720, options [mss 1460,sackOK,TS val 1511928806 ecr 0,nop,wscale 7], length 0
IP 192.168.100.90.60238 > 172.16.10.10.80: Flags [S], seq 3124513394, win 62720, options [mss 1460,sackOK,TS val 1511929823 ecr 0,nop,wscale 7], length 0
IP 192.168.100.90.60238 > 172.16.10.10.80: Flags [S], seq 3124513394, win 62720, options [mss 1460,sackOK,TS val 1511931839 ecr 0,nop,wscale 7], length 0

Podemos ver que la respuesta nunca se redirige a 192.168.100.90.

Si deshabilité el seguimiento de conexiones y permití todo en iptables, funciona. Entonces, creo que conntrack tiene problemas para administrar las conexiones TCP desde sí mismo a otra zona cuando son NAT. Si algo no queda claro, con gusto responderé cualquier pregunta al respecto.

Respuesta1

El problema estaba presente en Debian 10 con un kernel 4.19.0-12-amd64, pero después de una actualización a Debian 11 con un kernel 5.10.0-11-amd64, funciona como se esperaba, incluso para flujos TCP.

información relacionada