Un firewall (cortafuegos en español) es una medida de protección básica en un servidor. Es utilizado para filtrar o restringir el tráfico de red en un sistema, tanto entrante como saliente. En los sistemas operativos Linux, iptables es la herramienta más ampliamente utilizada para implementar firewalls. Esta es una interfaz de alto nivel al framework de filtrado de paquetes netfilter, parte de la pila de red del kernel Linux. Este tutorial trata de clarificar el significado de las tablas, cadenas, reglas y targets, así como hacer una breve introducción al uso y funcionamiento de iptables.

iptables gestiona, mantiene e inspecciona las reglas de filtrado de paquetes IPv4 a través de tablas. Estas tablas clasifican y organizan las reglas de acuerdo al tipo de decisiones que se deben tomar sobre los paquetes. Por ejemplo, si una regla se encarga de implementar traducción de direcciones, será puesta en la tabla "nat". En cambio, si una regla decide cuándo o no dejar pasar un paquete hacia su destino, probablemente será agregada en la tabla "filter".

A su vez, cada tabla contiene un número de cadenas (chains), algunas predeterminadas y otras definidas por el usuario. Dentro de cada tabla de iptables las reglas se organizan en cadenas separadas. Mientras que las tablas son definidas por el tipo de reglas que mantienen (filtrado, nateo, manipulación de paquetes), las cadenas representan los eventos que disparan o inician a cada regla (hooks de netfilter). De esta forma, las cadenas determinan cuándo las reglas son evaluadas (cuando un paquete ingresa al sistema, cuando un paquete sale del sistema, cuando un paquete se debe reenviar hacia otro sistema, etc.)

Los diferentes hooks presentes en el framework netfilter coinciden con las siguientes cadenas de iptables:

  • PREROUTING: tráfico entrante, justo antes de ingresar a la pila de red del kernel. Las reglas en esta cadena son procesadas antes de tomar cualquier decisión de ruteo respecto hacia dónde enviar el paquete.
  • INPUT: tráfico entrante, luego de haber sido ruteado y destinado al sistema local.
  • FORWARD: tráfico entrante, luego de haber sido ruteado y destinado hacia otro host (reenviado).
  • OUTPUT: tráfico saliente originado en el sistema local, inmediatamente luego de haber ingresado a la pila de red del kernel.
  • POSTROUTING: tráfico saliente originado en el sistema local o reenviado, luego de haber sido ruteado y justo antes de ser puesto en el cable.

El objetivo de las cadenas es poder controlar cuándo, a lo largo del flujo de un paquete a través del sistema y la pila de red, una regla es evaluada.

Dependiendo de cómo ha sido configurado el kernel Linux en el sistema, y qué módulos están presentes, iptables provee diferentes tablas. La tabla más ampliamente utiliza es "filter". Esta se utiliza para tomar decisiones acerca de cuándo permitir o denegar el paso de un paquete a través del sistema. Esto es lo que se conoce como filtrar o filtrado de paquetes. La tabla "filter" contiene por defecto las cadenas "INPUT", "FORWARD" y "OUTPUT".

La tabla "nat" es utilizada sólo por sistemas que implementan alguna clase de NAT (Network Address Translation). Por ejemplo para proveer un medio de acceso a Internet a una subred privada y viceversa. Las reglas en esta tabla se encargan de traducir las direcciones origen y destino de los paquetes, para impactar la forma en que el tráfico es ruteado. Esta tabla contiene por defecto las cadenas "PREROUTING" (para alterar los paquetes antes de que sean ruteados), "OUTPUT" (para alterar paquetes generados en el sistema local antes de ser ruteados) y "POSTROUTING" (para alterar paquetes antes de ir al cable, es decir, luego de ser ruteados).

Otra tabla, menos utilizada, es "mangle". Su objetivo es almacenar reglas que implementan modificaciones especializadas. Por ejemplo reglas que modifican headers del protocolo IP (TTL, TOS y otros). Además de estas tres pueden estar disponibles también las tablas "raw" (sólo para marcar paquetes durante el proceso de connection tracking, lo que hace que iptables sea stateful) y "security" (SELinux).

Sintetizando, cada tabla posee diferentes cadenas, las cuales son listas de reglas que pueden coincidir con un conjunto de paquetes. Las tablas agrupan las cadenas de acuerdo al tipo de trabajo que realizan, mientras que las cadenas agrupan las reglas de acuerdo al momento en que deben ser evaluadas. En este punto es importante aclarar que, dentro de cada cadena, las reglas son evaluadas en orden.

