¿Por qué nuestro firewall (Ubuntu 8.04) rechaza el paquete final (FIN, ACK, PSH) con un RST


20

Antecedentes, durante mucho tiempo hemos tenido problemas con nuestro firewall que a veces mantiene las solicitudes HTTP colgadas parcialmente cargadas hasta que TCP agota el tiempo de espera.

Después de rastrear el tráfico en el firewall, noté que ocurre solo durante ciertas condiciones de tiempo, por ejemplo, cuando el servidor web ha enviado la respuesta completa antes de que el cliente haya enviado su segundo ACK en la carga útil. Se ha intercambiado [SYN, SYN / ACK, ACK], se ha enviado SOLICITUD y ACK'ed y se recibió el primer paquete de RESPUESTA y ACK'ed, luego el servidor web envía el resto del cuerpo de respuesta de una sola vez (8 paquetes incluyendo el último FIN, PSH) y antes de que el cliente haya ACEPTADO ninguno de ellos, el Firewall RECHAZA con un RST hacia el servidor web y mantiene al cliente colgando infinito.

Aquí está todo el rastro de Wirehark con paquetes de ambos lados del firewall. 192.168.126.161 es la dirección IP privada de NAT'et del cliente. 172.16.1.2 es la IP del servidor web (no muestra la IP pública real) y 10.1.1.1 es la IP externa del firewall (no muestra la IP pública real)

2105 0.086275 192.168.126.161  172.16.1.2       TCP 37854 > http [SYN] Seq=0 Win=5840 Len=0 MSS=1460 SACK_PERM=1 TSV=89375083 TSER=0
2106 0.000066 10.1.1.1         172.16.1.2       TCP 37854 > http [SYN] Seq=0 Win=5840 Len=0 MSS=1460 SACK_PERM=1 TSV=89375083 TSER=0
2107 0.002643 172.16.1.2       10.1.1.1         TCP http > 37854 [SYN, ACK] Seq=0 Ack=1 Win=32768 Len=0 MSS=1460
2108 0.007705 172.16.1.2       192.168.126.161  TCP http > 37854 [SYN, ACK] Seq=0 Ack=1 Win=32768 Len=0 MSS=1460
2109 0.006301 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=1 Ack=1 Win=5840 Len=0
2110 0.000025 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=1 Ack=1 Win=5840 Len=0
2111 0.000007 192.168.126.161  172.16.1.2       HTTP GET /test/style.css HTTP/1.1 
2112 0.000015 10.1.1.1         172.16.1.2       HTTP GET /test/style.css HTTP/1.1 
2113 0.001536 172.16.1.2       10.1.1.1         TCP http > 37854 [ACK] Seq=1 Ack=111 Win=32658 Len=0
2114 0.000014 172.16.1.2       192.168.126.161  TCP http > 37854 [ACK] Seq=1 Ack=111 Win=32658 Len=0
2115 0.002274 172.16.1.2       10.1.1.1         HTTP HTTP/1.1 200 OK  (text/css)
2116 0.000025 172.16.1.2       192.168.126.161  HTTP HTTP/1.1 200 OK  (text/css)
2117 0.005689 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=1461 Win=8760 Len=0
2118 0.000024 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=1461 Win=8760 Len=0
2119 0.001536 172.16.1.2       10.1.1.1         HTTP Continuation or non-HTTP traffic
2120 0.000026 172.16.1.2       192.168.126.161  HTTP Continuation or non-HTTP traffic
2121 0.000007 172.16.1.2       10.1.1.1         HTTP Continuation or non-HTTP traffic
2122 0.000023 172.16.1.2       192.168.126.161  HTTP Continuation or non-HTTP traffic
2123 0.000313 172.16.1.2       10.1.1.1         HTTP Continuation or non-HTTP traffic
2124 0.000030 172.16.1.2       192.168.126.161  HTTP Continuation or non-HTTP traffic
2125 0.000007 172.16.1.2       10.1.1.1         HTTP Continuation or non-HTTP traffic
2126 0.000023 172.16.1.2       192.168.126.161  HTTP Continuation or non-HTTP traffic
2127 0.000009 172.16.1.2       10.1.1.1         HTTP Continuation or non-HTTP traffic
2128 0.000023 172.16.1.2       192.168.126.161  HTTP Continuation or non-HTTP traffic
2129 0.001108 172.16.1.2       10.1.1.1         HTTP Continuation or non-HTTP traffic
2130 0.000035 172.16.1.2       192.168.126.161  HTTP Continuation or non-HTTP traffic
2131 0.000008 172.16.1.2       10.1.1.1         HTTP Continuation or non-HTTP traffic
2132 0.000022 172.16.1.2       192.168.126.161  HTTP Continuation or non-HTTP traffic
2133 0.000007 172.16.1.2       10.1.1.1         HTTP Continuation or non-HTTP traffic
REJECT-->
2134 0.000089 10.1.1.1         172.16.1.2       TCP 37854 > http [RST] Seq=111 Win=0 Len=0
CLIENT FIRST ACK-->
2135 0.002421 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=2921 Win=11680 Len=0
2136 0.000033 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=2921 Win=11680 Len=0
2137 0.000007 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=4381 Win=14600 Len=0
2138 0.000014 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=4381 Win=14600 Len=0
2139 0.000008 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=5841 Win=17520 Len=0
2140 0.000014 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=5841 Win=17520 Len=0
2141 0.000007 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=7301 Win=20440 Len=0
2142 0.000013 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=7301 Win=20440 Len=0
2143 0.000007 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=8761 Win=23360 Len=0
2144 0.000015 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=8761 Win=23360 Len=0
2145 0.000007 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=10221 Win=26280 Len=0
2146 0.000013 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=10221 Win=26280 Len=0
2147 0.001059 192.168.126.161  172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=11681 Win=29200 Len=0
2148 0.000018 10.1.1.1         172.16.1.2       TCP 37854 > http [ACK] Seq=111 Ack=11681 Win=29200 Len=0

