[OpenBSD]

[Anterior: Tablas] [Contenido] [Siguiente: Traducción de Direcciones de Red]

PF: Filtrado de Paquetes


Índice de Contenidos


Introducción

La acción de filtrar paquetes es bloquear o permitir el paso a los paquetes de datos de forma selectiva, según van llegando a una interfaz de red. Los criterios que usa pf(4) para inspeccionar los paquetes los toma de la información existente en la capa 'Layer 3' (IPv4 y IPv6) y en la capa 'Layer 4' (TCP, UDP, ICMP, y ICMPv6) de las cabeceras de los paquetes. Los criterios que más se utilizan son los de la dirección de origen y de destino, el puerto de origen y de destino, y el protocolo.

Las reglas de filtrado especifican los criterios con los que debe concordar un paquete y la acción a seguir, bien sea bloquearlo o permitir que pase, que se toma cuando se encuentra una concordancia. Las reglas de filtrado se evalúan por orden de secuencia, de la primera a la última. A menos que el paquete concuerde con una regla que contenga la clave quick, se evaluará el paquete comparándolo con todas las reglas de filtrado antes de decidir una acción final. La última regla que concuerde será la «ganadora» y la que dictamine qué acción se tomará con el paquete. Al final del grupo de reglas de filtrado hay un pass all implícito que indica que si algún paquete no concuerda con ninguna de las reglas de filtrado, la acción a seguir será pass, o sea permitirle el paso.

Sintaxis de las Reglas

La sintaxis general, muy simplificada, para las reglas de filtrado es:

action direction [log] [quick] on interfaz [af] [proto protocol] \
   from src_addr [port src_port] to dst_addr [port dst_port] \
   [tcp_flags] [state]
action
La acción a seguir para los paquetes que concuerden, ya sea pass o block. La acción pass permitirá el paso al paquete de vuelta hasta el núcleo del sistema, para que éste lo procese, mientras que la acción block actuará según se indique en la configuración de la opción de la política de bloqueo, block-policy. La acción predeterminada se puede anular especificando block drop (bloquear y eliminar el paquete) o block return (bloquear y devolver el paquete).
direction
La dirección en la que se mueve el paquete en una interfaz, que será in (entrante) o out (saliente).
log
Indica que se debe registrar el paquete por medio de pflogd(8). Si la regla especifica la opción keep state, modulate state, o synproxy state entonces sólo se registrará el paquete que establezca el estado. Para registrar todos los paquetes hay que usar la opción log-all.
quick
Si un paquete concuerda con una regla que especifique la opción quick, entonces esa regla se considera como la regla final de concordancia para el paquete, y se tomará la acción que esté especificada en action sin más dilación.
interfaz
El nombre de la interfaz de red a través de la cual se mueve el paquete.
af
La familia de direcciones del paquete, que será inet para IPv4 ó inet6 para IPv6. Generalmente, PF es capaz de determinar este parámetro basándose en la dirección, o direcciones, de origen y/o de destino.
protocol
El protocolo de la capa 'Layer 4' del paquete:
src_addr, dst_addr
La dirección de origen y/o de destino en la cabecera IP. Las direcciones se pueden especificar como:
src_port, dst_port
El puerto de origen y/o de destino en la capa 'Layer 4' de la cabecera IP. Los puertos se pueden especificar como:
tcp_flags
Especifica los indicadores que deben existir en la cabecera TCP cuando se usa proto tcp. Los indicadores se especifican como flags check/mask. Por ejemplo, flags S/SA instruye a PF para que sólo mire los indicadores S y A (SYN y ACK), y que acepte la concordancia si el indicador SYN está activo ("on").
state
Especifica si se guarda la información sobre el estado en paquetes que concuerden con esta regla.

Denegación Predeterminada

La práctica recomendada para configurar un cortafuegos es la de tomar una aproximación de «denegación predeterminada»; o sea, denegar el paso a todo y a partir de ahí ir permitiendo el paso a través del cortafuegos de forma selectiva a cierto tráfico. Esta aproximación es la recomendada ya que los posibles fallos se cometerían a favor de la seguridad, y también por que hace más fácil la creación de grupos de reglas.