Debido a que ciertas tablas poseen cadenas idénticas (es decir, conjuntos de reglas que deben ser evaluadas en el mismo momento), existe una prioridad entre las cadenas de diferentes tablas. Para ejemplificar, ambas tablas "filter" y "nat" incluyen la cadena "OUTPUT". Por ende, cuando un paquete está saliendo del sistema ¿qué cadena debe ser evaluada primero? ¿la cadena "OUTPUT" de la tabla "filter", o la cadena "OUTPUT" de la tabla "nat"?

PREROUTING:

  1. raw
  2. mangle
  3. nat (DNAT)

INPUT:

  1. mangle
  2. filter
  3. security
  4. nat (SNAT)

FORWARD:

  1. mangle
  2. filter
  3. security

OUTPUT:

  1. raw
  2. mangle
  3. nat (DNAT)
  4. filter
  5. security

POSTROUTING:

  1. mangle
  2. nat (SNAT)

Resta entonces saber cómo (cuáles y en qué orden) se examinan las cadenas de las diferentes tablas, de acuerdo al tipo de tráfico. Asumiendo que el sistema sabe cómo rutear cada paquete, y que las reglas permiten su transmisión, las cadenas se evalúan en el siguiente orden:

Tráfico entrante destinado al sistema local:

  1. PREROUTING
  2. INPUT

Tráfico entrante destinado a otro sistema (paquetes que se deben reenviar):

  1. PREROUTING
  2. FORWARD
  3. POSTROUTING

Tráfico originado desde el sistema local:

  1. OUTPUT
  2. POSTROUTING

Si se combina esta información con la prioridad de cadenas de diferentes tablas, es posible determinar que un paquete entrante, destinado al sistema local, será primero evaluado contra las reglas de las cadenas "PREROUTING" de las tablas "raw", "mangle" y "nat". Y luego atravesará las cadenas "INPUT" de las tablas "mangle", "filter", "security" y "nat", en ese orden, antes de ser enviado al socket correspondiente en el sistema local.

Las reglas de iptables se ubican dentro de una cadena en una tabla específica. A medida que cada cadena es analizada, el paquete en cuestión es comparado con cada regla dentro de la cadena, en orden. Cada regla se compone de dos partes: una parte de matching, para determinar si una regla debe ser aplicada al paquete actual; y una parte de acción, donde se indica qué hacer con el paquete.

Cada paquete se compara contra la porción de matching de la regla, la cual indica el criterio que debe verificar el mismo para que se le apliquen las acciones asociadas. Las reglas pueden construirse para buscar coincidencias (matching) en protocolos, direcciones fuente y destino, puertos origen y destino, redes o subredes involucradas, interfaces de entrada y salida, cabeceras, estado de la conexión, etc. Todos estos criterios pueden ser combinados para crear reglas bastante complejas que distingan diferentes tipos de tráfico.

Las acciones a tomar, llamadas targets, se disparan cada vez que un paquete coincide con el criterio de selección de una regla. Existen targets que son de terminación y otros que no. Un target de terminación hace que la regla actual sea la última en ser evaluada. Un target de no terminación, hace que se ejecute la acción y luego se continúe evaluando el resto de las reglas.

Cuando hay una coincidencia entre un paquete y una regla, el target indica la próxima regla a evaluar, que puede ser el nombre de una cadena definida por el usuario o uno de los valores especiales: ACCEPT (dejar pasar el paquete), DROP (descartar el paquete), QUEUE (redirigir el paquete a espacio usaurio) o RETURN (salir de la cadena actual y continuar en la siguiente regla de la cadena previa). Si se llega al final de una cadena built-in, o se encuentra un target RETURN en una cadena built-in, el destino final del paquete es decidido por la política de la cadena.

Ejemplos prácticos

Habiendo repasado someramente los conceptos clave que conforman un firewall iptables, veamos ejemplos prácticos de su uso.

Listar diferentes tablas

El comando -L lista todas las reglas de una cadena específica. Si no se indica una cadena como parámetro, lista todas las cadenas de la tabla indicada. Para seleccionar la tabla se debe utilizar la opción -t. Si no se especifica esta opción, iptables selecciona la tabla por defecto, que es "filter".

