Rasguñando Netfilter (parte 1)

Probablemente todo el que visita este sitio ha escuchado sobre Netfilter al menos indirectamente, pues su comando principal de configuración es iptables, que se menciona frecuentemente. Netfilter es un conjunto de módulos para el kernel de GNU/Linux que permite filtrar los paquetes de red, o en otras palabras, configurar un poderoso cortafuegos.

Si bien existen algunos proyectos que ofrecen interfaces amistosas para la configuración de un cortafuegos y por debajo traducen la configuración en reglas de netfilter, en mi opinión trabajar directamente con netfilter es más flexible y potente, y no particularmente difícil, una vez que se comprende cómo funciona.

De modo que en esta primera parte comenzaré exponiendo algunos de los conceptos y elementos básicos que necesitan comprenderse para configurar correctamente netfilter.

Tablas

Netfilter tiene cuatro tablas para clasificar las reglas de filtrado:

  • raw (crudo) es la primera tabla que se evalúa antes de activarse el rastreo de conexiones, por lo que puede resultar útil para realizar verificaciones básicas sin consumir recursos del equipo innecesariamente, aunque no se recomienda utilizarla para un verdadero filtrado.
  • mangle (destroce) es la tabla donde pueden alterarse las propiedades de los paquetes y las conexiones, aunque como en esta tabla ya el rastreo de conexiones está activo, también puede utilizarse para realizar verificaciones básicas.
  • nat es la tabla donde se establece la network address translation (traducción de direcciones de red), es aquí donde se realiza el enmascaramiento o reenvío de puertos, etc.
  • filter (filtro) es la tabla donde realmente debe hacerse el filtrado de paquetes, es la predeterminada y por esto su nombre puede omitirse al utilizar el comando iptables.

Cadenas

Cada una de las tablas de netfilter tiene cadenas integradas que clasifican la función que se realiza sobre los paquetes de red.

TablaCadenaFunción
 raw PREROUTING Gestionar los paquetes que entran por alguna interfaz.
 OUTPUT Gestionar los paquetes generados localmente.
 mangle PREROUTING Gestionar los paquetes entrantes antes de enrutarlos.
 INPUT Gestionar los paquetes entrantes con destino al propio equipo.
 FORWARD Gestionar los paquetes que el equipo reenvía.
 OUTPUT Gestionar los paquetes generados localmente antes de enrutarlos.
 POSTROUTING Gestionar los paquetes antes de que salgan.
 nat PREROUTING Gestionar los paquetes entrantes antes de enrutarlos.
 INPUT Gestionar los paquetes entrantes con destino al propio equipo.
OUTPUT Gestionar los paquetes generados localmente antes de enrutarlos.
POSTROUTING Gestionar los paquetes antes de que salgan.
filterINPUT Gestionar los paquetes entrantes con destino al propio equipo.
FORWARD Gestionar los paquetes que el equipo reenvía entre otros dos equipos.
OUTPUT Gestionar los paquetes salientes generados localmente.

Netfilter también permite crear en las distintas tablas cadenas personalizadas para analizar o alterar ciertos paquetes de manera más eficiente. Estas cadenas pueden usarse entonces como destinos.

Interfaces

Netfilter permite especificar para qué interfaces de red queremos aplicar las reglas, como lo, para referirse a la interfaz local (paquetes originados o destinados al propio equipo), o eth0, para referirse a la primera interfaz de ethernet (usualmente utilizada para la LAN). Algo no muy utilizado con el comando iptables pero que conviene tener presente, es que el signo de suma sirve de comodín para especificar más de una interfaz. Por ejemplo, eth+ para referirse a todas las interfaces de ethernet o ppp+ para referirse a todos los enlaces PPP, etc. Sin embargo, hay tablas como raw donde esto puede no funcionar, de modo que es preferible utilizarlo solo en la tabla filter.

Protocolos

Netfilter soporta una variedad de protocolos. Los más comunes son TCP, UDP e ICMP, pero hay muchos más, algunos de los cuales rara vez se utilizan y podrían explotarse para fines maliciosos, por lo que podrían deshabilitarse. Evidentemente que esto dependerá de las necesidades locales, por lo que el administrador debería identificar todos los protocolos que pretende utilizar en su red, para al menos poder marcar como sospechoso el paquete que utilice un protocolo no autorizado.

Puertos

Es importante también identificar qué servicios tenemos habilitados en el servidor, y qué puertos utilizan estos para “escuchar”, de esta manera es más fácil filtrar cualquier petición a un servicio inexistente. En otras palabras, en ocasiones es más simple, claro y seguro crear reglas diciendo por ejemplo “descarta cualquier paquete TCP nuevo cuyo puerto de destino no sea el puerto 80 o 443” que algo como “descarta cualquier paquete TCP nuevo cuyo puerto de destino sea el 0, 1, 2, 3 …” (la lista podría ser larga, pues el kernel de Linux permite 65,536 puertos). Similarmente, es importante identificar cualquier servicio válido que corra en otros equipos de la red, especialmente aquellos servicios que se pretenda exportar al exterior de la red local, pues en este caso habrá que realizar una traducción de direcciones y posiblemente también una redirección de puertos.

Los puertos privilegiados (aquellos entre 0 y 1023) son particularmente importantes, pues en algunos de estos puertos escuchan servicios que se concibieron en los inicios de la expansión de las redes informáticas, cuando se confiaba en que se les daría un uso apropiado. Actualmente algunos de estos servicios que no son particularmente útiles (como MOTD y CharGen, por ejemplo) pueden explotarse maliciosamente para realizar ataques distribuidos de denegación de servicios mediante reflexión con factores de amplificación (mas adelante ilustraremos esto con el servicio NTP), por lo que conviene que estén deshabilitados.

