Cómo entender el mecanismo de seguimiento de conexiones
¿Por qué necesitas nuevamente el seguimiento de la conexión? Porque es la base para implementar firewalls con estado y NAT.
Neftiler desarrolló el seguimiento de conexiones como un mecanismo para implementar firewalls con estado y traducción de direcciones NAT basadas en la detección del estado de la conexión de datos. Esto significa que si el kernel se compila con el seguimiento de conexiones activado, el sistema Linux mantendrá un estado de conexión para cada paquete recibido para registrar el estado de la conexión de datos. A continuación, veremos cómo se diseña e implementa el seguimiento de conexiones de Netfilter.
En la figura anterior, podemos ver claramente que la prioridad más alta utilizada para implementar la función de enlace de entrada de seguimiento de conexión se registra en los dos puntos de enlace de NF_IP_PRE_ROUTING y NF_IP_LOCAL_OUT de netfitler respectivamente; salida de seguimiento de conexión La prioridad extremadamente baja de la función de enlace se registra en los dos puntos de enlace de NF_IP_PRE_ROUTING y NF_IP_LOCAL_OUT de netfitler respectivamente.
De hecho, las funciones de salida de conexión con prioridad extremadamente baja están registradas en los dos puntos de enlace de netfilter: NF_IP_PRE_ROUTING y NF_IP_LOCAL_OUT.
De hecho, PRE_ROUTING y LOCAL_OUT pueden considerarse como los puntos de entrada de todo el netfilter, mientras que POST_ROUTING y LOCAL_IN pueden considerarse como sus puntos de salida. Cuando solo se considera el seguimiento de la conexión, un paquete de datos no debe pasar por más de los siguientes tres procesos:
Paquete de datos enviado a la computadora local
Proceso: PRE_ROUTING--. --LOCAL_IN --- Proceso local, si es un nuevo paquete de datos, el registro de conexión se genera en PREROUTING y se agrega a la tabla hash después de pasar POSTROUTING
2.
p>Proceso: PRE_ROUTING---FORWARD---POST_ROUTING---saliente, generar registros de conexión en PREROUTING y agregar los registros de conexión generados a la tabla hash de LOCAL_IN
Tres, paquetes de datos de la máquina local
Proceso: LOCAL_OUT ----POST_ROUTING --- Saliente, genera registros de conexión en LOCAL_OUT y agrega los registros de conexión generados a la tabla hash de POSTROUTING.
Todos sabemos que la estructura utilizada para representar paquetes de datos en la capa INET es la famosa sk_buff{} (en lo sucesivo, skb). Si desafortunadamente no ha oído hablar de esto, le recomiendo encarecidamente. Antes de continuar leyendo este artículo, repase los conceptos básicos de la pila de protocolos de red. Hay un puntero de miembro nfct en skb, cuyo tipo es struct nf_conntrack{} y está definido en el archivo include/linux/skbuff.h. Esta estructura registra un recuento de los registros de conexión que se exponen a la aplicación y también facilita la referencia al seguimiento de conexiones en otros lugares. En la práctica, el seguimiento de conexiones se utiliza normalmente para obtener información de estado sobre la pista de conexión a la que pertenece un paquete forzando una conversión de tipo de nfct a ip_conntrack{} (definido en include/linux/netfilter_ipv4/ip_conntrack.h). Es decir, el marco Neftilter utiliza ip_conntrack{} para registrar el estado de conexión de los paquetes.
Al mismo tiempo, el archivo include/linux/netfilter_ipv4/ip_conntrack.h también proporciona una interfaz muy útil: struct ip_conntrack *ip_conntrack_get(skb, ctinfo) se utiliza para obtener el puntero nfct de skb para comprenderlo. el paquete de datos El estado de la conexión y la información relacionada con el estado de la conexión ctinfo. Desde una perspectiva de seguimiento de conexión, este ctinfo muestra varios estados de conexión para cada paquete:
l IP_CT_ESTABLISHED
El paquete es parte de una conexión establecida y está en la dirección inicial.
l IP_CT_RELATED
El paquete es parte de la conexión relacionada de una conexión establecida en su dirección original.
l IP_CT_NEW
El paquete está intentando establecer una nueva conexión
l IP_CT_ESTABLISHED IP_CT_IS_REPLY
El paquete ya está en su dirección de respuesta parte del establecimiento de una conexión.
l IP_CT_RELATED IP_CT_IS_REPLY
El paquete forma parte de una conexión establecida y está asociado a una conexión en su dirección de respuesta.
Dentro del seguimiento de conexiones, cada skb recibido se convierte primero en una estructura ip_conntrack_tuple{}, lo que significa que la estructura ip_conntrack_tuple{} es el paquete "reconocido" por el sistema de seguimiento de conexiones. Entonces, ¿cómo funciona la conversión entre las estructuras skb e ip_conntrack_tuple{}? No hay una respuesta única a esta pregunta y depende del acuerdo. Por ejemplo, para el protocolo TCP/UDP, un paquete de datos se puede identificar de forma única según el "origen, IP de destino y puerto de destino" más el número de secuencia para el protocolo ICMP, según el "tipo de IP de origen y destino"; "código" más el número de secuencia, para ICMP Según el protocolo, un paquete ICMP se puede identificar de forma única en función de los "códigos de tipo IP de origen y destino" más el número de secuencia. Por ejemplo, los protocolos "activos" de la capa de aplicación como FTP son más complejos. Este artículo no intenta analizar la implementación del seguimiento de conexiones para un protocolo específico, sino que explora los principios de diseño y el flujo de trabajo del seguimiento de conexiones, para que todos puedan comprender la esencia del seguimiento de conexiones. Desde que el kernel de Linux se actualiza a 3.4.x demasiado rápido, muchas cosas han cambiado. Incluso 2.6.22 y 2.6.21 todavía tienen ciertas diferencias en el seguimiento de conexiones. Una vez que comprendamos las ideas de diseño del seguimiento de conexiones y dominemos su encanto, no importa cómo las cambiemos, no nos confundiremos cuando miremos el código de implementación específico. Como dice el refrán: "Es mejor enseñarle a pescar a un hombre que enseñarle a pescar". Una vez que tenga el método y practique mucho, se convertirá en una habilidad y finalmente tendrá una idea clara al desarrollar su propia función de seguimiento de conexión de protocolo. Esta es también la intención y el propósito original de escribir esta serie de publicaciones de blog. Aquí animo a todos a hacer lo mismo.
Antes de comenzar a analizar el seguimiento de conexiones, primero veamos todo el diseño del seguimiento de conexiones desde la perspectiva del comandante general. Aquí, primero le mostraré un diagrama de flujo simplificado relativamente aproximado para facilitar su comprensión y ayudarlo a comenzar. Por supuesto, mi comprensión puede ser inexacta, así que corríjame.
Quiero reiterar: el seguimiento de conexiones se divide en dos puntos: entrada y salida. Recuerde que los registros de seguimiento de conexiones se crean al ingresar y se agregan a la tabla de seguimiento de conexiones al salir. Veamos cada uno individualmente.
Entrar:
Todo el proceso de entrada se describe brevemente de la siguiente manera: para cada skb entrante, el seguimiento de la conexión lo convierte en una estructura de tupla y luego usa la tupla para buscar la conexión. tabla de seguimiento.
Si un paquete de este tipo aún no ha sido rastreado, se crea una entrada de registro de conexión en la tabla hash de seguimiento de conexiones, pero esto no es necesario para los paquetes que sí han sido rastreados. Inmediatamente después, se llamará a la función de devolución de llamada del paquete () proporcionada por el módulo de seguimiento de conexión del protocolo al que pertenece el paquete de datos, y finalmente se cambiará el estado del registro de seguimiento de conexión según el estado.
Exportar:
Todo el proceso de exportación se describe brevemente de la siguiente manera: Para cada paquete que está a punto de salir del marco de Netfilter, si el módulo de seguimiento de conexión se utiliza para procesar paquetes de ese protocolo El tipo proporciona función de asistencia, el paquete será procesado primero por la función auxiliar y luego, si el paquete ha sido rastreado, continuará determinando el estado de la conexión a la que pertenece.
Si el paquete ha sido rastreado, la función auxiliar continúa determinando el estado de la conexión a la que pertenece, decidiendo así si el paquete debe descartarse, devolverse a la pila para continuar con la transmisión o agregarse a la tabla de seguimiento de conexiones en el medio.
Gestión de protocolos de seguimiento de conexiones:
Como se mencionó anteriormente, diferentes protocolos tienen diferentes implementaciones de seguimiento de conexiones. Si cada protocolo quiere desarrollar su propio módulo de seguimiento de conexiones, primero debe crear una instancia de una variable del tipo de estructura ip_conntrack_protocol{}, completarla según sea necesario y luego llamar a la función ip_conntrack_protocol_register() para registrar la estructura, que en realidad se basa en el protocolo. escriba en la ubicación adecuada en la matriz global ip_ct_protos[].
La variable ip_ct_protos almacena todos los protocolos que el sistema de seguimiento de conexiones puede manejar actualmente. El número de protocolo es el subíndice único de la matriz, como se muestra a continuación.
Cada miembro de la estructura ip_conntrack_protocol{} tiene comentarios muy detallados en el código fuente del kernel. No los explicaré uno por uno aquí. En el proceso de desarrollo real, se analizará en detalle qué función utilizamos. .
Módulo auxiliar para seguimiento de conexiones:
El seguimiento de conexiones de Netfilter nos proporciona un módulo de funciones muy útil: helper. El requisito para este escenario de aplicación suele ser que cuando el paquete de datos esté a punto de salir del marco de Netfilter, podamos realizar el procesamiento final en el paquete de datos nuevamente. También podemos ver en la figura anterior que la prioridad de registro del módulo auxiliar es menor que los puntos de enlace LOCAL_OUT y POST_ROUTING de Netfilter.
Cada módulo auxiliar es un objeto de estructura tipo ip_conntrack_helper{}. Es decir, si el protocolo que está desarrollando requiere conectarse a un módulo auxiliar de seguimiento para realizar algún trabajo, entonces también debe crear una instancia de un objeto ip_conntrack_helper{}, completar ese objeto y luego llamar a la función ip_conntrack_helper_register{} para registrar su módulo auxiliar. en los ayudantes de variables globales.
La definición e inicialización de los asistentes de variables globales se completan en el archivo net/netfilter/nf_conntrack_helper.c.
Finalmente, la lista bidireccional representada por nuestra variable auxiliar generalmente se ve así:
A partir de esto, básicamente podemos saber que la función de devolución de llamada ip_conntrack_help() (esta función también está registrada a los ganchos LOCAL_OUT y POST_ROUTING del marco Netfilter) hacen básicamente lo mismo: la función de devolución de llamada ip_conntrack_help() hace básicamente lo mismo. La función de esta función también es básicamente clara: recorrer la lista de ayuda en secuencia y luego llamar a la función help () en cada objeto ip_conntrack_helper{}.
Conexiones esperadas:
El seguimiento de conexiones de Netfilter proporciona un mecanismo llamado "conexiones esperadas" para admitir conexiones "activas" como FTP. Todos sabemos que en modo activo, el servidor de protocolo FTP usa el puerto 21 como canal de transmisión de comandos, y el servidor usa el puerto 20 como canal de transmisión de datos; en modo pasivo, el servidor abre aleatoriamente un puerto superior a 1024 y luego el; El cliente se conecta al puerto. El puerto inicia la transmisión de datos. Es decir, ya sea activa o pasiva, se requieren dos conexiones: una conexión de canal de comando y una conexión de canal de datos. El seguimiento de conexiones maneja esta situación introduciendo el concepto de "conexión esperada", una conexión de datos que está relacionada con otra conexión de datos, y luego proporcionando su propia solución para esta conexión "relacionada". Como decíamos, este artículo no pretende analizar la implementación del seguimiento de conexiones para un protocolo específico. Hablemos de conexiones esperadas.
Cada conexión esperada está representada por un objeto de estructura tipo ip_conntrack_expect{}, y todas las conexiones esperadas se almacenan en una lista doblemente enlazada a la que apunta la variable global ip_conntrack_expect_list. Los miembros de conntrack_expect{} y sus significados también están completamente comentados en el código fuente del kernel, por lo que no los analizaré uno por uno aquí y los exploraré con más detalle cuando sea necesario.
Tabla de seguimiento de conexiones:
Habiendo dicho todo esto, finalmente es hora de que la tabla de seguimiento de conexiones muestre sus talentos. La tabla de seguimiento de conexiones es una tabla hash que se utiliza para registrar toda la información de conexión de paquetes. De hecho, la tabla de seguimiento de conexiones es un valor hash de paquetes compuesto por una lista vinculada de matriz circular bidireccional. Cada nodo en la lista vinculada es un objeto de tipo ip_conntrack_tuple_hash{}. La tabla de seguimiento de conexiones está representada por la variable de puntero de lista global doblemente enlazada ip_conntrack_hash[]. Para facilitar la comprensión de la matriz de lista enlazada circular bidireccional ip_conntrack_hash[], presentaremos las estructuras importantes mencionadas anteriormente y actualmente no introducidas ip_conntrack_tuple{}, ip_conntrack{} e ip_conntrack_tuple_hash{} una por una.
Podemos ver que ip_conntrack_tuple_hash{} es solo un paquete de ip_conntrack_tuple{} y lo organiza en una estructura de lista doblemente enlazada. Entonces, a nivel de comprensión, podemos tratarlos como la misma cosa.
Al analizar la estructura ip_conntrack{}, enumeramos todas las estructuras de datos previamente relacionadas con ella para una fácil comprensión y memoria.
Consulte /thread-1925862-1-1.html
Se puede decir que esta imagen son los datos centrales de la parte de seguimiento de la conexión. Presentaremos a los miembros relevantes en. la estructura ip_conntrack{} en detalle.
l ct_general: esta estructura registra la cantidad de veces que el registro de conexión se ha utilizado públicamente y también es conveniente para hacer referencia al seguimiento de conexiones en otros lugares.
l estado: El estado de la conexión del paquete de datos, un mapa de bits.
l Tiempo de espera: Para diferentes protocolos, cada conexión tiene un tiempo de espera predeterminado. Si se excede el período de tiempo de espera y no hay paquetes pertenecientes a una conexión disponibles para actualizar el seguimiento de la conexión, se llama a la función de tiempo de espera proporcionada por el tipo de protocolo.
l Contador: este miembro solo existe cuando CONFIG_IP_NF_CT_ACCT está activado cuando se compila el kernel y representa el número de bytes y paquetes registrados por una conexión específica.
l master: Este miembro apunta a otro ip_conntrack{}. Suele utilizarse en situaciones de conexión esperadas. Es decir, si la conexión actual es la conexión esperada de otra conexión, este miembro apunta a la conexión principal a la que pertenecemos.
l ayudante: si el protocolo proporciona un módulo de extensión, este miembro se utiliza para llamar a la función del módulo de extensión.
l proto: esta estructura es de tipo ip_conntrack_proto{}, que no debe confundirse con la estructura ip_conntrack_protocol{} que describimos anteriormente para almacenar el seguimiento de conexiones para diferentes protocolos. La primera es una enumeración y la segunda es una estructura. El proto aquí representa los parámetros adicionales requeridos por diferentes protocolos para implementar sus respectivas funciones de seguimiento de conexiones. La estructura de enumeración actual se ve así:
Esta estructura se puede ampliar si su protocolo requiere algunos datos adicionales en el futuro para implementar el seguimiento de conexiones.
l Ayuda: ip_conntrack_help{} también es una estructura de tipo enumeración ip_conntrack_help{}, que se confunde fácilmente con el tipo de estructura ip_conntrack_helpers{} que acabamos de describir: ip_conntrack_proto.conntrack_proto{} satisface las necesidades de la capa de protocolo y ip_conntrack_help{} satisface las necesidades de la capa de aplicación.
l tuplehash: como se muestra en la figura anterior, tuplehash [0] representa la conexión en la dirección "inicial" del flujo, tuplehash [1] representa la dirección de "respuesta" del flujo y tuplehash [1] representa la "respuesta" del flujo "dirección".
Hasta ahora, hemos entendido la idea de diseño y el mecanismo de funcionamiento del seguimiento de conexiones: el seguimiento de conexiones es un marco básico proporcionado por Netfilter. Los diferentes protocolos pueden guiarse por el mecanismo de seguimiento de conexiones según sus propias particularidades. protocolos. La función de seguimiento de conexiones se desarrolla bajo restricciones y, finalmente, se entrega al mecanismo de seguimiento de conexiones para una gestión unificada.
Reimpreso únicamente como referencia, los derechos de autor pertenecen al autor original. Te deseo una vida feliz, acéptala si estás satisfecho