Para listar el contenido de la tabla "nat" (mostrar todas las reglas de todas sus cadenas), ejecutar:

root@fw:~# iptables -nL -t nat
Chain PREROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

En este ejemplo, la tabla "nat" no tiene reglas en ninguna de las tres cadenas que posee. Es decir está vacía.

Listar una cadena específica

Para listar una cadena específica de una tabla, sólo basta con pasarla como parámetro luego del comando -L:

root@fw:~# iptables -nL FORWARD -t filter
Chain FORWARD (policy DROP)
target     prot opt source               destination         
LOG        all  --  0.0.0.0/0            0.0.0.0/0            LOG flags 0 level 4

Se observa que la cadena "FORWARD" de la tabla "filter" posee una única regla. Esta regla aplica el target "LOG" a todos los paquetes que pasan por la cadena "FORWARD". Este target es una extensión (ver la sección "TARGET EXTENSIONS" en el manual de iptables) que habilita el registro (logging) en el log del kernel Linux.

La opción -n (numeric) se utiliza para que iptables no traduzca puertos a protocolos asociados ni direcciones IP a nombres de host.

Insertar una regla al final de una cadena

Para insertar una regla al final de una cadena (append) se puede utilizar el comando -A. Este comando requiere indicar la cadena en cuestión y, opcionalmente, la tabla. Siempre que no se especifique una tabla, iptables usa la tabla por defecto, que es "filter".

iptables -A INPUT <especificación de regla>

Insertar una regla en una posición específica de una cadena

Para insertar una regla en una posición específica se utiliza el comando -I. Este comando, además de la cadena, requiere la posición de la regla como parámetro. Si no se especifica el número de regla, por defecto se inserta en la primera posición (1).

iptables -I INPUT 1 <especificación de regla>

Eliminar una regla específica

Es posible borrar una regla utilizando el comando -D, simplemente especificando la cadena y número de regla como parámetro, tal como explica el artículo Cómo borrar una regla de iptables.

iptables -D INPUT <número de regla>

Sin embargo, también es posible borrar una regla utilizando el comando -D y replicando la regla (si no se conoce la posición o número de regla), tal como lo implementa el script GTFO en el artículo GTFO my server yo - Bloquear intentos de acceso a tu servidor Apache/Nginx.

iptables -D INPUT <especificación de regla>

Eliminar todas las reglas de un firewall

Para eliminar todas las reglas de todas las cadenas de una tabla, utilizar el comando flush. Por ejemplo, para vaciar las tablas "filter" y "nat" respectivamente:

iptables -F
iptables -F -t nat

Crear un firewall simple

El artículo Cómo configurar el cortafuegos en Debian explica cómo crear un firewall simple utilizando la tabla "filter". Este artículo es válido para todo sistema corriendo Linux con iptables, no sólo para Debian.

Volcar las reglas de un firewall

Notar que, al listar reglas con el comando -L, iptables muestra la salida en un formato visualmente amigable, para ser interpretado fácil y rápidamente por el administrador del firewall. Si se desea en cambio volcar las reglas tal como fueron creadas (por ejemplo, para hacer un backup del firewall), se debe recurrir al comando -S. Este comando acepta una cadena como parámetro. Si no se especifica, vuelca todas las reglas de todas las cadenas. Si no se indica una tabla (a través de la opción -t), se selecciona la tabla "filter" por defecto. Por ejemplo:

root@webserver:~# iptables -S INPUT | grep -e "ACCEPT"
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p icmp -m icmp --icmp-type 8 -m conntrack --ctstate NEW -j ACCEPT
-A INPUT -d 192.168.100.10/32 -p tcp -m tcp --sport 1024:65535 --dport 22 -m state --state NEW -j ACCEPT
-A INPUT -d 192.168.100.10/32 -p tcp -m tcp --sport 1024:65535 --dport 80 -m state --state NEW -j ACCEPT
-A INPUT -d 192.168.100.10/32 -p tcp -m tcp --sport 1024:65535 --dport 443 -m state --state NEW -j ACCEPT

Notar que sólo basta con anteponer iptables (o /sbin/iptables) delante de cada línea para reproducir el firewall (habiendo previamente eliminado todas las reglas, como se explicó anteriormente).

Referencias

man iptables

iptables(8) - Linux man page

IP filtering introduction

A Deep Dive into Iptables and Netfilter Architecture - DigitalOcean


Tal vez pueda interesarte


Compartí este artículo