netfiletr和iptables的状态和连接跟踪机制

Como se lleva a cabo el rastreo de conexiones o connection tracking en netfilter/iptables ? Como funcionan los estados de una conexión ? Como funciona la tabla conntrack ? Como se enlaza con el firewall para conseguir un stateful firewall ? Estado inválido , eso que es?

Estas son algunas de las preguntas que solemos hacernos (yo al menos me las hice) cuando queremos aprender a configurar un firewall basado en netfilter/iptables como es el caso del firewall de Vyatta .


Gracias a Netfilter el kernel de Linux mantiene un rastreo de todas las conexiones (connection tracking o conntrack ), se puede ver en los archivos /proc/net/ip_conntrack y /proc/net/nf_conntrack y se le llama máquina de estados o máquina de rastreo de conexiones (state machine o connection tracking machine), es una parte especial dentro de iptables y es lo que permite al framework Netfilter saber el estado de una conexión específica y lo que posibilita definir políticas de filtrado (firewall ) basadas en el estado de conexión de los paquetes así como el funcionamiento de los servicios NAT y WAN load balancing en el caso de Vyatta .

La fuente clave para esta publicación es el tutorial de iptables de Oskar Andreasson traducido al español por Xavier Bartol, de donde he copiado muchas de las partes de esta entrada y otras las he adaptado tratando de relacionarlo siempre con el funcionamiento del modulo conntrack en Vyatta. Si comparas esta entrada con el manual traducido por Xavier Bartol podrás ver que al principio he comenzado a hacer la traducción del original debido a que no había encontrado antes el trabajo de Xavier, una vez descubierto me limito a copiarlo y a añadir notas referentes a Vyatta ya que es muy completo y esta perfectamente redactado.



Flujo de paquetes en Netfilter:


netfilter-iptables-packet-flow


Componentes de Netfilter:





En iptables los paquetes pueden relacionarse a conexiones rastreadas en cuatro estados diferentes conocidos como NEW , ESTABLISHED , RELATED e INVALID . Todo el rastreo de paquetes se lleva a cabo por un framework del kernel llamado conntrack que puede cargarse como modulo o como parte interna del propio kernel. A su vez esta formado por partes más específicas de conntrack que manejan los protocolos TCP, UDP o ICMP entre otros y almacenan información única y específica de los paquetes con lo que mantienen rastreo de cada stream de datos. Esta información reunida por conntrack se usa para saber en que estado se encuentra cada stream de datos.

Todo el rastreo de conexiones se lleva a cabo por la cadena PREROUTING y la cadena OUTPUT, los paquetes que se generan localmente son manejados por la cadena OUTPUT y el resto por la cadena PREROUTING. Cuando el primer paquete de un stream de datos se genera localmente el rastreo de ese stream se pone en estado NEW en la cadena OUTPUT y una vez se recibe un paquete de vuelta referente al mismo stream se cambia su estado a ESTABLISHED en la cadena PREROUTING. Si por el contrario el primer paquete de un stream se origina desde fuera la cadena PREROUTING almacenará su estado como NEW, con lo que todos los cambios de estado y los cálculos se hacen en las cadenas PREROUTING y OUTPUT de la tabla NAT.

Las entradas de conntrack



Si echamos un vistazo a algunas entradas de conntrack en /proc/net/ip_conntrack , la base de datos de conntrack si tenemos el modulo conntrack cargado, tendrán un formato como este:

udp      17 2 src=192.168.1.5 dst=80.58.32.97 sport=30719 dport=53 packets=1 bytes=73 src=80.58.32.97 dst=xx.xx.xx.xx sport=53 dport=30719 packets=1 bytes=132 mark=0 secmark=0 use=2
tcp      6 431271 ESTABLISHED src=192.168.2.15 dst=192.168.2.1 sport=1052 dport=22 packets=64 bytes=8682 src=192.168.2.1 dst=192.168.2.15 sport=22 dport=1052 packets=66 bytes=27000 [ASSURED] mark=0 secmark=0 use=2
unknown  89 597 src=10.251.1.1 dst=224.0.0.5 packets=5326 bytes=461952 [UNREPLIED] src=224.0.0.5 dst=10.251.1.1 packets=0 bytes=0 mark=0 secmark=0 use=2
tcp   6 117 SYN_SENT src=192.168.1.6 dst=192.168.1.9 sport=32775 dport=22 [UNREPLIED] src=192.168.1.9 dst=192.168.1.6 sport=22 dport=32775 [ASSURED] use=2


Nota: en este caso dst=xx.xx.xx.xx equivale a la IP publica desda la que salgo a internet.


