¿Por qué iptables rechaza el segundo fragmento y los siguientes de un paquete permitido?

9

Tengo dos hosts que intentan configurar una conexión IPSec entre sí. Para esto tienen que comunicarse en los puertos UDP 500 y 4500, así que los abrí en los firewalls en ambos extremos (se muestra en la parte relevante):

-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -m udp -p udp --dport 500 -j ACCEPT
-A INPUT -m udp -p udp --dport 4500 -j ACCEPT
#.....
-A INPUT -j REJECT --reject-with icmp6-port-unreachable

Sin embargo, el intercambio de claves nunca tiene éxito. Cada lado sigue intentando retransmitir los paquetes UDP una y otra vez, sin escuchar una respuesta, hasta que finalmente se rinden.

Comencé tcpdumpen un extremo y observé que el paquete UDP estaba siendo fragmentado, y que un puerto ICMP inalcanzable estaba siendo devuelto después de que entrara el segundo fragmento.

Un ejemplo de dicho intercambio fallido (desinfectado para su protección):

04:00:43.311572 IP6 (hlim 51, next-header Fragment (44) payload length: 1240) 2001:db8::be6b:d879 > 2001:db8:f:608::2: frag (0x5efa507c:0|1232) ipsec-nat-t > ipsec-nat-t: NONESP-encap: isakmp 2.0 msgid 00000001 cookie 55fa7f39522011ef->f8259707aad5f995: child_sa  ikev2_auth[I]: [|v2e] (len mismatch: isakmp 1596/ip 1220)
04:00:43.311597 IP6 (hlim 51, next-header Fragment (44) payload length: 384) 2001:db8::be6b:d879 > 2001:db8:f:608::2: frag (0x5efa507c:1232|376)
04:00:43.311722 IP6 (hlim 64, next-header ICMPv6 (58) payload length: 432) 2001:db8:f:608::2 > 2001:db8::be6b:d879: [icmp6 sum ok] ICMP6, destination unreachable, length 432, unreachable port[|icmp6]

El firewall registró lo siguiente con respecto a este paquete:

Aug 26 04:00:43 grummle kernel: iptables: REJECT IN=eth0 OUT= MAC=############### SRC=2001:0db8:0000:0000:0000:0000:be6b:d879 DST=2001:0db8:000f:0608:0000:0000:0000:0002 LEN=424 TC=0 HOPLIMIT=51 FLOWLBL=0 OPT ( FRAG:1232 ID:5efa507c ) PROTO=UDP

Tenía la impresión de que Linux reensamblaba automáticamente los fragmentos antes de pasarlos al filtro de paquetes. Entonces, ¿por qué estos fragmentos no se vuelven a ensamblar y, por lo tanto, el segundo fragmento se rechaza posteriormente?

Michael Hampton
fuente
Como nota al margen, IME también debe permitir ESP:iptables -A INPUT -p esp -j ACCEPT
fukawi2
@ fukawi2 Sí, pero eso no es relevante para esta pregunta.
Michael Hampton

Respuestas:

14

El código de netfilter solo vuelve a ensamblar fragmentos para usted antes del filtrado de paquetes si las reglas de su firewall usan el seguimiento de conexión (es decir, la regla del firewall tiene estado y usa -m conntracko está en desuso -m state) o NAT. De lo contrario, todos los fragmentos se procesan por separado y obtienes problemas como este.

Esto hace que resolver el problema sea fácil y obvio (en retrospectiva, de todos modos). Simplemente agregue el seguimiento de conexión a las reglas de firewall en cuestión.

-A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
-A INPUT -m conntrack --ctstate NEW -m udp -p udp --dport 500 -j ACCEPT
-A INPUT -m conntrack --ctstate NEW -m udp -p udp --dport 4500 -j ACCEPT

O para sistemas Linux más antiguos (por ejemplo, RHEL 5 y anteriores):

-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -m state --state NEW -m udp -p udp --dport 500 -j ACCEPT
-A INPUT -m state --state NEW -m udp -p udp --dport 4500 -j ACCEPT
Michael Hampton
fuente