Arquitectura del firewall de Linux: comprendiendo iptables, nftables, y los frontends

Publicado por Diego Córdoba el

Hoy analizaremos la arquitectura interna del firewall en Linux, desde los hooks de Netfilter en el kernel hasta las herramientas de espacio de usuario como iptables, nftables, ufw y firewalld. El objetivo es entender qué son realmente y cómo se relacionan entre sí.

¿Alguna vez te has sentido perdido/a con los firewalls en Linux?
Unos dicen ‘usá iptables’, otros ‘nftables’, otros ‘firewall-cmd’, y luego aparece ‘ufw’ o ‘firewall-config.
¿Son lo mismo? ¿Son diferentes? ¿Cuál deberías usar?

Hoy vamos a (intentar) aclarar esta duda recurrente entre mis alumnos de los cursos de firewalling y redes, y dudas que están empezando a surgir también en el canal de youtube.

Frontend y backend: una enorme diferencia

Antes que nada, toda la explicación que voy a dar a continuación se resume en este diagrama, que he armado basándome en algo de documentación, leyendo código y man’s de comandos:

arquitectura de firewall de linux

En primer lugar debemos distinguir entre front-end y back-end en el manejo del firewall en Linux.

Esta distinción coincide con la de cualquier aplicación:

  • Un frontend es una aplicación que sirve de interfaz para que podamos usar cierto servicio del sistema.
  • Un backend es el motor que realmente lleva a cabo las tareas en el sistema.

En el contexto de los firewalls de Linux, el frontend contiene las herramientas de espacio de usuario, mientras que el backend las de espacio del núcleo.

El backend, el motor que hace andar al firewall en el núcleo, son las implementaciones desarrolladas sobre el framework Netfilter, como xtables (para iptables) y nf_tables (para nftables).

📚 ¿Querés saber más de firewalls con nftables? Sumate a nuestro curso!

El frontend: la cara visible

El frontend está compuesto por las herramientas que usamos como usuarios para interactuar con el firewall.

Aquí tenemos una lista interesante, entre las que se cuentan:

  • iptables (legacy): este comando nos permite introducir las reglas de filtrado en bajo nivel, en el formato tradicional de iptables, con su sintaxis clásica.
  • nft (nftables nativo): nft permite interactuar, también en bajo nivel, con el nuevo backend de filtrado de nftables. Sintaxis compacta, renovada, etc.
  • iptables-nft: se trata de una herramienta de transición desde el viejo iptables al nuevo nftables. Con esta herramienta podemos introducir los comandos en la sintaxis original de iptables, pero internamente estaremos usando (mayormente) el nuevo framework de nftables.
  • libnftables: una biblioteca de desarrollo que nos permite crear aplicaciones y scripts que implementen reglas de firewall, pero sin lanzar una terminal que ejecute los comandos de iptables/nft.

Estas herramientas se comunican con el núcleo del sistema, con el backend, por medio de un API, una serie de funciones que hacen de nexo con el espacio del núcleo.

El backend: El corazón del firewall en el núcleo

Mientras que el frontend vive en el espacio de usuario, el backend reside en el espacio del núcleo, y es el verdadero motor que ejecuta las reglas de filtrado de paquetes.

En Linux, este ecosistema se construye sobre una base común llamada Netfilter. Netfilter es un framework dentro del kernel que proporciona una serie de «hooks» (puntos de enganche) en el subsistema de red, por donde pasan todos los paquetes.

Permite que módulos del kernel registren funciones para inspeccionar, modificar o descartar paquetes en momentos clave.

Sobre Netfilter se han construido dos backends principales:

  • nf_tables (moderno): Es el nuevo backend introducido con nftables. Más eficiente, con mejor rendimiento y una sintaxis más unificada. Es el backend por defecto en las distribuciones actuales.
  • xtables (legacy): Es el backend tradicional que utilizaba iptables. Procesa reglas en el formato clásico de cadenas, tablas y matches.

El API: el puente entre frontend y backend