Estas entradas de ejemplo contienen toda la información que el modulo conntrack mantiene para saber en que estado se encuentra una conexión específica. En primer lugar tenemos el protocolo. Después su valor en codificación decimal. El tiempo de vida en segundos de la entrada en la tabla de conntrack, este valor irá disminuyendo hasta que no se vuelva a ver tráfico perteneciente a ese stream de datos y se volverá a poner a su valor por defecto para el estado específico en el que esté en el momento que se reciba tráfico referente a ese stream de datos. Seguidamente viene el estado actual en el que se encuentra el stream de datos al que se refiere la entrada.
Por ejemplo, en la última entrada mostrada arriba se está a la espera de un paquete con flags SYN_SENT activados. El valor interno de una conexión es ligeramente diferente al que se usa externamente por iptables. El valor SYN_SENT nos informa de que estamos buscando una conexión que solo haya visto un paquete TCP SYN en una dirección. Después tenemos la dirección IP de origen del stream, la dirección de destino, el puerto origen, el puerto de destino y el número de paquetes y de bytes correspondientes a ese stream de datos. Después, si nos seguimos centrando en la última entrada de la lista de arriba veremos la palabra clave [UNREPLIED] que nos dice que no se ha visto aun tráfico de vuelta para este tipo de conexión. Finalmente tenemos la información que se espera ver en los paquetes de retorno, dirección IP de origen y destino (invertidas de como estaban al principio ya que será tráfico de vuelta) y lo mismo con lo puertos de origen y destino. En este punto conviene destacar la primera entrada en la que la respuesta al stream se espera a una dirección IP diferente, en este caso es debido a que el tráfico se redirige por otra interfaz de la máquina, se realiza un SNAT y será por donde se reciba.


Las entradas de rastreo de conexiones tomarán un valor entre una serie de diferentes valores que se especifican en los ficheros de cabecera de conntrack, localizados en la ruta linux/include/netfilter-ipv4/ip_conntrack*.h y que dependen del subprotocolo IP que se use. Los protocolos TCP, UDP e ICMP toman valores especificados por defecto en linux/include/netfilter-ipv4/ip_conntrack.h . Ésto lo veremos con más detalle un poco más adelante cuando se definan cada uno de los protocolos.

También, dependiendo de como cambie este estado, el valor por defecto del tiempo hasta que la conexión se destruya también cambiará.

Cuando para una conexión se haya detectado tráfico en las dos direcciones se borrará en la respectiva entrada de conntrack la etiqueta [UNREPLIED] y se reseteará la entrada.

La entrada que nos indica que la conexión no ha visto tráfico en ambas direcciones será reemplazada por la etiqueta [ASSURED] que aparecerá cerca del final de la entrada. La etiqueta [ASSURED] indica que la conexión esta asegurada y que no será borrada si se alcanza el máximo posible de conexiones rastreadas. El número de conexiones que la tabla de rastreo puede manejar depende de una variable configurable por medio de la función ip-sysctl en kernels recientes. El valor por defecto depende enormemente de la cantidad de memoria que tenga el sistema, esta configuración puede verse en el archivo /proc/sys/net/ipv4/ip_conntrack_max , en Vyatta el valor por defecto de máximo número de entradas en la tabla conntrack es 32768 y los ficheros de configuración que contienen este valor son /proc/sys/net/ipv4/netfilter/ip_conntrack_max y /proc/sys/net/netfilter/nf_conntrack_max .


Una forma diferente y más eficiente de hacerlo es configurando la opción del tamaño de hash al modulo ip_conntrack una vez este cargado. En circunstancias normales la fórmula ip_conntrack_max = 8 * tamaño de hash suele ser bastante adecuada. Por ejemplo, si configuramos el tamaño de hash a 4096 el tamaño correspondiente al valor de ip_conntrack_max según la fórmula es 32768 y puede configurarse así:

work3:/home/blueflux# modprobe ip_conntrack hashsize=4096
work3:/home/blueflux# cat /proc/sys/net/ipv4/ip_conntrack_max 32768
work3:/home/blueflux#



Nota: Desde hace poco hay un nuevo parche en el “patch-o-matic” de iptables llamado “tcp-window-tracking” . Este parche añade, entre otras cosas, todos los tiempos límite mencionados a variables especiales del “sysctl”, con lo que se pueden cambiar (los tiempos) al instante, mientras el sistema está en marcha. Gracias a esto ya no es necesario recompilar el núcleo cada vez que se deseen cambiar los límites de los contadores de tiempo. Estos límites se pueden modificar utilizando llamadas al sistema específicas que se encuentran disponibles en el directorio /proc/sys/net/ipv4/netfilter . Concretamente debes buscar las variables /proc/sys/net/ipv4/netfilter/ip_ct_* .
En Vyatta no podemos aplicar este parche, al menos de forma fácil, un poco más adelante hablaremos del tema de configuración de tiempos de conntrack en Vyatta



Venido al caso, cabe destacar que estos valores de conntrack en Vyatta pueden modificarse, pero no son persistentes ante reinicio, para modificarlos de forma persistente hay que hacerlo desde CLI con los comandos:

set firewall conntrack-expect-table-size x
set firewall conntrack-hash-size x
set firewall conntrack-table-size y


En caso de querer cambiar los valores de la tabla conntrack en Vyatta es más que recomendable tener primero en cuenta la cantidad de RAM de que dispone el sistema y después leer detenidamente las secciones reservadas a los comandos anteriores en el documento de firewall disponible en la sección de documentos de Vyatta

Los estados del espacio de usuario



Como hemos visto, los paquetes pueden tomar varios estados diferentes dentro del propio kernel dependiendo del protocolo tratado. Sin embargo, fuera del kernel, en el espacio disponible para el usuario, solo tenemos los 4 estados descritos antes. Estos estados pueden ser usados principalmente para la búsqueda de paquetes basada en su estado de rastreo actual. Los estados válidos son NEW, ESTABLISHED, RELATED e INVALID.