Para crear una política de filtrado de denegación predeterminada, las primeras dos reglas deben ser:

block in  all
block out all

Con esto se bloquea todo el tráfico en todas las interfaces en cualquier dirección, y desde cualquier origen, hasta cualquier destino.

Paso de Tráfico

Ahora hay que permitir de forma explícita y selectiva el paso del tráfico a través del cortafuegos, o de lo contrario será bloqueado por la política de denegación predeterminada. Aquí es donde entran en juego los criterios del paquete, como son el puerto de origen/destino, la dirección de origen/destino, y el protocolo. Siempre que se permita el paso de cierto tráfico a través del cortafuegos hay que escribir las reglas de un modo tan restrictivo como sea posible. Esto es para asegurarse de que sólo pasará el tráfico que se permita, y ningún otro.

Algunos ejemplos:

# Permitir el paso al tráfico entrante en la interfaz dc0 de la red local,
# 192.168.0.0/24, hacia la dirección IP 192.168.0.1 de la máquina de OpenBSD.
# También permitir el paso al tráfico saliente que es enviado de vuelta en dc0.
pass in  on dc0 from 192.168.0.0/24 to 192.168.0.1
pass out on dc0 from 192.168.0.1 to 192.168.0.0/24


# Permitir el paso al tráfico entrante TCP en la interfaz fxp0 del servidor
# de web que se encuentra en la máquina de OpenBSD. El nombre de la
# interfaz, fxp0, se usa como la dirección de destino para que los paquetes
# sólo concuerden con esta regla si tienen como destino la máquina de OpenBSD.
pass in on fxp0 proto tcp from any to fxp0 port www

La Clave quick

Como se ha indicado anteriormente, cada paquete se evalúa con el grupo de reglas de filtrado, desde la primera hasta la última. El resultado predeterminado es el de marcar el paquete para que se le permita el paso; esto puede cambiar con cualquiera de las reglas por las que pasa, y podría cambiar varias veces antes de llegar al final de las reglas de filtrado. La última regla con la que concuerde marcará el resultado. Existe una excepción para esto: la opción quick en una regla de filtrado tiene el efecto de cancelar el procesamiento de cualquier regla consiguiente, y provoca que se ejecute la acción especificada sin más dilación. Veamos un par de ejemplos:

Mal:

block in on fxp0 proto tcp from any to any port ssh
pass  in all

En este caso, la línea block puede ser evaluada, pero nunca tendrá ningún efecto, ya que va seguida por una línea que permite el paso de todo.

Mejor:

block in quick on fxp0 proto tcp from any to any port ssh
pass  in all

Estas reglas se evalúan de una forma algo diferente. Si un paquete concuerda con la línea block, debido a la naturaleza de la opción quick, se bloqueará el paso a dicho paquete y se ignorará el resto del grupo de reglas.

Mantenimiento del Estado

Una de las funcionalidades importantes de PF es la del «mantenimiento del estado» (keeping state) o «inspección completa del estado» (stateful inspection). La inspección del estado se refiere a la capacidad de PF de llevar un seguimiento del estado, o del progreso, de una conexión de red. Almacenando información sobre cada conexión en una tabla de estado, PF puede determinar rápidamente si un paquete que está pasando a través del cortafuegos pertenece a una conexión ya establecida. Si es así, se le permite pasar a través del cortafuegos sin tener que pasar a través de la evaluación del grupo de reglas.

El mantenimiento del estado tiene muchas ventajas, entre otras que los grupos de reglas son más simples y se obtiene un rendimiento más alto del filtrado de paquetes. PF puede puede hacer que los paquetes que vayan en cualquier dirección concuerden con entradas en la tabla de estado, lo que quiere decir que no es necesario escribir reglas de filtrado que permitan el paso del tráfico de vuelta. Y, como los paquetes que concuerdan con conexiones stateful no pasan a través de la evaluación del grupo de reglas, el tiempo que tarda PF en procesarlos puede reducirse considerablemente.

