CGNAT y cómo evitar la caducidad de sesiones con conexiones de larga duración

Es sabido por todos que las direcciones IPv4 se están agotando en todo el planeta. Hace tiempo que son un recurso escaso y caro.

Ante esa perspectiva, los ISPs tienen dos opciones:

  • Migrar a IPv6 o, en el caso de operadores móviles de nueva creación, desplegar desde un primer momento IPv6 de forma nativa.

    Esta sería la opción recomendable, pero todavía hoy existen equipos de red con soporte IPv6 mediocre. Un problema aún mayor es que la mayor parte de los servicios disponibles en internet siguen prestándose exclusivamente a través de IPv4.

    Es decir, aunque la red del operador sea IPv6 nativa, casi todo su tráfico tendrá que pasar a través de conversores IPv4 <-> IPv6.

  • Dado el último párrafo, otra posibilidad es colocar toda la red del ISP detrás de sistemas NAT de escala masiva, los llamados Carrier-grade NAT (CGNAT). Un proveedor con millones de usuarios podría conectar a internet a través de un pequeño número de direcciones IP tipo IPv4.

    Ni que decir tiene que esta es la opción común en los ISPs en España.

No voy a a hablar aquí de las implicaciones de seguridad, privacidad y libertad que supone el uso de CGNAT. Afortunadamente los ISPs con los que trabajo permiten sacar tu conexión doméstica del CGNAT con una simple llamada telefónica. Naturalmente el 99.9% de los usuarios no lo harán, pero, siendo realistas, la mayoría de ellos ni lo notan ni lo necesitan.

Por descontado, en casa he pedido que se me quite del CGNAT y mi ISP no me ha puesto pegas. El problema está cuando viajo.

Un CGNAT tiene el concepto de sesión, asociando una dirección IP y puerto internos a una dirección IP y puerto externos. Esa asociación es lo que proporciona el NAT y lo que permite disociar las direcciones IP internas de la red del ISP con el pequeño conjunto de direcciones IP públicas disponibles.

Normalmente esta asociación se mantiene mientras la conexión no se cierre, pero es un hecho de la vida que los datagramas se pueden perder o uno de los extremos puede desaparecer de forma abrupta sin dejar rastro, así que el CGNAT no puede permitirse mantener sesiones vivas en su memoria RAM de forma indefinida (sería también un excelente vector de ataque), así que todos los CGNAT eliminan sesiones de forma rápida si la conexión asociada no tiene actividad tras un cierto número de minutos.

Esta actividad de limpieza no tiene efectos perniciosos para la mayoría de los usuarios. Casi todas las conexiones son cortas y las conexiones largas están "vivas" y tienen actividad constante.

En mi caso, el problema son las conexiones SSH: Son de muy larga duración y pueden tener muy poco tráfico, incluso inactividad completa durante horas.

Los síntomas son fáciles de reconocer: todo funciona perfectamente hasta que una de mis conexiones SSH se queda "clavada" tras ciertos minutos de inactividad. Cortando esa conexión y estableciendo una nueva, todo funciona con normalidad hasta que la conexión SSH vuelve a estar inactiva cierto tiempo. Si la conexión tiene actividad, aunque sea poca, no hay problema.

El diagnóstico es evidente: las conexiones SSH inactivas pierden su sesión en el CGNAT. Se quedan huérfanas y son incapaces de comunicarse en ninguno de los dos sentidos.

La solución es evidente también, puedes elegir una de estas dos opciones:

  • Solicitar que el ISP retire nuestro contrato de datos del sistema CGNAT. Sería la opción más recomendable, pero puede que haya ISPs que nos pongan pegas o se nieguen. En mi caso lo habitual es que esté utilizando una conexión de la que no soy titular y, por tanto, no tengo autoridad para pedir nada el ISP.
  • Puedo generar tráfico en la conexión SSH, de forma pequeña pero frecuente, para evitar que la sesión CGNAT caduque. Esta es la solución más práctica.

Existen dos formas simples de generar un pequeño tráfico de fondo en las conexiones SSH:

  • Activar en la configuración SSH parámetros como ServerAliveInterval, ServerAliveCountMax en el cliente, y/o ClientAliveCountMax, ClientAliveInterval en el servidor.
  • El protocolo TCP soporta "keep alive" que son pequeños datagramas enviados de forma periódica cuando una conexión TCP no tiene actividad de por sí. Si no se recibe respuesta a esos datagramas "keep alive", la conexión se considera rota.

Nos sirve cualquiera de las dos opciones. Yo suelo emplear la segunda porque me parece más simple y porque cubre todo el tráfico TCP de mi ordenador, independientemente de que sea SSH o no.

Si utilizas un sistema operativo como Linux, puedes hacer lo siguiente (otros sistemas operativos tienen capacidades similares):

jcea@jcea:~$ sudo bash
[sudo] password for jcea:
root@jcea:~# echo 100 >/proc/sys/net/ipv4/tcp_keepalive_time

El último comando generará un datagrama "keep alive" para cualquier conexión TCP del sistema que haya estado inactiva durante 100 segundos.

Ese pequeño tráfico es suficiente para mantener vivas nuestras sesiones en el CGNAT.

Nota

En mi sistema operativo el valor por defecto de ese parámetro es 7200 segundos. Es decir, dos horas. Claramente un valor demasiado alto.

No me he puesto a hacer experimentos para determinar el tiempo de caducidad de sesiones de los CGNAT que me he encontrado por ahí. Doy por hecho que cada uno será diferente y que cualquier valor que obtenga quedará anticuado en cuanto el ISP actualice equipos o si el ISP emplea equipos diferentes en su red (muy sabio por su parte).

Nota

En vez de ejecutar este comando a mano, lo suyo sería vincularlo a conexiones WIFI concretas. Tema para el futuro.