La siguiente tabla explica brevemente cada posible estado:

EstadoDescripccion
NEWEl estado NEW (nuevo) nos indica que el paquete es el primero que vemos. Esto significa que el primer paquete que el módulo conntrack vea en una conexión será etiquetado de esta manera. Por ejemplo, si vemos un paquete SYN que además es el primero de una conexión, coincidirá con el criterio del conntrack y será etiquetado como NEW. Sin embargo, el primer paquete puede que no sea un paquete SYN y aún así ser considerado como NEW. Este comportamiento puede llevar a determinados problemas en determinados casos, pero también puede ser extremadamente útil si necesitamos captar conexiones perdidas de otros firewalls, o si una conexión ha excedido su tiempo de espera, pero en realidad no ha sido cerrada.
ESTABLISHEDEl estado “ESTABLISHED” (establecido) ha visto tráfico en ambas direcciones y por tanto admitirá continuamente los paquetes de ese flujo. Las conexiones “establecidas” son bastante fáciles de comprender: el único requisito para alcanzar el estado “ESTABLISHED” es que un host envíe un paquete y obtenga una respuesta del otro host. El estado “NEW” (nuevo) cambiará al estado “establecido” en cuanto llegue un paquete de respuesta al cortafuegos (o cuando este paquete pase por el cortafuegos). Los mensajes de error ICMP, las redirecciones… también se pueden considerar como “ESTABLISHED”, si hemos enviado un paquete que a su vez genera el mensaje de error ICMP.
RELATEDEl estado “RELATED” (relacionado) es uno de los más complejos. Una conexión se considera “relacionada” cuando está ligada a otra conexión ya “establecida”. Por este motivo, para que una conexión se considere en estado “RELATED” primero debemos tener otra conexión en estado “ESTABLISHED”: la conexión “establecida” generará una conexión externa a la conexión principal, y esta nueva conexión será considerada como “relacionada” siempre que el módulo conntrack pueda entender que está relacionada con la principal. Un buen ejemplo: las conexiones FTP-data son consideradas como relacionadas con el puerto de control FTP (FTP control); otro ejemplo son las conexiones DCC generadas con el IRC. Puede utilizarse para permitir las respuestas ICMP, las transferencias FTP y los DCCs (protocolos de conexión Directa de Cliente a Cliente) a través del cortafuegos. Ten en cuenta que muchos protocolos TCP (además de algunos UDP) que dependen de este mecanismo son bastante complejos y envían información de la conexión conjuntamente con la carga de datos de los segmentos TCP o UDP, por lo que requieren de módulos de ayuda especiales para ser correctamente interpretados.
INVALIDEl estado “INVALID” (inválido) implica que el paquete no puede ser identificado o que no tiene ningún estado. Ésto puede ser debido a varias razones, como que el sistema se ha quedado sin memoria disponible, o a mensajes ICMP de error que no responden a ninguna conexión conocida. Normalmente es una buena idea eliminar (DROP) todo aquello que se encuentre en este estado. Puede ocurrir también que una conexión se establezca con estado invalido si se supera el tiempo de espera para que el flujo de datos al que corresponde y por consiguiente se elimina ese flujo de la tabla conntrack antes de que realmente haya terminado, este puede ser el caso de paquetes FIN-ACK que lleguen tarde.



Los anteriores estados pueden usarse conjuntamente con la comparación –state (en Vyatta set state ) para diferenciar paquetes en función de su estado en el seguimiento de conexiones. Ésto es lo que hace que la máquina de estados sea tan increíblemente fuerte y eficiente para nuestro cortafuegos. En el pasado, frecuentemente nos veíamos obligados a abrir todos los puertos por encima del 1024 para permitir el tráfico de retorno a nuestra red local. Con la máquina de estados funcionando ya no es necesario, pues podemos abrir el cortafuegos sólo para el tráfico de retorno, no para todo tipo de tráfico.

  • Conexiones TCP



En esta sección y las siguientes vamos a repasar en profundidad los estados y como son gestionados para cada uno de los tres protocolos básicos: TCP, UDP e ICMP.
Asimismo, veremos como se gestionan por defecto las conexiones si no se pueden incluir en ninguno de los anteriores protocolos. Empezaremos con el protocolo TCP, ya que es un protocolo de “flujos” en si mismo (stateful protocol: como ya se ha explicado en la introducción , “stateful” implicaría que todos los paquetes de un mismo flujo son considerados como la misma cosa, como un todo que llega “en porciones”); además contiene muchos detalles interesantes respecto a la máquina de estados en iptables.


Una conexión TCP siempre se inicia con el “apretón de manos en tres pasos” (3-way handshake), que establece y negocia la conexión sobre la que se enviarán los datos. La sesión entera se inicia con un paquete SYN, seguido por un paquete SYN-ACK y finalmente por un paquete ACK, para confirmar el establecimiento de la sesión (1-”hola, ¿quieres hablar conmigo?”, 2-”de acuerdo”, 3-”bien, pues empecemos”). En este momento la conexión se establece y está preparada para empezar a enviar datos. El gran problema es: ¿cómo maneja el seguimiento de
conexiones todo este tráfico? En realidad de una forma bastante simple.


