La situación es así:
http client ----> corporate firewall ----> http server
Debido a una actividad activa, el servidor y el cliente mantendrían abiertas las conexiones TCP y el cliente usaría un grupo de conexiones para las solicitudes HTTP.
El firewall tiene una regla para "matar" conexiones TCP de larga data después de 1 hora. El problema es que nuestro cliente HTTP no detectaría que la conexión TCP fue destruida y trató de reutilizar conexiones esencialmente inactivas que, por nuestro lado, parecían "colgadas" después de un período de tiempo. Se colgaría una solicitud, luego la siguiente funcionaría, presumiblemente porque se estableció una nueva conexión.
La pregunta aquí es cuál es el mecanismo con el que el firewall está matando las conexiones TCP de una manera que nuestro cliente HTTP no pudo detectarlas. Traté de reproducir este comportamiento localmente de varias maneras:
- Elimine las conexiones TCP en nuestro enrutador vyos, Wireshark en el lado del cliente capturó TCP FIN-ACK. Okay
- Eliminar la conexión TCP del lado del cliente en TCPView en Windows, Wireshark detectó TCP RST en el lado del cliente. Okay
- Bloquear el puerto después de la conexión establecida con el firewall del lado del cliente, resultó en una excepción de reinicio del socket. Okay
Tengo un volcado de Wireshark en el lado del servidor y traté de encontrar si el firewall envía un FIN o RST ip.dst==serverip && (tcp.flags.reset==1 || tcp.flags.fin==1)
pero no apareció nada.
Además, la captura de Wireshark en el lado del cliente muestra el problema cuando se cierra la solicitud HTTP, seguida de una docena de retransmisiones TCP, que finalmente no van a ninguna parte.
El cliente HTTP es un cliente Java nativo y / o Jetty HTTP (probó ambos), ambos no pudieron detectar una conexión TCP inactiva. Me gustaría reproducir el comportamiento localmente, pero no puedo entender de qué manera dudosa el cortafuegos está matando las conexiones, por lo tanto, buscando posibles respuestas.
Respuestas:
No mencionas el tipo de firewall, pero sospecho que la mayoría simplemente descarta los paquetes.
Lo que tendería a confirmar esto.
fuente
Lo más probable es que el firewall haya descartado el paquete sin enviar un paquete RST, probablemente después de alcanzar un valor de tiempo de espera de sesión de algún tipo. Este es típicamente un comportamiento configurable.
Personalmente prefiero que se envíe ese paquete RST precisamente porque ayuda a los clientes a comportarse normalmente, pero he escuchado argumentos en el sentido de que esto no debería hacerse en firewalls externos para evitar proporcionar cualquier tipo de retroalimentación a los posibles atacantes.
He visto que esto causa bastantes problemas porque los clientes generalmente no manejan este tipo de escenario con mucha elegancia. Esencialmente, siguen intentando de nuevo a través de la sesión TCP original (que ahora está muerta) y nunca intentan restablecer una nueva. Finalmente, se activa un tiempo de espera del lado del cliente y el usuario recibe un mensaje de error desagradable. Configurar HTTP keepalive adecuadamente para la aplicación puede ayudar a solucionar esto.
fuente
@Ron Trunk es exactamente correcto, casi con certeza la conexión abierta se cae de forma activa (se niega la regla insertada) o de forma pasiva (se elimina de las conexiones conocidas y no se permite volver a crear sin una sincronización). Uno de los comentarios sugirió probarlo usted mismo. Aquí hay una receta para hacerlo utilizando espacios de nombres de red de Linux. Se supone que el reenvío de IP está habilitado en el kernel de su host, usted es root y probablemente otras cosas.
Luego necesita tres ventanas / conchas / pantallas / terminales. Ejecute cada comando a continuación en un terminal distinto:
ip netns exec three socat TCP-LISTEN:5001 STDIO
ip netns exec one socat STDIO TCP:3.3.3.3:5001
Tenga en cuenta que después de ejecutar estos comandos, todo lo que escriba en una ventana se reflejará en la otra, y viceversa (después de presionar regresar). Si eso no es cierto, es posible que deba habilitar el reenvío de IP.
ip netns exec two iptables -I FORWARD -j DROP
Entonces, nada de lo que escriba se permitirá.
Puede simular un método de descarte menos activo con reglas de reenvío (no probadas) como:
Ver /unix/127081/conntrack-tcp-timeout-for-state-stablished-not-working y https://www.kernel.org/doc/Documentation/networking/nf_conntrack-sysctl .txt para obtener información sobre cómo ajustar los tiempos de espera, aunque no me queda claro que iptables admite de forma nativa una vida útil de conexión máxima; Creo que todos los tiempos de espera son tiempos de inactividad.
Limpiar con
ip netns del one; ip netns del two; ip netns del three
fuente
El cortafuegos puede enviar un paquete ICMP que indica que no se pudo alcanzar el objetivo. Para cualquier cosa que no sea TCP, esa es la única indicación de error posible, por ejemplo, enviar un paquete a un puerto UDP cerrado generará un mensaje de "destino inalcanzable" con el código de razón establecido en "puerto inalcanzable".
También es posible enviar mensajes de "puerto inalcanzable" como respuesta a los paquetes TCP, esto también termina la conexión, pero cualquiera que analice los volcados de paquetes notará que esto es inusual, porque la convención TCP es indicar puertos cerrados con un RST.
Se espera que el remitente asigne los paquetes de error ICMP recibidos de nuevo a la conexión de origen y los maneje adecuadamente, de modo que un paquete de error generado por el firewall también se pueda usar para terminar una conexión TCP. El paquete ICMP contiene una copia de los encabezados del paquete ofensivo para permitir esta asignación.
fuente