Cuando una regla tiene la opción keep state, el primer paquete que concuerda con ella crea un estado entre el remitente y el destinatario. A partir de ahí, los paquetes que vayan desde el remitente hacia el destinatario no serán los únicos que concuerden con la entrada de estado y que circunvalen la evaluación de las reglas, sino que también lo harán los paquetes de respuesta desde el destinatario hacia el remitente. Por ejemplo:

pass out on fxp0 proto tcp from any to any keep state

Esta regla permite el paso de cualquier tráfico TCP saliente en la interfaz fxp0, y también permite que el tráfico de respuesta pase de vuelta a través del cortafuegos. El mantenimiento del estado es una funcionalidad muy útil, y su uso mejora de forma significativa el rendimiento del cortafuegos, ya que las búsquedas de estados son mucho más rápidas que la evaluación de un paquete a través de todas las reglas de filtrado.

La opción de «modulación del estado», modulate state, funciona como keep state, con la diferencia que sólo es válida para paquetes TCP. Con modulate state, el ISN de las conexiones salientes es aleatorio. Esta opción es útil para proteger conexiones que hayan sido iniciadas por ciertos sistemas operativos que realizan un pobre trabajo al escoger ISNs.

Mantenimiento del estado en paquetes TCP, UDP y ICMP salientes y ISN TCP modulados:

pass out on fxp0 proto tcp from any to any modulate state
pass out on fxp0 proto { udp, icmp } from any to any keep state

Otra ventaja del mantenimiento del estado es que el tráfico ICMP correspondiente pasará a través del cortafuegos. Por ejemplo, si se especifica keep state para una conexión TCP y llega un mensaje ICMP de «requerimiento de ralentización» (source quench ICMP message; es un mensaje de respuesta generado por una pasarela o por el anfitrión de destino, y avisando al anfitrión de origen de la conexión para que ralentice el envío de datos) con referencia a esta conexión TCP, se buscará su concordancia con la entrada apropiada de la tabla de estado y pasará a través del cortafuegos.

Es importante tener en cuenta que las conexiones con estado están limitadas a la interfaz en las que han sido creadas. Esto es importante sobre todo en enrutadores y cortafuegos con PF, en especial cuando se ha implementado una política de denegación predeterminada como la que se ha detallado anteriormente. Si un cortafuegos está manteniendo el estado en todas las conexiones salientes en la interfaz externa, hay que permitir el paso de esos paquetes a través de la interfaz interna de forma explícita.

Nótese que las reglas de nat, binat, y rdr crean un estado implícito para las conexiones que concuerden, siempre que la conexión pase por el filtro del grupo de reglas.

Mantenimiento del Estado para UDP

Algunos dicen que «no se puede crear estado con UDP, ya que UDP es un protocolo sin estado». Aunque es cierto que una sesión de comunicación de UDP no tiene ningún concepto de estado (un comienzo y un final de las comunicaciones explícito), esto no tiene ningún impacto en la capacidad de PF para crear estado para una sesión de UDP. En el caso de protocolos sin paquetes de «inicio» ni «final», PF se limita a mantener un seguimiento del tiempo transcurrido desde que ha pasado un paquete que concuerde. Los valores del tiempo agotado (timeout) se pueden configurar en la sección de opciones del fichero pf.conf.

Indicadores de TCP

La concordancia de paquetes TCP basada en indicadores es algo que se suele usar para filtrar paquetes TCP que estén intentando abrir una nueva conexión. Aquí se puede ver una lista de indicadores TCP y sus significados:

Para que PF inspeccione los indicadores TCP durante la evaluación de una regla se usa la clave flags con la sintaxis siguiente:

flags check/mask

La parte mask indica a PF que sólo inspeccione los indicadores especificados, y la parte check especifica qué indicadores deben estar activos ("on") en la cabecera para que ocurra una concordancia.

pass in on fxp0 proto tcp from any to any port ssh flags S/SA

Esta regla permite el paso de tráfico TCP con el indicador SYN activo, y sólo mira a los indicadores SYN y ACK. Un paquete con los indicadores SYN y ECE concordaría con la regla anterior, mientras que un paquete con SYN y ACK, o sólo con ACK, no concordaría.