Al menos en lo que concierne al usuario, el seguimiento de conexiones trabaja más o menos de la misma manera para todo tipo de conexiones. Échale un vistazo al gráfico de abajo para ver exactamente en que estado entra el flujo durante las diferentes fases de la conexión. Como puedes observar, desde el punto de vista del usuario el código del seguimiento de conexiones realmente no acompaña al flujo de la conexión TCP. Una vez ha visto un paquete (el SYN), considera la conexión como nueva (NEW). En cuanto ve el paquete de retorno (SYN/ACK), considera la conexión como establecida (ESTABLISHED). Si piensas en ello un momento, entenderás por qué: con esta particular forma de trabajar puedes permitir a los paquetes NEW y ESTABLISHED que abandonen tu red local, pero permitiendo únicamente a las conexiones ESTABLISHED que vuelvan a la red local y funcionen correctamente. Por el contrario, si la máquina de seguimiento de conexiones tuviera que considerar todo establecimiento de conexión como NEW, no seríamos capaces de detener los intentos de conexión desde el exterior hacia nuestra red local, puesto que tendríamos que permitir el retorno de todos los paquetes NEW. Para complicarlo todo un poco más, existen varios estados internos más dentro del núcleo que se usan para las conexiones TCP, pero que no están disponibles en el espacio de usuario. Básicamente siguen los estándares de estados especificados en RFC 793 – Protocolo de Control de Transmisiones , páginas 21-23 (en inglés). Los tendremos en cuenta un poco más adelante en esta misma sección.

conexiones_TCP_conntrack_1



Como puedes ver, desde el punto de vista del usuario es bastante simple. Sin embargo, desde el punto de vista del núcleo el esquema es un poco más complejo. Veamos un ejemplo que ilustra a la perfección cómo cambian los estados de la conexión en la tabla /proc/net/ip_conntrack. El primer estado es registrado a la recepción del primer paquete SYN de una conexión.

tcp      6 117 SYN_SENT src=192.168.1.5 dst=192.168.1.35 sport=1031 dport=23 [UNREPLIED] src=192.168.1.35 dst=192.168.1.5 sport=23 dport=1031 use=1



Como puedes ver en la entrada anterior, tenemos un estado concreto en el cual un paquete SYN ha sido enviado (se establece la bandera SYN_SENT) y que todavía no ha recibido ninguna respuesta (de ahí la bandera [UNREPLIED]). El siguiente estado interno se alcanzará cuando se vea un paquete en la otra dirección.

tcp      6 57 SYN_RECV src=192.168.1.5 dst=192.168.1.35 sport=1031 dport=23 src=192.168.1.35 dst=192.168.1.5 sport=23 dport=1031 use=1



En este caso hemos recibido el correspondiente paquete SYN/ACK como respuesta. En cuanto llega, el estado cambia una vez más, esta vez a SYN_RECV: indica que el paquete SYN original llegó correctamente y que el paquete SYN/ACK de retorno también ha atravesado correctamente el cortafuegos. Además, esta entrada del seguimiento de conexiones ya ha visto tráfico en
ambas direcciones y por ello se considera que ha obtenido respuesta. Este hecho no es explícito, pero se considera asumido de la misma forma que ocurría con la bandera [UNREPLIED] anterior. El último paso se dará cuando veamos el paquete ACK final del “apretón de manos” (3-way handshake).

tcp      6 431999 ESTABLISHED src=192.168.1.5 dst=192.168.1.35 sport=1031 dport=23 src=192.168.1.35 dst=192.168.1.5 sport=23 dport=1031 use=1



En este último ejemplo ya hemos visto el paquete ACK final y la conexión ha entrado en el estado ESTABLISHED (establecida), al menos hasta donde llega el control de los mecanismos internos de iptables. Después de unos pocos paquetes más, la conexión se convertirá en [ASSURED] (“asegurada”), tal como se ha mostrado en la introducción del capítulo.

Cuando una conexión TCP se cierra, lo hace de la siguiente manera y tomando los siguientes estados:

conexiones_TCP_conntrack_2



Como puedes ver, en realidad la conexión nunca se cierra hasta que se envía el último paquete ACK. Ten en cuenta que este gráfico sólo muestra cómo se cierra una conexión en circunstancias normales. También puede cerrarse enviando un paquete RST (“reset”, reiniciar) si la conexión se tiene que rechazar. En este caso la conexión será cerrada tras un periodo de tiempo predeterminado.


En condiciones normales, cuando una conexión TCP se cierra, entra en el estado TIME_WAIT (“tiempo de espera”), que por defecto es de 2 minutos. Este lapso de tiempo se emplea para que todos los paquetes que se han quedado “atascados” de alguna manera puedan atravesar igualmente el conjunto de reglas, incluso después de que la conexión se haya cerrado; de esta forma
se dispone de una especie de “buffer”/colchón de tiempo para que los paquetes que se han quedado parados en algún enrutador congestionado, puedan llegar al cortafuegos o al otro extremo de la conexión sin problemas.


Si la conexión se reinicia por un paquete RST, el estado cambia a CLOSE (“cerrar”). Esta orden implica que la conexión por defecto dispone de 10 segundos antes de que se cierre definitivamente. Los paquetes RST no piden consentimiento de ninguna clase y cortan la conexión directamente.


También hay otros estados además de los que ya se han comentado. A continuación tienes la lista completa de los posibles estados que puede tomar un flujo TCP y sus tiempos límite.