Destinos

En netfilter, cada regla con que se evalúa un paquete debe terminar con el salto a un destino, que define que hacer si el paquete coincide con la regla. De no coincidir, simplemente se continúa evaluando el paquete mediante el resto de las reglas de la cadena. El destino puede ser uno integrado, o también una cadena personalizada. De no coincidir el paquete con ninguna regla, se le aplica el destino establecido en las políticas por defecto. Algunos de los destinos integrados más utilizados o útiles son los siguientes:

DestinoFunción y observaciones
ACCEPTEl paquete se acepta, y no se evalúan más reglas de la cadena.
REJECTEl paquete se rechaza generando un paquete asociado de error explícito (para lo cual se utiliza el protocolo ICMP) y no se evalúan más reglas de la cadena. Este paquete solo es válido en las cadenas INPUT, FORWARD, OUTPUT o en las cadenas personalizadas que partan de estas.
DROPEl paquete se descarta, y no se evalúan más reglas de la cadena.
REDIRECTEl paquete se redirige a la propia máquina cambiando la dirección IP de destino a la dirección primaria de la interfaz por donde entró (los paquetes generados localmente se redirigen a la dirección 127.0.0.1). Solo es válido en las cadenas PREROUTING y OUTPUT de la tabla nat.
MASQUERADEEl paquete se enmascara cambiando la dirección de origen a la de la interfaz de salida. Este destino solo es válido en la cadena POSTROUTING de la tabla nat, y debería utilizarse sólo para enlaces temporales como los de acceso telefónico, pues cuando la interfaz se cae, las conexiones se olvidan. Para direcciones IP estáticas siempre debería utilizarse el destino SNAT.
SNATPermite cambiar la dirección (y opcionalmente el puerto) de origen del paquete. Solo es válido en las cadenas POSTROUTING e INPUT de la tabla nat.
DNATPermite cambiar la dirección (y opcionalmente el puerto) de destino del paquete. Solo es válido en las cadenas PREROUTING y OUTPUT de la tabla nat.
NFLOGPermite la creación una traza del paquete, que se continúa evaluando mediante el resto de las reglas de la cadena.
CTPermite estblecer parámetros de rastreo para un paquete o su conexión asociada. Útil por ejemplo para deshabilitar el rastreo de conexiones en la tabla raw mediante el destino -j CT --notrack.
RETURNFinaliza la evaluación del paquete en la cadena actual y regresa al punto de invocación para continuar con la próxima regla. Debe colocarse al final de las reglas de cada cadena personalizada que creemos.

Estados (rastreo de conexiones)

Una de las características de netfilter es el rastreo de conexiones (Connection Tracking). Para esto, se utiliza un módulo del kernel (nf_conntrack) que permite analizar el tráfico y clasificar los paquetes según los siguientes estados:

  • NEW (nuevo) es el estado que se aplica a los paquetes que inician nuevas conexiones o para los cuales no existe tráfico previo (en el caso de protocolos sin control de estado).
  • RELATED (relacionado) es el estado que se aplica a paquetes relacionados con una conexión para la cual se ha visto tráfico, pero que no son parte de la conexión en si. Ejemplos típicos son las respuestas ICMP de tipo 3 (destino inaccesible), o el protocolo FTP.
  • ESTABLISHED (establecido) es el estado que se aplica a las conexiones una vez que se han establecido y se ha visto tráfico entre equipos.
  • INVALID (inválido) es el estado que se asigna a cualquier paquete con parámetros inesperados o que alegue ser parte de una conexión, pero el rastreo de conexiones no haya visto tráfico asociado a ninguna conexión conocida. La identificación de un paquete como inválido también podría ocurrir como consecuencia de alcanzarse el máximo de entradas permitidas en la tabla de rastreo, o al excederse el tiempo de espera en dicha tabla, por lo que puede ser útil modificar los parámetros del kernel ip_conntrack_max e ip_conntrack_generic_timeout. En el caso del protocolo TCP, el rastreo de conexiones verifica cosas como que el paquete esté en la ventana esperada o tenga un número de secuencia apropiado, aunque puede realizarse una verificación menos estricta utilizando el siguiente parámetro del kernel: net.ipv4.netfilter.ip_conntrack_tcp_loose = 1.
  • UNTRACKED (no rastreado) es el estado que se asigna a cualquier paquete para el cual se haya deshabilitado el rastreo de conexiones en la tabla raw.

Coincidencias

Netfilter incluye muchos módulos o extensiones de coincidencias (matches) que permiten personalizar las reglas en base a muchos criterios diferentes. Entre las muchas coincidencias disponibles se encuentran udp, tcp, multiport, conntrack, etc. Como son tantas, en este caso es mejor consultar la página de manual del comando iptables (mediante el comando man iptables-extensions).

(Continuará)

En la próxima parte de este tema, ejemplificaremos cómo se integran estos elementos para conformar reglas de filtrado.

(Visited 135 times, 1 visits today)
Hugo Florentino
Sobre Hugo Florentino 7 Artículos
Administrador de redes y sistemas. Usuario regular de GNU/Linux desde Octubre de 2008. Miembro fundador del Grupo de Usuarios de Tecnologías Libres (GUTL).

Sé el primero en comentar

Dejar una contestacion

Tu dirección de correo electrónico no será publicada.


*