He estado cavando y registrando el recorrido del paquete de acuerdo con este cuadro y parece que el último paquete entrante 2133 pasa de PREROUTING, conntrack, mangle-PREROUTING, pero luego se pierde. No tengo reglas de RECHAZO en mis iptables, registro todas las reglas de DROP y ninguna de ellas muestra dónde se pierde el paquete 2133.

Me encantaría usar el objetivo TRACE en el filtro entrante, pero desafortunadamente ubuntu 8.04 no se envía con soporte para el objetivo TRACE.

Por lo tanto, creo que se aplican algunas reglas internas implícitas de enrutamiento / seguimiento / manipulación que, por algún motivo, restablecen la conexión. Tal vez el tráfico desencadena alguna protección de DOS, pero no tengo idea de dónde configurarlo / analizarlo. Lo más frustrante es que se rechaza un paquete y no se registra nada ...

También solicitar este archivo funciona al 100% desde los hosts de Windows, pero falla en ciertos hosts de Linux y el 99.9% de todas las solicitudes se procesan, pero a veces la sincronización de los paquetes desencadena este comportamiento en nuestro firewall.

EDITAR Ok, ahora he agregado toneladas de inicio de sesión en iptables y parece que sucede lo siguiente (¡todavía no sé por qué!)

Para los paquetes que atraviesan con éxito el firewall, se toman los siguientes pasos, referencias de tabla / paso desde aquí

Table 3-3 step

2     raw-pre
      conntrack
3     mangle-pre
4     [nat-pre]
5     routing-decision -> destination forward
6     mangle-fwd
7     filter-fwd
8     mangle-post
9     [nat-post]

El paquete 2133 que se rechaza atraviesa estos pasos:

Table 3-1 steps for the incoming FIN,ACK packet 2133
2     raw-pre
      conntrack
3     mangle-pre
4     [nat-pre]
5     routing-decision -> destination local
6     mangle-input
7     filter-input
8     local process emits RST -> webserver

Table 3-2 steps for the outgoing RST packet 2134 in response to 2133
1     raw-out
2     routing decision
      conntrack
3     mangle-out
      reroute-check
4     [nat-out]
5     filter-out
6     mangle-post
7     nat-post

Lo extraño es que la decisión de enrutamiento para el paquete 2133 en el paso 5 ahora es diferente a la decisión de enrutamiento para los otros paquetes. Al analizar solicitudes que funcionan, por ejemplo, no se atasca, incluso el último FIN se enruta correctamente. Parece un error en el kernel o que la decisión de enrutamiento tiene estado de alguna manera.

EDITAR

Una cosa que podría causar estos problemas es el siguiente hecho: el tráfico se enruta entre el firewall y la LAN local, por lo que la LAN del cliente no está directamente conectada al firewall a través de L2.

                +---------------------------+       +------------------+                         +------------------------+
                |                           |       |      Router      |   (   Lab network    )  |                        |