Estado Tiempo limite
NONE30 minutos
ESTABLISHED5 dí­as
SYN_SENT2 minutos
SYN_RECV60 segundos
FIN_WAIT2 minutos
TIME_WAIT2 minutos
CLOSE10 segundos
CLOSE_WAIT12 horas
LAST_ACK30 segundos
LISTEN2 minutos



Estos tiempos no son de ninguna manera definitivos, ya que pueden cambiar con las revisiones del núcleo, además de poderse cambiar a través del sistema de ficheros proc mediante las variables /proc/sys/net/ipv4/netfilter/ip_ct_tcp_*. Sin embargo, en la práctica los valores por defecto deberían estar bastante bien definidos. Los tiempos se indican en “jiffies” (centésimas de segundo), es decir, 3000 significa 30 segundos.

Nota:Ten en cuenta que la parte del espacio de usuario de la máquina de estados no se fija en las banderas TCP establecidas en los paquetes TCP. Hacer eso normalmente es una mala idea, ya que puedes querer permitir que los paquetes en el estado NEW puedan atravesar el cortafuegos, pero cuando específicas la bandera NEW lo que en la mayoría de las ocasiones quieres
permitir son los paquetes SYN.

En la implementación actual de los estados no ocurre esto, ya que incluso un paquete sin ningún valor establecido o sin una bandera ACK, se considerará como NEW. Este tipo de comparación puede ser útil en sistemas con cortafuegos redundantes, pero en general es una malísima idea en tu red personal, dónde sólo tienes un cortafuegos. Para evitar este comportamiento puedes usar el comando explicado en la sección Paquetes cuyo estado es NEW pero cuyo bit SYN no se ha establecido del apéndice Problemas y preguntas frecuentes . Otra forma de conseguirlo es instalando la extensión tcp-window-tracking que encontrarás en el patch-o-matic, que permitirá que el cortafuegos sea capaz de hacer el seguimiento de los estados en función de las configuraciones de las ventanas TCP.

En Vyatta la gestión de tiempos es algo diferente, posiblemente la diferencia esté en la versión a la que se refiere el manual objetivo y la versión actual de Netfilter incluida en Vyatta. En Vyatta los valores de timeout de conntrack se encuentran en la ruta /proc/sys/net/netfilter/ almacenados en diferentes ficheros con nombre específico.
Podemos listar dichos ficheros con el siguiente comando:

openredes@vyatta:~$ sudo find /proc/ -iname *nf_conntrack*timeout*
/proc/sys/net/netfilter/nf_conntrack_generic_timeout
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_syn_sent
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_syn_recv
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_fin_wait
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_close_wait
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_last_ack
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_time_wait
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_close
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_max_retrans
/proc/sys/net/netfilter/nf_conntrack_udp_timeout
/proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream
/proc/sys/net/netfilter/nf_conntrack_icmp_timeout
openredes@vyatta:~$



Podemos también listar los archivos de configuración de timeouts en conntrack y mostrar su valor (segundos) con el comando:

openredes@vyatta:~$ sudo find /proc/ -iname *nf_conntrack*timeout*  | xargs grep .
/proc/sys/net/netfilter/nf_conntrack_generic_timeout:600
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_syn_sent:120
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_syn_recv:60
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established:432000
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_fin_wait:120
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_close_wait:60
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_last_ack:30
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_time_wait:120
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_close:10
/proc/sys/net/netfilter/nf_conntrack_tcp_timeout_max_retrans:300
/proc/sys/net/netfilter/nf_conntrack_udp_timeout:30
/proc/sys/net/netfilter/nf_conntrack_udp_timeout_stream:180
/proc/sys/net/netfilter/nf_conntrack_icmp_timeout:30
openredes@vyatta:~$



Se pueden ajustar (como root) los valores anteriores con el comando “echo [segundos] > [file] “. Por ejemplo, para disminuir el timeout de conexiones TCP establecidas a dos horas:

vyatta:~# echo 7200 > /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established
vyatta:~# cat /proc/sys/net/netfilter/nf_conntrack_tcp_timeout_established
7200



El problema es que estos cambios no son persistentes y se modificarán a su valor por defecto en cada reinicio de la máquina Vyatta. Para hacer los cambios persistentes se podría añadir el comando anterior, que modifique el valor que queramos, en el script de arranque /etc/rc.local .

  • Conexiones UDP



Las conexiones UDP son en sí mismas “conexiones sin flujo”. Existen varias razones para ello, principalmente porque no implican ningún establecimiento o cierre de conexión; más que nada les falta algún tipo de secuenciamiento: recibir dos datagramas UDP en un orden específico no dice nada acerca del orden en que fueron enviados. Sin embargo es posible establecer
estados en las conexiones dentro del núcleo. Veamos cómo se puede seguir una conexión y cómo podría verse en el conntrack.

conexiones_UDP_conntrack_iptables



Como puedes observar, desde el punto de vista del espacio de usuario la conexión se inicia casi exactamente de la misma forma que una conexión TCP. Internamente, sin embargo, la información del conntrack es bastante diferente, pero intrínsecamente los detalles son los mismos. Para empezar, veamos la entrada tras haber enviado el paquete UDP inicial.