Las herramientas de espacio de usuario (frontend) necesitan un canal de comunicación con estos backends del kernel. Ese canal es Netlink, una interfaz de sockets diseñada para transferir información entre el kernel y los procesos de usuario .

  • Las herramientas modernas (nftiptables-nftfirewalld) usan Netlink para enviar reglas al backend nf_tables .
  • Las herramientas legacy (iptables tradicional) usaba una API diferente (setsockopt/getsockopt), pero en los sistemas actuales suelen ser emuladas sobre Netlink mediante capas de compatibilidad.

Un caso especial es iptables-nft: este comando acepta la sintaxis clásica de iptables, pero internamente traduce las reglas y las envía por Netlink al backend nf_tables utilizando una capa llamada xt_compat, que oficia de puente para la transición .

El rol de xt_compat y la transición

xt_compat es un módulo del kernel y una capa de traducción que permite que las reglas escritas con la sintaxis tradicional de iptables (basada en xtables) sean ejecutadas sobre el nuevo backend nf_tables.
En otras palabras, xt_compat hace posible que reglas como esta:

iptables -A INPUT -p tcp --dport 22 -j ACCEPT

Sean procesadas internamente por el backend nf_tables.

El proceso es mas o menos así:

  1. Usuario ejecuta: iptables -A INPUT -p tcp --dport 22 -j ACCEPT
  2. iptables-nft (frontend) recibe el comando
  3. iptables-nft traduce la sintaxis a una representación intermedia
  4. iptables-nft envía la regla por Netlink al kernel
  5. En el kernel, xt_compat recibe la petición
  6. xt_compat convierte la regla al formato nf_tables
  7. nf_tables (backend) aplica la regla sobre Netfilter

Aquí hay que añadir que no todos los módulos de matching de xtables están implementados en nf_tables. Algunos módulos poco usados, o de terceros, pueden fallar.

En este punto es donde xt_compat hace la magia.

En realidad, no precisamente xt_compat, sino un módulo llamado nft_compat.

Cuando una regla tradicional de iptables no puede ser traducida, nft_compat toma los módulos originales de xtables, y los encapsula para poder usarlos dentro del nuevo marco de nf_tables.

nft_compat actúa como un «adaptador» o «intérprete» entre el mundo de xtables (el de iptables legacy) y el nuevo mundo de nf_tables.

Cuando instalamos iptables-nft en el sistema, las herramientas de espacio de usuario usan una biblioteca llamada libxtables para manejar la sintaxis de las reglas.

Luego, se conectan al kernel a través de la API Netlink, pero su destino no es el viejo sistema xtables, sino este nuevo módulo nft_compat .

¿Cómo funciona esto?

Podemos entenderlo en dos pasos:

  • Traducción Preferente (Nativa de nftables): La mayoría de las extensiones de iptables (como tcp, udp, multiport) tienen un equivalente directo y más eficiente en el lenguaje de nftables.
    iptables-nft intenta traducir la regla de sintaxis legacy a una expresión nativa de nftables.
    Este es el camino preferido porque es más rápido y moderno.
  • El Camino de nft_compat (Usando Módulos xtables): Cuando iptables-nft se encuentra con un módulo de iptables que no tiene una traducción nativa directa (algunos módulos muy específicos o de terceros), no puede simplemente ignorarlo.
    Es aquí donde entra en juego nft_compat. En lugar de fallar, nft_compat toma el módulo original de xtables, y lo envuelve en una «expresión» de nftables.
    Esto significa que el módulo legacy se carga y ejecuta igual, pero lo hace dentro de una estructura de nf_tables.

En resumen, las reglas que pueden traducirse a nftables, se traducen, y las que no, se encapsulan de modo que se ejecute el módulo original de xtables dentro de una especie de «jaula» de nftables.

Aquí se puede ver que si usamos iptables original (legacy) realizaremos llamadas al núcleo utilizando el API original de iptables, y este API utiliza el código de matching de paquetes de xtables.