( Internet ) -- + eth1                 eth0 +-------+                  +-- (                  ) -+ Client 192.168.126.161 |
                | 10.1.1.1   192.168.60.254 |       |                  |   ( 192.168.126.0/24 )  |                        |
                +---------------------------+       +------------------+                         +------------------------+

En esta imagen, 10.1.1.1 representa la dirección IP externa del firewall, todas las demás direcciones son las direcciones IP reales utilizadas.

Aquí está la tabla de enrutamiento en el firewall:

Destination     Gateway         Genmask         Flags Metric Ref    Use Iface
10.1.1.0        0.0.0.0         255.255.255.240 U     0      0        0 eth1
192.168.126.0   0.0.0.0         255.255.255.0   U     0      0        0 eth0
192.168.60.0    0.0.0.0         255.255.255.0   U     0      0        0 eth0
0.0.0.0         10.1.1.15       0.0.0.0         UG    0      0        0 eth1

Tenga en cuenta que 10.1.1.0 y gw por defecto 10.1.1.15 están compuestos, el resto es exactamente el mismo que se usó. Tuve que agregar manualmente la ruta 192.168.126.0/24 para llegar a la red del laboratorio desde eth0 (192.168.60.254).

Aquí hay algunos registros extensos en el recorrido del paquete para el último paquete 2133 que se rechaza debido a que se enruta al host local (por ejemplo, el firewall).

[16406874.374588] raw pre IN=eth1 OUT= MAC=00:02:b3:b9:ff:b5:00:90:1a:10:06:88:08:00 SRC=172.16.1.2 DST=10.1.1.1 LEN=1004 TOS=0x00 PREC=0x00 TTL=55 ID=13739 DF PROTO=TCP SPT=80 DPT=53497 WINDOW=5840 RES=0x00 ACK PSH FIN URGP=0 
[16406874.374625] mangle pre IN=eth1 OUT= MAC=00:02:b3:b9:ff:b5:00:90:1a:10:06:88:08:00 SRC=172.16.1.2 DST=10.1.1.1 LEN=1004 TOS=0x00 PREC=0x00 TTL=55 ID=13739 DF PROTO=TCP SPT=80 DPT=53497 WINDOW=5840 RES=0x00 ACK PSH FIN URGP=0 
[16406874.374667] mangle in IN=eth1 OUT= MAC=00:02:b3:b9:ff:b5:00:90:1a:10:06:88:08:00 SRC=172.16.1.2 DST=10.1.1.1 LEN=1004 TOS=0x00 PREC=0x00 TTL=55 ID=13739 DF PROTO=TCP SPT=80 DPT=53497 WINDOW=5840 RES=0x00 ACK PSH FIN URGP=0 
[16406874.374699] filter in IN=eth1 OUT= MAC=00:02:b3:b9:ff:b5:00:90:1a:10:06:88:08:00 SRC=172.16.1.2 DST=10.1.1.1 LEN=1004 TOS=0x00 PREC=0x00 TTL=55 ID=13739 DF PROTO=TCP SPT=80 DPT=53497 WINDOW=5840 RES=0x00 ACK PSH FIN URGP=0 
[16406874.374780] mangle out IN= OUT=eth1 SRC=10.1.1.1 DST=172.16.1.2 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=53497 DPT=80 WINDOW=0 RES=0x00 RST URGP=0 
[16406874.374807] mangle post IN= OUT=eth1 SRC=10.1.1.1 DST=172.16.1.2 LEN=40 TOS=0x00 PREC=0x00 TTL=64 ID=0 DF PROTO=TCP SPT=53497 DPT=80 WINDOW=0 RES=0x00 RST URGP=0 
[16406874.378813] mangle pre IN=eth0 OUT= MAC=00:02:b3:b9:ff:b4:00:90:1a:10:0c:dd:08:00 SRC=192.168.126.161 DST=172.16.1.2 LEN=40 TOS=0x00 PREC=0x00 TTL=63 ID=35424 DF PROTO=TCP SPT=53497 DPT=80 WINDOW=11680 RES=0x00 ACK URGP=0 
[16406874.378863] mangle fwd IN=eth0 OUT=eth1 SRC=192.168.126.161 DST=172.16.1.2 LEN=40 TOS=0x00 PREC=0x00 TTL=62 ID=35424 DF PROTO=TCP SPT=53497 DPT=80 WINDOW=11680 RES=0x00 ACK URGP=0 

