Gestionar el filtrado de paquetes con iptables

LinuxBeginner
Practicar Ahora

Introducción

iptables es una interfaz de línea de comandos para gestionar las reglas de filtrado de paquetes de Linux. Aunque muchas distribuciones modernas implementan estas reglas mediante un backend de nftables, los administradores siguen encontrándose con tareas y sistemas existentes que utilizan la sintaxis del comando iptables.

Un modelo sencillo para principiantes consiste en imaginar el cortafuegos como una lista de comprobación ordenada. Un paquete entra en una cadena, cada regla comprueba si coincide con condiciones como una interfaz, un protocolo o un puerto, y un destino como ACCEPT o REJECT decide qué ocurre. La cadena INPUT gestiona los paquetes dirigidos al equipo local. Como las reglas se evalúan de arriba abajo, tanto su contenido como su posición son importantes.

En este laboratorio trabajarás con un único servicio web local y realizarás cambios muy específicos sobre su puerto TCP. Inspeccionarás el cortafuegos actual, añadirás una regla que rechace las solicitudes, demostrarás el efecto mediante tráfico real, sustituirás la regla por una regla explícita de разрешение y eliminarás la regla creada por el laboratorio sin vaciar ni reescribir el estado no relacionado del cortafuegos.

Inspeccionar el cortafuegos y probar el servicio

En este paso identificarás la implementación de iptables instalada y comprobarás que el servicio de prueba local funciona antes de modificar cualquier regla del cortafuegos.

Ve al directorio del proyecto para que todos los comandos posteriores se ejecuten desde el espacio de trabajo del curso.

cd /home/labex/project

Usa command -v para localizar el ejecutable que utilizará el shell.

command -v iptables

Esta comprobación es más útil que dar por hecho que el comando está instalado: muestra la ruta del ejecutable resuelto, normalmente /usr/sbin/iptables, y devuelve un estado distinto de cero si el shell no puede encontrarlo.

Muestra la versión y la información del backend. En este equipo Ubuntu, la salida normalmente incluye nf_tables; esto significa que la sintaxis conocida de iptables se traduce al backend moderno del conjunto de reglas del kernel.

sudo iptables --version

Deberías ver una salida similar a:

iptables v1.8... (nf_tables)

El nombre del backend no cambia los comandos de este laboratorio. Seguirás creando e inspeccionando reglas con iptables; la implementación se encarga de representarlas en el kernel.

Antes de filtrar el puerto, solicita su endpoint de estado. Una respuesta correcta demuestra que la aplicación está preparada, de modo que un fallo posterior pueda atribuirse a la regla del cortafuegos.

curl --noproxy '*' --fail --silent http://127.0.0.1:18086/health

Aquí, 127.0.0.1 es la dirección de loopback IPv4, por lo que el tráfico sale y regresa a través de la interfaz local lo sin llegar a una red externa. --noproxy '*' evita que la configuración del proxy redirija la solicitud, --fail hace que los errores HTTP produzcan un estado de fallo y --silent oculta el indicador de progreso para que la respuesta del servicio sea fácil de leer.

El servicio devuelve:

iptables filter service ready

Inspeccionar la cadena INPUT y añadir una regla de rechazo

En este paso leerás la cadena INPUT actual e insertarás una regla precisa que rechace el tráfico TCP de loopback dirigido al puerto de prueba.

La opción -S muestra las reglas con un formato similar al de los comandos. Indicar INPUT limita la salida a los paquetes destinados a este equipo.

sudo iptables -S INPUT

La primera línea suele mostrar la política de la cadena, por ejemplo -P INPUT ACCEPT. La política es la acción alternativa que se utiliza únicamente cuando ninguna regla anterior toma una decisión definitiva. Las líneas siguientes que comienzan por -A INPUT son las reglas añadidas actualmente a esa cadena.

Para obtener una vista operativa, -L lista la cadena, -n evita la lenta resolución de nombres y --line-numbers muestra la posición de cada regla. El orden es importante porque el primer destino terminal que coincide determina el resultado del paquete.

Inserta la regla del laboratorio en la posición 1 con -I INPUT 1. Esta regla coincide con la interfaz de loopback lo, el protocolo TCP y el puerto de destino 18086. El destino REJECT con tcp-reset rechaza la conexión inmediatamente, en lugar de obligar al cliente a esperar a que expire el tiempo de espera de un paquete descartado.

sudo iptables -I INPUT 1 -i lo -p tcp --dport 18086 -j REJECT --reject-with tcp-reset

Lee el comando de izquierda a derecha: -i lo restringe la interfaz de entrada, -p tcp selecciona el protocolo, --dport 18086 selecciona el servicio y -j REJECT salta al destino de rechazo. -I inserta la regla en una posición determinada; en cambio, -A añadiría la regla al final, donde una regla anterior coincidente podría impedir que se alcanzara. Esta combinación específica evita bloquear puertos o interfaces externas no relacionados.

REJECT y DROP no son idénticos. REJECT envía una respuesta de error, mientras que DROP descarta el paquete silenciosamente. Un reinicio TCP hace que esta prueba local falle de forma rápida y predecible, lo que facilita el diagnóstico frente a tener que esperar a que expire un tiempo de espera.

Usa -C para comprobar si existe exactamente esa regla. Una comprobación correcta termina con el estado cero. En este equipo, la implementación respaldada por nftables también muestra la regla de coincidencia normalizada; otras implementaciones pueden completarla silenciosamente.