📚 ¿Querés saber más de firewalls con iptables? Sumate a nuestro curso!

Y ya que estamos, un pequeño ejemplo:

Sí, como nos encanta ensuciarnos las manos en la terminal, veamos el siguiente ejemplo.

La utilidad iptables-translate, que mencioné en este video, nos permite traducir una regla de sintaxis original de iptables a sintaxis moderna de nft.

Veamos una traducción simple:

$ iptables-translate -A INPUT -j ACCEPT

nft 'add rule ip filter INPUT counter accept'

Esta regla simple es perfectamente traducida a formato nft. No debemos confundir con la traducción que hace iptables-nft, iptables-translate es una herramienta de línea de comandos para traducir manualmente las reglas, sin realizar consultas al núcleo ni interactuar con Netlink.

Ahora, si la regla de iptables usa algún módulo que (todavía) no está implementado en nftables, como el módulo string, el resultado será diferente:

$ iptables-translate -A INPUT -p udp --dport 234 -m string --string "abc.exe" --algo bm -j DROP

nft # -A INPUT -p udp --dport 234 -m string --string abc.exe --algo bm -j DROP

Aquí, iptables-translate devuelve una línea comentada, indicando que no pudo ser traducida, y que deberemos revisar manualmente.

Si bien en la documentación de iptables-translate no encontré nada sobre esto de la línea traducida, en la comunidad se habla de este comportamiento.

Nota al margen, iptables-translate falla en este caso porno poder realizar la traducción, pero si hubiéramos utilizado iptables-nft en su lugar, la regla se hubiese cargado correctamente gracias al toque mágico de xt_compat/nft_compat.

¿Y el resto de las herramientas?

Antes de cerrar, extendamos la gráfica original para entender cómo interactúan los front-ends de firewall modernos:

arquitectura de firewall de linux

En este diagrama he añadido algunos de los front-ends más conocidos para gestionar el firewall, entre ellos:

  • ufw: el firewall de Ubuntu, esta herramienta permite al usuario introducir, en muy alto nivel, reglas de firewalling, y luego el daemon de ufw las traduce a reglas de iptables-nft para enviarlas al núcleo. El resto ya lo conocemos.
  • firewalld, el firewall nativo de sistemas basados en systemd, recibe sus configuraciones por línea de comandos con herramientas como firewall-cmd, o mediante interfaz gráfica con firewall-config. Las reglas que configuremos aquí se enviarán al núcleo mediante libnftables, es decir, firewalld usa libnftables para comunicarse con el API de netlink directamente, sin realizar «traducciones» intermedias a comandos de nft.

📚 ¿Querés saber más de Redes y protocolos TCP/IP? Sumate a nuestro curso!

Resumen y conclusiones

Hemos llegado al final!

Para quienes siguen el blog al detalle, verán que parte de este contenido ya lo había publicado, más brevemente, en este post:

nftables vs iptables: Guía de diferencias y por qué migrar en Linux

Empecé a extenderlo, pero se iba a hacer demasiado largo, además de que le post anterior estaba orientado a diferencias prácticas entre iptables y nftables, mientras que este nuevo artículo está más orientado a la arquitectura interna de firewalling en el núcleo Linux, para aquellos que quieren sumergirse un poco más en profundidad, y entender estos mecanismos.

Este contenido también lo he subido al canal de youtube, pueden verlo acá:

Espero que se haya entendido! Cualquier duda, quedan invitados a sumarse a la JuncoTIC Community en Telegram! 👇

Hasta la próxima!


¿Querés aprender más? 📚

👉 Visitá nuestros cursos!
💬 Y si tenés dudas, o querés dejarnos tus comentarios sumate a la Comunidad JuncoTIC en Telegram!
¡Te esperamos!

Categorías: LinuxRedes

Diego Córdoba

- Ingeniero en Informática - Mgtr. Teleinformática - Instructor GNU/Linux, Programación, Redes TCP/IP, criptografía y ciberseguridad. - (Ex) Docente universitario e investigador