Nota: la siguiente sintaxis tenía soporte en versiones anteriores de OpenBSD:

. . . flags S

Este soporte ya no existe. Ahora hay que especificar siempre una máscara.

Los indicadores se suelen usar junto con reglas keep state para ayudar a controlar la creación de entradas de estado:

pass out on fxp0 proto tcp all flags S/SA keep state

Esto permitiría la creación de estado en cualquier paquete TCP saliente, con el indicador SYN activado entre los indicadores SYN y ACK.

Hay que tener cuidado con el uso de indicadores; hay que entender qué es lo que se está haciendo y porqué, y tener cuidado con los consejos recibidos de otros ya que muchos suelen ser erróneos. Algunas personas han sugerido la creación de estado «sólo si está activado el indicador SYN, y no otros». Una regla de este tipo terminaría así

     . . . flags S/FSRPAUEW  ¡¡mala idea!!

La teoría es crear estado sólo en el inicio de la sesión TCP, y la sesión debería iniciarse con un indicador SYN, y ninguno otro. El problema es que algunos sitios están empezando a usar el indicador ECN, y cualquier sitio que use ECN e intentara conectar con nosotros sería rechazado por una regla de ese tipo. Una directiva mucho mejor es:

. . . flags S/SAFR

Aunque esto es práctico y seguro, también es necesario comprobar los indicadores FIN y RST si se está aplicando la normalización de paquetes (scrub) sobre el tráfico. El proceso de normalización de paquetes hará que PF bloquee cualquier paquete entrante que lleve una combinación ilegal del indicador TCP (como SYN y FIN o SYN y RST). Es muy recomendable que se normalice siempre el tráfico entrante:

scrub in on fxp0
.
.
.
pass in on fxp0 proto tcp from any to any port ssh flags S/SA \
   keep state

Proxy TCP SYN

Normalmente, cuando un cliente inicia una conexión TCP a un servidor, PF pasa los paquetes del saludo inicial (handshake) entre los dos extremos según llegan. Sin embargo, PF también puede hacer de proxy para el saludo inicial. Con el modo proxy, PF completará el saludo inicial con el cliente, iniciará un saludo inicial con el servidor, y pasará los paquetes entre los dos. La ventaja de este proceso es que no se enviará ningún paquete al servidor antes de que el cliente complete el saludo inicial. Esto elimina la amenaza de que desbordamientos TCP SYN falseados puedan afectar al servidor, debido a que una conexión de un cliente falseado no podrá completar el saludo inicial.

La proxy TCP SYN se activa usando la clave synproxy state en las reglas de filtrado. Ejemplo:

pass in on $ext_if proto tcp from any to $web_server port www \
   flags S/SA synproxy state

En este ejemplo, PF hará de proxy TCP para las conexiones del servidor de web.

Debido al modo en que funciona synproxy state, también incluye la misma funcionalidad que keep state y modulate state.

La proxy SYN no funcionará si PF está funcionando sobre un bridge(4).

Bloqueo de Paquetes Falsificados (Spoofed Packets)

La falsificación de direcciones (spoofing) es cuando un usuario con malas intenciones falsifica la dirección IP de origen en los paquetes que se transmiten, con el objetivo de esconder su dirección real o de suplantar otro nodo en la red. Una vez que el usuario ha falsificado su dirección, puede lanzar un ataque a nivel de red sin revelar la dirección real de origen del ataque, o intentar obtener acceso a servicios de la red que estén restringidos para ciertas direcciones IP.

PF ofrece cierto nivel de protección contra la falsificación de direcciones mediante la clave antispoof:

antispoof [log] [quick] for interface [af]
log
Indica que los paquetes que concuerden se deben registrar en un fichero a través de pflogd(8).
quick
Si un paquete concuerda con esta regla, entonces se considerará que es la regla «ganadora», y finalizará la evaluación del grupo de reglas.
interface
La interfaz de red en la que se va a activar la protección contra las falsificaciones. También puede ser una lista de interfaces.
af
La familia de direcciones para la que se va a activar la protección contra las falsificaciones, y que puede ser inet para IPv4 ó inet6 para IPv6.

