Cortafuegos en Linux con iptables (primera parte)

Iptables se utiliza en sistemas GNU/Linux para filtrar paquetes. Aunque ya ha quedado anticuado respecto a otros sistemas como Firewalld o UFW, lo cierto es que todavía es muy usado, por lo que creo que esta entrada puede ser de bastante utilidad.

La herramienta básica de este clásico cortafuegos es iptables y se configura mediante la aplicación de reglas de gestión de paquetes. Con iptables podemos filtrar el tráfico que transita, bien por un equipo local, un servidor o un router con un sistema Linux. Además del tráfico entrante y del saliente.

Como he comentando antes iptables tiende a estar en desuso y uno de los motivos es lo farragoso y poco intuitivo que es su fichero de configuración con un galamatías (bueno, quizás no tanto) de reglas. Aún así cuando aprendes su lógica todo se hace más fácil.

¿Cómo funciona iptables?

Uso de tablas

Una pieza clave es la utilización de tablas. Depende de la regla que queramos aplicar a iptables esta necesita la tabla asociada. Las tablas más importantes son nat para traducir direcciones entre una red privada y otra pública o filter, que como sugiere el nombre se encarga de filtrar.

La tabla nat tiene como función traducir direcciones y debe indicarse siempre cuando se vaya a utilizar.

En cambio la tabla filter es la tabla por defecto. Por lo que, cuando se establece una nueva regla, con el objeto de filtrar paquetes, se supone, por lo que no hace falta mencionarla.

Las cadenas

Las cadenas son las encargadas de especificar si una regla debe aplicarse al tráfico entrante, de salida o de tránsito. Por lo que podemos decir que se encarga de gestionar el tráfico desde el punto de vista de su pase por un host dado.

Existen diferentes tipos:

  • La cadena INPUT se encarga de identificar el tráfico de entrada.
  • La cadena OUTPUT se encarga de identificar el tráfico de salida.
  • Y la cadena FORWARD identifica el tráfico que pasa por el host, entrando por una interfaz y saliendo por otra.
  • La cadena POSTROUTING se utiliza en la configuración de NAT y tiene como función tratar los paquetes después de una operación de enrutamiento.

Es importante remarcar que las cadenas siempre se indicar en mayúsculas.

Acciones

Cuando se cumplen las condiciones para aplicar una regla se produce una acción sobre el paquete en cuestión. Existen dos acciones principales, la primera es ACCEPT que permite el paso del paquete y DROP que lo deniega. Cuando creamos la regla, cuando queremos indicar una acción, previamente la debemos indicar con -j. Las acciones siempre deben ir en mayúsculas.

Imagen de funcionamiento simplificado de iptables (fuente: elbinario.net)

Tratamiento

Las reglas se van aplicando una por una, por cada paquete que se filtra. Se se cumple con una regla, se produce una acción sobre dicho paquete. En cambio, si no se cumple la regla, se pasa a comprobar la siguiente regla sobre el mismo paquete. Cuando al paquete no se le ha aplicado ningún regla, este paquete recibe el tratamiento por defecto, indicado al final del fichero de configuración llamado policy.

Trabajar con iptables

La mejor manera de decir es hacer, así que veamos algunos ejemplo de uso. Empecemos listando las reglas existentes en un nuestro sistema, para ello debemos utilizar el parámetro -L, como se muestra en el ejemplo:

pi@raspberrypi:~ $ sudo iptables -L -n
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
 
Chain FORWARD (policy ACCEPT)
target     prot opt source               destination
 
Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Con el parámetro -n se imprimirán las direcciones IP y los números de puerto en formato numérico. De forma predeterminada, el programa intentará mostrar como nombres de host, nombres de red o servicios. En la muchas distribuciones para poder utilizar iptables debemos tener permisos de superusuario.

Por otra parte parte podemos usar el parámetro -S, para visualizar las reglas que se han introducido en el sistema, sino se ha utilizado ninguna la salida habitual es esta:

pi@raspberrypi:~ $ sudo iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
Añadir políticas

Antes de nada hay que tener en cuenta que cualquier cortafuegos puede funcionar de dos maneras, la primera es que todo lo que no está autorizado está prohibido, y la segunda es que todo lo que no está prohibido está autorizado. Para definir esto, iptables permite definir para cadena una acción por defecto.

Para añadir la política por defecto debemos utilizar el parámetro -P, de esta manera:

sudo iptables -P cadena acción

Recordamos que cadenas serían INPUT, OUTPUT y FORWARD, y en las acciones DROP o ACCEPT

A modo de ejemplo vamos a bloquear todo el tráfico saliente, aunque normalmente se bloquea el entrante, por lo menos desde mi experiencia:

iptables -P OUTPUT DROP

De esta manera, si queremos hacer ping a cualquier IP obtendremos este resultado:

ping 192.168.1.200
ping: sendmsg: Operation not permitted

Para la creación de una política básica, por ejemplo si deseamos que de inicio se descarte todo, tanto lo entrante, lo saliente y en tránsito:

sudo iptables -P INPUT DROP
sudo iptables -P OUTPUT DROP
sudo iptables -P FORWARD DROP

Esta es sin duda es la política más restrictiva, generalmente utilizada en los encaminadores o routers que funcionnen con Linux. A partir de aquí se añaden las reglas que permiten el tráfico con ACCEPT

Filtrando paquetes

Tras haber indicado las política por defecto, debemos empezar a crear las reglas de filtrado, para el tráfico que deseamos que sí puede pasar. Para cada elemento que debe estar permitido o prohibido hay que crear una regla específica.

La sintaxis es esta:

sudo iptables -A cadena -s ip_de_origen -d ip_de_destino -p protocolo --dport puerto -j acción_a_realizar

Vamos un poco al detalle:

  • -A cadena : Añadimos una regla en cadena: INPUT, OUTPUT o FORWARD
  • -s ip_de_origen : Esto es opcional, ya que podemos indicar la IP de origen de donde provienen los paquetes sujetos a la regla. Hay que tener en cuenta si la dirección es una dirección de red, hay que indicar la máscara de red.
  • -d ip_de_destino : También es opcional, indicamos la IP de destino a la que van destinados los paquetes sujetos a la regla. Lo mismo, si es una dirección de red hay que indicar la máscara de red.
  • -p protocolo : Se indica el protocolo utilizado en el paquete sujeto a la regla. Los valores habituales son : tcp, udp, icmp.
  • -dport puerto : Es opcional. Hay que indicar el puerto de destino del paquete sujeto a la regla.
  • -j acción : Decimos cómo hay que tratar el paquete sujeto a la regla, esto es, ACCEPT o DROP

Veamos algún ejemplo:

sudo iptables -A OUTPUT -p icmp -j ACCEPT
sudo iptables -A INPUT -p icmp -j ACCEPT

Al habilitar el protocolor ICMP permitimos que podamos utilizar el programa ping.

Si deseamos permitir el tráfico HTTP desde una red en concreto, por ejemplo la red de empresa:

sudo iptables -A FORWARD -s 192.168.1.0/24 -p tcp -dport 80 -j ACCEPT

Para eliminar una regla debemos utilizar el parámetro -D, indicando la cadena y el número de la línea obtenido con el comando y parámetros iptables -L cadena --line-numbers -s, por ejemplo:

iptables -D cadena número

Si queremos insertar una regla con el parámetro I, siguiendo el formato:

iptables -I cadenanúmero condiciones -j acción

Aquí un ejemplo de estos puntos:

Muestro de uso de iptables en RaspBerryPi

Y aquí lo dejamos por hoy. En la próxima entrada sobre el tema hablaremos de iptables para gestionar el NAT y mostraremos un fichero de configuración con todas las reglas ya incluidas:

Cortafuegos en Linux con iptables (segunda parte)

Fuentes consultadas

Página de man de iptables