udp      17 20 src=192.168.1.2 dst=192.168.1.5 sport=137 dport=1025 [UNREPLIED] src=192.168.1.5 dst=192.168.1.2 sport=1025 dport=137 use=1



Como puedes ver en los dos primeros valores, se trata de un paquete UDP. El primer valor es el nombre del protocolo, mientras que el segundo es el número del protocolo. Es lo mismo que se encuentra en las conexiones TCP. El tercer valor indica el “tiempo de vida” en segundos que le queda a esta entrada de estado. Tras esto vienen los valores de origen y destino del
paquete que hemos visto, la bandera [UNREPLIED], que nos indica que hasta el momento no ha habido respuesta al paquete, y por fin un listado de los valores que se esperan en los paquetes de respuesta. Estos últimos valores son los mismos que antes pero en sentido inverso. El tiempo de vida (“timeout”) por defecto es de 30 segundos.

udp      17 170 src=192.168.1.2 dst=192.168.1.5 sport=137 dport=1025 src=192.168.1.5 dst=192.168.1.2 sport=1025 dport=137 use=1



En este ejemplo el servidor ya ha visto una respuesta al paquete inicial y la conexión se considera ESTABLISHED (establecida). Este detalle no se muestra en el seguimiento de conexiones, como puedes ver. La diferencia principal es la ausencia de la bandera [UNREPLIED]. Además el tiempo de vida por defecto ha cambiado a 180 segundos: en el ejemplo ya han pasado 10 segundos y por eso el valor es 170; en diez segundos más el valor disminuirá a 160 y así hasta que se agote el tiempo. Sin embargo, hay un detalle que se ha visto antes y que ahora falta: la bandera [ASSURED]. Para que se establezca esta bandera en el seguimiento de conexiones, debe haber habido un mínimo de tráfico en la conexión.

udp      17 175 src=192.168.1.5 dst=195.22.79.2 sport=1025 dport=53 src=195.22.79.2 dst=192.168.1.5 sport=53 dport=1025 [ASSURED] use=1



En este momento la conexión ya está asegurada. Este ejemplo parece exactamente igual que el anterior, excepto por la bandera [ASSURED]. Si la conexión no es utilizada en 180 segundos, entonces caduca. Este tiempo (180 segundos) es un valor relativamente bajo, pero debería ser suficiente para la mayoría de los casos. Cada vez que un paquete coincide con los valores
indicados en el paquete inicial (los valores que se esperan de los paquetes de respuesta ya comentados antes) y atraviesa el cortafuegos, el contador vuelve al valor por defecto, igual que ocurre con el resto de estados internos.

  • Conexiones ICMP



Los paquetes ICMP no pueden estar más lejos de ser conexiones de flujo (o “stateful connections”), ya que sólo se usan para el control de las conexiones y nunca deberían establecer ninguna conexión por sí mismos. Sin embargo, hay cuatro tipos ICMP que generarán paquetes de retorno y que presentan 2 estados diferentes: estos mensajes ICMP pueden tomar los estados NEW (nuevo) y ESTABLISHED (establecido). Los tipos ICMP de los que hablamos son: Echo request (petición de eco) y su reply (respuesta o Echo reply), Timestamp request (petición de “marca de tiempo”, el valor del momento exacto en que se envía el paquete) y su reply, Information request (petición de información) y su reply, y por último Address mask request (petición de máscara de subred) y su reply. De éstos, los tipos timestamp request e information request están obsoletos y lo más probable es que simplemente se puedan desechar. Sin embargo, los mensajes de Echo se emplean en varias configuraciones, como hacer “pings” a los hosts. Las peticiones de máscara de subred (Address mask requests) no se suelen utilizar,
pero pueden ser útiles en ocasiones y vale la pena permitirles que atraviesen el cortafuegos. Para tener una idea de cómo funciona una conexión de este tipo, veamos la siguiente imagen:

conexiones_ICMP_conntrack_iptables_1



Como puedes observar, el host envía una petición de eco (echo request) al destinatario y el cortafuegos considera el paquete como nuevo (NEW). El destinatario responde con una respuesta de eco (echo reply) que el cortafuegos considera mediante el estado “establecido” (ESTABLISHED). Cuando ya se ha visto la primera petición de eco, se crea la siguiente entrada en el ip_conntrack.

icmp     1 25 src=192.168.1.6 dst=192.168.1.10 type=8 code=0 id=33029 [UNREPLIED] src=192.168.1.10 dst=192.168.1.6 type=0 code=0 id=33029 use=1



Como ya te habrás dado cuenta, esta entrada es un poco diferente a las entradas estándar para los paquetes TCP y UDP. Vemos el protocolo, su número, el tiempo de vida que le queda a la entrada, así como las direcciones de origen y destino. La diferencia viene después: tenemos 3 campos nuevos llamados type (tipo), code (código) e id (identidad/identificación). En realidad no son nada especiales: el valor type indica el tipo ICMP y el valor code indica el código ICMP. Todos ellos están disponibles en el apéndice Tipos ICMP . El valor de id indica
el ICMP ID: cada paquete ICMP toma un valor ID (de identificación) cuando se envía y al responder el receptor también establece este mismo ID; de esta forma al llegar la respuesta al host que envió la petición se puede unir esa respuesta a la petición ICMP correcta.