Ejemplo:

antispoof for fxp0 inet

Cuando se carga un grupo de reglas, cualquier suceso de la clave antispoof se expandirá en dos reglas de filtrado. Asumiendo que la interfaz fxp0 tuviera una dirección IP 10.0.0.1 y una máscara de subred de 255.255.255.0 (o sea, un /24), la regla antispoof anterior se expandiría así:

block in on ! fxp0 inet from 10.0.0.0/24 to any
block in inet from 10.0.0.1 to any

Estas reglas realizan dos funciones:

NOTA: Las reglas de filtrado resultantes de la expansión de la regla antispoof también bloquearán los paquetes que se envíen por la interfaz de loopback hacia direcciones locales. Es necesario permitir el paso de estas direcciones de forma explícita. Por ejemplo:

pass in quick on lo0 all

antispoof for fxp0 inet

El uso de antispoof se debe restringir a las interfaces a las que se les haya asignado una dirección IP. El uso de antispoof en una interfaz sin una dirección IP resultará en reglas de filtrado como:

block drop in on ! fxp0 inet all
block drop in inet all

Con estas reglas existe el riesgo de bloquear todo el tráfico entrante en todas las interfaces.

Opciones de IP

Por definición, PF bloquea los paquetes con las opciones IP activadas. Esto puede hacer las cosas más difíciles para utilidades de detección de sistemas operativos (OS fingerprinting) como nmap. Si se tiene una aplicación que requiere el paso de estos paquetes, como multidifusión o IGMP, se puede usar la directiva allow-opts:

pass in quick on fxp0 all allow-opts

Ejemplo de Reglas de Filtrado

A continuación tenemos un ejemplo de un grupo de reglas de filtrado. La máquina en la que está funcionando PF actúa como cortafuegos entre una red interna pequeña e Internet. Sólo se muestran las reglas de filtrado; las reglas de queueing, nat, rdr, etc.. se han omitido en este ejemplo.

ext_if  = "fxp0"
int_if  = "dc0"
lan_net = "192.168.0.0/24"

# normalizar los paquetes entrantes
scrub in all

# configurar una política de denegación predeterminada
block in  all
block out all

# permitir el paso del tráfico en la interfaz de loopback
# en cualquier dirección
pass quick on lo0 all

# activar la protección contra la falsificación de direcciones
# para la interfaz interna
antispoof quick for $int_if inet

# permitir sólo conexiones por ssh si provienen
# desde la máquina de confianza, 192.168.0.15;
# usar "block return" para que se envíe un TCP RST
# para cerrar inmediatamente las conexiones bloqueadas;
# usar "quick" para que las reglas "pass" que
# vienen a continuación no anulen esta regla.
block return in quick on $int_if proto tcp from ! 192.168.0.15 \
   to $int_if port ssh flags S/SA

# permitir el paso del tráfico hacia y desde la red local
pass in  on $int_if from $lan_net to any
pass out on $int_if from any to $lan_net

# permitir el paso de paquetes tcp, udp y icmp
# salientes en la interfaz externa (Internet);
# mantener el estado en udp y icmp, y modular
# el estado en tcp.
pass out on $ext_if proto tcp all modulate state flags S/SA
pass out on $ext_if proto { udp, icmp } all keep state

# permitir el paso de las conexiones entrantes de ssh
# en la interfaz externa siempre que su destino NO sea
# el cortafuegos (o sea, aquéllas cuyo destino sea
# una máquina en la red local);  registrar el paquete inicial
# para que podamos ver más tarde quién intenta conectar.
# Usar la proxy tcp syn para la conexión.
pass in log on $ext_if proto tcp from any to { !$ext_if, !$int_if } \
   port ssh flags S/SA synproxy state

[Anterior: Tablas] [Contenido] [Siguiente: Traducción de Direcciones de Red]


[Índice] www@openbsd.org
Originally [OpenBSD: filter.html,v 1.16 ]
$Translation: filter.html,v 1.13 2004/01/04 21:32:07 horacio Exp $
$OpenBSD: filter.html,v 1.12 2004/01/04 22:29:12 horacio Exp $