El túnel se cae, el kill switch se activa y una descarga que estaba terminada en tres cuartas partes o se congela o falla de inmediato. Esos dos resultados provienen de decisiones de aplicación distintas, no de distintos niveles de protección. Un paquete descartado deja la conexión esperando, mientras que uno rechazado la cierra y avisa a la aplicación. Decidir qué comportamiento quiere es una cuestión de diseño, y probarlo es un ejercicio aparte.

Descartado, rechazado y reiniciado son cosas distintas

Una regla de cortafuegos que descarta el tráfico tira el paquete y no devuelve nada, así que el emisor sigue retransmitiendo con sus propios temporizadores. Una regla que rechaza con un reset TCP cierra la conexión de inmediato y la aplicación ve un error. La mayoría de los kill switch descartan, porque un rechazo revelaría la política y porque descartar se parece a cómo se comporta una red muerta.

Bloquear tampoco es lo mismo que cerrar el socket. La aplicación sigue teniendo un descriptor en estado establecido y solo faltan los paquetes. Por eso una página puede quedarse en un indicador de carga durante minutos mientras el sistema operativo insiste en que la conexión existe. Lea la aplicación documentada de la política en lugar de deducirla del mensaje de la aplicación, ya que ambos comportamientos parecen una red caída.

Qué hace la aplicación mientras dura el hueco

TCP retransmite con retardos crecientes, y el presupuesto de reintentos predeterminado de Linux caduca más o menos a un cuarto de hora, no en segundos. Hasta entonces el socket no está ni útilmente abierto ni cerrado. Las aplicaciones con sus propios keepalive o tiempos de espera de solicitud suelen rendirse antes, por eso dos programas en la misma máquina se comportan de forma distinta durante una caída.

Cuando el túnel vuelve, el socket local no ha cambiado, pero la ruta puede que sí. Una nueva dirección de origen pública produce una tupla distinta en el servidor, así que un cortafuegos con estado del otro lado ya no coincide con la sesión. La conexión está muerta aunque el cliente nunca vio un error.

Decida si la recuperación es obligatoria

Elija entre dos contratos. O la sesión debe sobrevivir a un hueco breve, lo que exige direccionamiento estable y un servidor que conserve su estado, o la aplicación debe reconectarse limpiamente, lo que exige lógica de reintento segura para repetir. Cualquier cosa intermedia produce el peor resultado: un cliente que reenvía lo que el servidor ya confirmó, o uno que informa de un éxito para una sesión que nadie puede ver.

El direccionamiento estable es la parte que la gente olvida, porque una reconexión que aterriza en una dirección pública distinta invalida el estado del lado del servidor incluso cuando el socket del cliente parece sano. Anote qué contrato de los dos se aplica a cada aplicación, ya que rara vez coinciden todos.

Pruebe el bloqueo y la recuperación por separado

Trate la protección contra fugas y la supervivencia de la sesión como dos propiedades, porque pasar una no dice nada de la otra. Una sesión que sobrevive no prueba que se bloqueó el tráfico directo, y una sesión que muere no prueba que se bloqueara cada ruta directa.

ss -tnp state established '( dport = :443 )'
sudo conntrack -L -p tcp --dport 443
sudo tcpdump -ni any 'tcp port 443 and tcp[tcpflags] & tcp-syn != 0'

Use una operación de prueba inofensiva al observar la recuperación, para que un envío duplicado no se convierta en el incidente. Anote el modo de fallo que realmente vio: qué mostró la aplicación, si el socket sobrevivió y cuándo se recuperó por sí solo.

Escriba el comportamiento esperado junto a la regla de aplicación y fíjele una fecha. La siguiente persona que cambie esa regla necesita saber cuál de los dos contratos prometió el despliegue.

Artículos relacionados