Una vez más, nuestra IP externa fw ha sido reemplazada por 10.1.1.1 y la ip del servidor web fuera de la red NAT se reemplaza por 172.16.1.2

EDITAR noticias de última hora!

Ok, el último intento fue DROP el paquete RST, muy, muy interesante, agregué una regla de iptables que eliminó todos los paquetes RST destinados al servidor web del que tenemos problemas para solicitar archivos. Y luego funcionó, por ejemplo, el último paquete FIN, ACK, PSH 2133 en el registro anterior se descartó, pero dado que se eliminó el RST, el servidor web tiene tiempo para obtener todas las hormigas ACK y luego decide retransmitir el último paquete, el paquete 2133 una vez más, y ahora pasa a través del cortafuegos ya que el módulo contrack ahora ha visto regresar ACK del cliente y permite el último paquete ACK, FIN con la carga útil final.

Entonces, definitivamente es un problema de tiempo / ventana, este archivo en particular, con el tiempo de los ACK del cliente, desencadena algo en conntrack que rechaza el paquete final del servidor web.

Hasta ahora, buscar en Google y leer los documentos de Kernel no revela nada que pueda causar este comportamiento, el siguiente paso será leer el código fuente del kernel para el módulo de enrutamiento / conntrack.

PROBLEMA RESUELTO

Bueno, al menos ahora sabemos exactamente qué sucede y tenemos una solución alternativa que resuelve el problema.

Sergey señaló el muy valioso estado -m: regla de coincidencia INVALIDA de estado que ayudó mucho en la depuración, ahora me doy cuenta de que una configuración de iptables sin una regla explícita para paquetes INVÁLIDOS no está completa, por lo que a veces parece que ocurre un comportamiento extraño.

Al habilitar el inicio de sesión en el módulo conntrack por lo que causa el paquete no válido, lo que sucede es bastante obvio y sospeché sobre esto.

[16659529.322465] nf_ct_tcp: SEQ is over the upper bound (over the window of the receiver) IN= OUT= SRC=172.16.1.2 DST=10.1.1.1 LEN=1004 TOS=0x00 PREC=0x00 TTL=55 ID=40874 DF PROTO=TCP SPT=80 DPT=55498 SEQ=658735108 ACK=1194081763 WINDOW=5840 RES=0x00 ACK PSH FIN URGP=0 

Una vez más, 172.16.1.2 es el servidor web externo (que se comporta incorrectamente) y 10.1.1.1 es la dirección externa del firewall.

El servidor web empuja más datos a través del cable de lo que el cliente ha anunciado en la ventana de recepción (conntrack está lleno de estado y lo verifica), parece que es cuando llega el paquete FIN que el conntrack se rescata, ya que la ventana de recepción se ha excedido mucho más temprano.

Creo que podría deberse a una descarga TCP incorrecta en la tarjeta de red en el servidor web. Cuando comencé a analizar esto, tomé capturas en el servidor web y, de acuerdo con las trazas tcpdump / wireshark, los marcos jumbo fueron escritos por la capa TCP en el núcleo, que luego fue segmentada en marcos más pequeños con MTU = 1500 por la tarjeta de red. Obviamente, esto debe abordarse en el servidor web, ya que no es correcto el comportamiento de TCP para enviar más datos de los que el receptor tiene anuncios en su ventana de recepción.

Tanto Polynomial como Sergey proporcionaron información valiosa, pero Sergey me señaló el comportamiento exacto del módulo conntrack / NAT con respecto al recorrido de paquetes.


¿Tiene alguna declaración de RECHAZO en su configuración de iptables? Si es así, vea si puede usar el registro para descubrir qué regla es.
Ladadadada

No, sin rechazar reglas parece que el rechazo que ocurre fuera de ella iptablesm sucede durante la decisión de enrutamiento
ernelli

¿Es posible que el firewall no sea compatible con ventanas deslizantes? ¿Cómo se compara una captura de un cliente que trabaja con este?
joeqwerty

Cuando funciona, además de que todos los paquetes se reenvían correctamente al cliente y no se devuelven paquetes RST, el cliente envía ACK antes del FIN final desde el servidor. He examinado un volcado de un archivo grande (300k) y luego no hay problemas. También funciona un rastro de un archivo pequeño, se reenvía el paquete final con FIN. ¿Puede usted explicar en mayor detalle "cortafuegos no soporta ventanas correderas"
ernelli