En el siguiente campo volvemos a encontrar la bandera [UNREPLIED] que hemos visto anteriormente. Como entonces, la entrada del seguimiento de conexiones que estamos viendo implica que sólo se ha visto tráfico en una dirección. Por último vemos los datos que se esperan en el paquete de respuesta ICMP, que obviamente son los valores iniciales pero invertidos. Por lo que respecta al tipo y al código, se cambian por los valores adecuados al paquete de retorno, de forma que una petición de eco se transforma en una respuesta de eco, etc. El ICMP ID,
lógicamente, se mantiene idéntico al paquete de petición.

El paquete de respuesta se considera como ESTABLISHED, tal como ya se ha explicado. Sin embargo, sabemos con seguridad que tras la respuesta ICMP no habrá absolutamente ningún tráfico legal en la misma conexión. Por esta razón la entrada del seguimiento de conexiones es destruida en cuanto la respuesta ha atravesado la estructura de Netfilter.

En cada uno de los casos anteriores la petición se considera como nueva (NEW), mientras que la respuesta se considera como establecida (ESTABLISHED). Más exactamente, cuando el cortafuegos ve un paquete de petición lo considera como nuevo, mientras que cuando el host envía un paquete de respuesta a la petición, se considera como establecido.


Nota: Ésto implica que el paquete de respuesta debe seguir el criterio fijado en la entrada del seguimiento de conexiones, para poder ser considerado como establecido, de la misma manera que ocurre en el resto de tipos de tráfico.

Las peticiones ICMP tienen un tiempo de vida por defecto de 30 segundos, que puedes cambiar en la entrada /proc/sys/net/ipv4/netfilter/ip_ct_icmp_timeout. En general este es un buen valor, ya que permitirá captar la mayoría de paquetes en tránsito.

Otra parte importantísima de ICMP es el hecho de que se emplea para indicarle a los hosts qué ha pasado con las conexiones UDP y TCP o con los intentos de conexión. Por este motivo las respuestas ICMP muy a menudo serán reconocidas como relacionadas (RELATED) con conexiones o intentos de conexión. Un ejemplo sencillo sería el de los mensajes ICMP Host unreachable (mensaje de host inalcanzable, no se puede llegar al host) e ICMP Network unreachable (mensaje de red inalcanzable, no se puede llegar hasta la red). Este tipo de mensajes se envían automáticamente de vuelta a nuestro host cuando el paquete no consigue efectuar la conexión con un host porque la red o el host de destino están fuera de servicio, de manera que el último enrutador (router) que intente conectar con el destino nos contestará con un mensaje ICMP diciéndonos lo que ocurre. En este caso la respuesta ICMP se considera como un paquete relacionado (RELATED). El siguiente gráfico debería aclarar lo que ocurre:

conexiones_ICMP_conntrack_iptables_2



En el ejemplo enviamos un paquete SYN a una dirección concreta: ésto es considerado como una nueva conexión (NEW) por el cortafuegos. Sin embargo no se puede llegar a la red a la que se está intentando enviar el paquete, por lo que un router (el último) nos devuelve un error ICMP de red inalcanzable. El código de seguimiento de conexiones puede reconocer este
paquete como relacionado (RELATED) gracias a la entrada ya existente, por lo que la respuesta ICMP es correctamente enviada al cliente que generó el paquete inicial y, si todo va bien, éste abortará la conexión. Mientras tanto el cortafuegos ya habrá eliminado la entrada del seguimiento de conexiones, puesto que sabe que se trata de un mensaje de error.

El mismo comportamiento se experimenta con las conexiones UDP si tienen problemas como en el caso anterior. Todo mensaje ICMP devuelto como respuesta a conexiones UDP es considerado como relacionado (RELATED). Observa el siguiente gráfico:

conexiones_ICMP_conntrack_iptables_3



En esta ocasión se envía un paquete UDP al host. Esta conexión UDP se considera como nueva NEW. Sin embargo la red está prohibida administrativamente por algún cortafuegos o router antes de llegar a destino y por ello nuestro cortafuegos recibe un mensaje ICMP Network Prohibited (red prohibida). El cortafuegos sabe que este mensaje ICMP de error está relacionado
con la conexión UDP abierta y lo envía como un paquete RELATED (relacionado) al cliente. Acto seguido, elimina la entrada del seguimiento de conexiones mientras el cliente recibe el mensaje y aborta la conexión.

  • Conexiones por defecto



En algunos casos el conntrack no sabe cómo gestionar un protocolo específico, bien sea porque no conoce el protocolo o porque no sabe cómo funciona. En estos casos sigue un comportamiento por defecto, como ocurre por ejemplo con NETBLT, MUX y EGP. El procedimiento seguido es básicamente el mismo que en el seguimiento de las conexiones UDP: el primer paquete se considera como nuevo (NEW) y el tráfico de respuesta y subsiguiente es considerado como establecido (ESTABLISHED).

Cuando se emplea el comportamiento por defecto todos los paquetes afectados tendrán el mismo “tiempo de vida” (timeout) por defecto, que se puede establecer a través de la variable /proc/sys/net/ipv4/netfilter/ip_ct_generic_timeout. El valor por defecto es de 600 segundos (10 minutos). En función del tipo de tráfico que estés intentando enviar a través de un enlace que utilice este comportamiento por defecto, es posible que necesites cambiarlo, especialmente si estás conectado a través de satélite o algo similar, pues la comunicación
puede llegar a tardar bastante tiempo.

  • Los protocolos complejos y el seguimiento de conexiones