sudo iptables -C INPUT -i lo -p tcp --dport 18086 -j REJECT --reject-with tcp-reset

El resultado portable de -C es el estado de salida, no que aparezca texto en pantalla. Esto permite utilizar el mismo comando en scripts de shell y comprobaciones de verificación.

Vuelve a listar la cadena. La nueva regla debería aparecer como la regla 1 y mencionar tcp dpt:18086.

sudo iptables -L INPUT -n --line-numbers

Verificar el tráfico bloqueado

En este paso repetirás la solicitud original e inspeccionarás los contadores de la regla para demostrar que fue el cortafuegos, y no la aplicación, quien rechazó el tráfico.

Ejecuta la solicitud dentro de una sentencia if. Como se espera que la solicitud falle, la rama else convierte ese fallo esperado en un mensaje claro y permite continuar con el flujo guiado.

if curl --noproxy '*' --fail --silent http://127.0.0.1:18086/health; then
  echo "Unexpected: request succeeded"
else
  echo "Expected: iptables rejected the request"
fi

Las condiciones del shell toman decisiones a partir del estado de salida de un comando: cero selecciona then, mientras que un valor distinto de cero selecciona else. El reinicio enviado por el cortafuegos hace que curl devuelva un valor distinto de cero, por lo que llegar a la rama else es el resultado esperado aquí.

El mensaje esperado es:

Expected: iptables rejected the request

Ahora lista la cadena con -v para mostrar los contadores detallados. Los contadores de paquetes y bytes de la regla del puerto 18086 deberían ser mayores que cero después de la solicitud.

sudo iptables -L INPUT -n -v --line-numbers

En la salida, la columna pkts cuenta los paquetes coincidentes y la columna bytes cuenta su tamaño combinado. Los contadores son una evidencia útil: comprobar con -C demuestra que la regla existe, mientras que el aumento del contador demuestra que tráfico real llegó a ella y coincidió. Si el contador sigue en cero, revisa la interfaz, el protocolo, el puerto y la posición de la regla antes de culpar a la aplicación.

Sustituir la regla de rechazo por una regla de разрешение

En este paso eliminarás la regla de rechazo exacta, añadirás una regla explícita de разрешение para el mismo tráfico y verificarás que el acceso vuelve a estar disponible.

La forma -D que aparece a continuación identifica la regla mediante su coincidencia y destino completos. Es más segura que vaciar la cadena, porque elimina únicamente el cambio realizado por el laboratorio.

sudo iptables -D INPUT -i lo -p tcp --dport 18086 -j REJECT --reject-with tcp-reset

Las reglas también pueden eliminarse por número de línea, pero los números cambian cada vez que se insertan o eliminan reglas. Eliminar mediante la especificación exacta resulta más claro en un procedimiento repetible y reduce la posibilidad de borrar una regla vecina. Evita iptables -F aquí: vaciar la cadena eliminaría todas sus reglas, incluidas las no relacionadas con este laboratorio.

Inserta una regla ACCEPT para la misma interfaz, protocolo y puerto.

sudo iptables -I INPUT 1 -i lo -p tcp --dport 18086 -j ACCEPT

ACCEPT permite que un paquete coincidente continúe por la pila de red. Se inserta en la posición 1 para que una regla terminal anterior no oculte su resultado. Observa que la coincidencia sigue siendo igual de específica que antes; solo cambia el destino.

Comprueba la regla de разрешение exacta.

sudo iptables -C INPUT -i lo -p tcp --dport 18086 -j ACCEPT

Repite la solicitud de estado original.

curl --noproxy '*' --fail --silent http://127.0.0.1:18086/health

La respuesta vuelve a estar disponible:

iptables filter service ready

Eliminar la regla creada por el laboratorio

En este paso eliminarás la regla temporal de разрешение y confirmarás que no queda ninguna regla procedente de este ejercicio.

Elimina la regla ACCEPT exacta. Como antes, esto no vacía la cadena ni modifica reglas pertenecientes a la plataforma o a otro administrador.

sudo iptables -D INPUT -i lo -p tcp --dport 18086 -j ACCEPT

Eliminar una regla explícita de разрешение no significa automáticamente que el servicio vaya a quedar bloqueado. Una vez eliminada la regla, las reglas restantes y, finalmente, la política de la cadena determinan el destino del paquete. En este entorno preparado, el cortafuegos original permite la solicitud local.

Comprueba la regla una vez más. Esta vez se espera un fallo, por lo que || ejecuta el mensaje de la derecha únicamente cuando iptables -C devuelve un estado distinto de cero.

sudo iptables -C INPUT -i lo -p tcp --dport 18086 -j ACCEPT 2>/dev/null || echo "Lab allow rule removed"

Deberías ver:

Lab allow rule removed

Por último, confirma que eliminar la regla explícita no detuvo la aplicación. La política y las reglas originales de la cadena vuelven a determinar el acceso.

curl --noproxy '*' --fail --silent http://127.0.0.1:18086/health

Resumen

Inspeccionaste la implementación de iptables y la cadena INPUT, insertaste y comprobaste una regla de rechazo específica, demostraste su efecto mediante tráfico real y contadores, la sustituiste por una regla de разрешение y eliminaste únicamente el cambio realizado por el laboratorio. Estas operaciones proporcionan la práctica necesaria a nivel de comandos para trabajar de forma segura con el filtrado de paquetes sin vaciar el estado no relacionado del cortafuegos.