¿Puede ampliar la conexión entre el enrutador y el cliente de laboratorio? Tiene / 24 máscaras de red en los 60 y 126, por lo que no está claro cómo los clientes de laboratorio pueden enviar tráfico. ¿Su máscara de red no es un / 24? ¿Hay algún tipo de arp proxy? ¿Hay un alias en eth0: 1 para 126.0 / 24?
polinomio

Respuestas:


9

Una situación similar se describe en http://www.spinics.net/lists/netfilter/msg51408.html : algunos paquetes que deberían haber sido procesados ​​por NAT de alguna manera se marcaron como NO VÁLIDOS en lugar de ESTABLECER, y fueron a la cadena de ENTRADA. Debería agregar algunas reglas -m state --state INVALIDpara verificar esto, y la respuesta en http://www.spinics.net/lists/netfilter/msg51409.html sugiere que dicho paquete NO VÁLIDO siempre debe DEJARSE, porque NAT no se realiza en ellos correctamente , por lo tanto, las direcciones en ellos pueden estar equivocadas.

Si sus paquetes problemáticos están realmente marcados como NO VÁLIDOS, la adición iptables -I INPUT -m state --state INVALID -j DROPprobablemente solucionará el problema (el paquete roto no llegará al proceso local y no causará la respuesta RST, entonces TCP se recuperará del paquete perdido después de un tiempo de espera). Luego puede intentar depurar el problema aún más, como se describe en http://www.spinics.net/lists/netfilter/msg51411.html :

echo 255 >/proc/sys/net/netfilter/nf_conntrack_log_invalid

(En ese caso particular, el problema fue causado por un hardware de red roto en el camino, probablemente combinado con alguna falla de descarga de suma de verificación TCP).


4

He visto este comportamiento en otros tipos de firewall y el comportamiento fue tan idéntico que pensé que lo lanzaría allí.

El problema que tuve fue que el cortafuegos estaba NAT 'en el mismo espacio que los puertos efímeros en la caja. Esto causaría este comportamiento exacto si los dos chocaran porque el núcleo ahora suponía que la conexión era para la máquina local. Para este fin, hay un par de cosas que puede verificar. Primero, ¿está especificando la configuración del puerto de salida en iptables (usando --to-ports)? O ha modificado el rango de puertos efímero en la máquina:

$ cat /proc/sys/net/ipv4/ip_local_port_range

Para diagnosticar, puede configurar su captura y ver si ve alguna otra solicitud usando el mismo combo externo de puerto fw ip, dentro del tiempo de 3 * MSL antes del RST (~ 180s, creo).

Si bien aún no estoy seguro de que esa sea la respuesta, si estuviera en esta situación, lo descartaría primero y luego vería un par de otras cosas.

¿Es esto fácil de reproducir? ¿Es posible capturar más diagnósticos desde la caja del firewall y ver cómo ocurre el problema? Intentaría capturar:

$ netstat -anp
$ cat /proc/net/ip_conntrack

cada segundo más o menos mientras intenta reproducir y ver si hay algo vinculante localmente al puerto y cómo se veía la tabla de disfraces durante el problema.

Si corta el firewall en la salida RST, ¿el ACK eventual del cliente interno hace que la conexión sea exitosa?

Lo último, ¿estás viendo todos los registros? ¿Ya has revisado dmesg? ¿Ha configurado *. * En el cuadro de firewall en la configuración de syslog en un archivo para asegurarse?

¡Déjame saber lo que encuentres! Realmente aprecio la cantidad de información que proporcionó en la pregunta, gracias.


Gracias por su esfuerzo, puedo reproducir el error al 100%, todas las solicitudes a través del firewall funcionan, excepto muy pocas. Aquellos que no trabajan parecen tener un problema de tamaño / sincronización precisa. Puedo agregar múltiples trazas de Wireshark para solicitudes más grandes / más pequeñas entre el mismo cliente / servidor web a través del firewall que funciona, pero la traza anterior es la que se atasca. He agregado nueva información arriba que podría indicar algo sobre el problema.
ernelli

/ proc / sys / net / ipv4 / ip_local_port_range se establece en [32768 61000] netstat no muestra ningún puerto vinculado localmente. ip_conntrack muestra la conexión establecida, por ejemplo, cree que aún está abierta ya que el último FIN no se ha reenviado al cliente. El estado es paquetes = 10 bytes = 12084 [ASEGURADO] marca = 0 segmark = 0 uso = 1
ernelli
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.