Determinados protocolos son más complejos que otros, lo cual implica que a la hora de realizar el seguimiento de conexiones el trabajo será más difícil. Buenos ejemplos de ello son los protocolos ICQ, IRC y FTP. Cada uno de ellos incluye información dentro del bloque de datos de los paquetes, por lo que para funcionar correctamente requieren de asistentes especiales para el seguimiento de conexiones.

Empecemos por ejemplo con el protocolo FTP. Este protocolo comienza abriendo una única conexión llamada sesión “FTP control” (sesión de control ftp). En cuanto enviamos comandos a través de esta sesión, se abren otros puertos para transportar el resto de datos relacionados con esos comandos. Estas conexiones se pueden crear de dos maneras: activamente o pasivamente. Cuando una conexión se genera activamente, el cliente FTP envía al servidor un puerto y una dirección IP a los que conectarse. Tras esto el cliente FTP abre el puerto indicado y el servidor conecta con él desde su propio puerto 20 (conocido como “FTP-Data”), enviando datos a través de él.

El problema radica en que el cortafuegos no tiene conocimiento de esas conexiones extras, ya que son negociadas a través del bloque de datos que transporta el paquete (lo que se conoce como “payload” o carga de información; recordemos que a groso modo un paquete IP tiene una cabecera con información sobre la conexión y un bloque de datos que es lo que desea el host que lo recibe). Debido a ésto el cortafuegos no será capaz de saber que debería dejar conectarse al servidor con el cliente a través de estos puertos concretos.

La solución al problema pasa por añadir un asistente especial al módulo del seguimiento de conexiones, que escaneará los datos de la conexión de control para detectar sintaxis e información específicas: cuando encuentre la información adecuada, la añadirá en una nueva entrada etiquetada como relacionada (RELATED) y gracias a esta nueva entrada el servidor ya
será capaz de efectuar un seguimiento de la conexión. Observa la siguiente imagen para entender los estados cuando el servidor FTP ya ha creado la conexión con el cliente.

conexiones_complejas_conntrack_iptables_1



El ftp pasivo (“Passive FTP”) funciona completamente a la inversa: el cliente FTP le indica al servidor que quiere determinados datos, a lo que el servidor responde con una dirección IP y un puerto a los que conectarse. Tras recibir estos datos, el cliente se conectará a ese puerto desde su propio puerto 20 (el puerto FTP-data) y cogerá los datos en cuestión. Si
tienes un servidor FTP tras tu cortafuegos, necesitarás de este módulo además de los módulos estándar de iptables para permitir que los clientes desde Internet puedan conectar correctamente con tu servidor FTP. De igual forma necesitarás el módulo si eres extremadamente restrictivo con tus usuarios y sólo quieres dejar que utilicen servidores HTTP y FTP de Internet, bloqueando cualquier otro puerto. Observa la siguiente imagen y su relación con el ftp pasivo (“Passive FTP”).

conexiones_complejas_conntrack_iptables_2



Algunos asistentes del conntrack ya están disponibles en el núcleo, más concretamente, en el momento de escribir estas líneas los protocolos FTP e IRC ya disponen de estos asistentes. Si no puedes encontrar en el núcleo los asistentes que necesitas, debes echar un vistazo al patch-o-matic, en la sección de zona de usuario de iptables: podrás encontrar más asistentes
del conntrack, como es el caso de los protocolos ntalk o H.323. Si no están disponibles en el patch-o-matic, todavía dispones de algunas opciones más, como el CVS (“Concurrent Versioning System”) de iptables, si recientemente ha entrado en él. O también puedes ponerte en contacto con la lista de correo Netfilter-devel y preguntar si está disponible. Si no lo está y no está planeado añadirlo, te quedas solo y lo más probable es que quieras leer el “COMO” de Rusty Russell: Rusty Russell’s Unreliable Netfilter Hacking HOW-TO (en inglés), del cual tienes un enlace en el apéndice Otras fuentes y enlaces .

Los asistentes del conntrack pueden ser compilados estáticamente o como módulos en el núcleo. Si se compilan como módulos puedes cargarlos con el siguiente comando:

modprobe ip_conntrack_ftp
modprobe ip_conntrack_irc
modprobe ip_conntrack_tftp
modprobe ip_conntrack_amanda



Ten en cuenta que el seguimiento de conexiones no tiene nada que ver con la traducción de direcciones (NAT), por lo que es posible que necesites más módulos si también estás “NATeando” (traduciendo) las conexiones. Por ejemplo, si quisieras traducir las direcciones y realizar un seguimiento de las conexiones FTP, necesitarías también el módulo NAT. Todos los asistentes NAT tienen el mismo prefijo en su nombre: “ip_nat_”, seguido por el nombre del asistente en cuestión. Por ejemplo, el asistente para FTP con NAT (traducción de direcciones) se llamará ip_nat_ftp y el módulo IRC se llamará ip_nat_irc. Los asistentes del conntrack siguen la misma regla de nomenclatura, por lo que el asistente del conntrack para IRC se llamará ip_conntrack_irc, mientras que el asistente para FTP será ip_conntrack_ftp.

Fuentes:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值