Esta pagina se ve mejor con JavaScript habilitado

IPFW básico

 ·  🎃 kr0m

La configuración de un firewall es una tarea básica en cualquier sistema operativo sobre todo en servidores, FreeBSD soporta varios sistemas de filtrado de tráfico pf, ipfw e ipfilter. En esta ocasión vamos a centrarnos en ipfw ya que es el firewall nativo de FreeBSD, realizaremos una configuración básico de filtrado como host.

Para entender como funciona IPFW debemos tener claros algunos puntos:

  • Cada regla es asociada con un ID del 1-65534,  el ID indica el orden en el que se procesan las reglas.
  • El ID 65535 es la regla por defecto.
  • Múltiples reglas pueden tener el mismo ID en cuyo caso son aplicadas en el orden en el que fueron añadidas.
  • Cada regla es asociada con un setID del 0-31, los setIDs pueden habilitarse/deshabilitarse individualmente haciendo posible de este modo añadir o eliminar conjuntos de reglas de forma fácil y rápida.
  • Si no se indica un setID por defecto se le asigna el setID 0.

IPFW es un software de firewall estateful por lo que es consciente del estado de las conexiones, hay varios parámetros que nos ayudarán a gestionar dichos estados:

  • setup: Machea cuando se trata del primer SYN del handshake(solo tiene sentido para TCP).
  • keep-state: Crea una entrada en la tabla de reglas dinámicas.
  • check-state: Comprueba si hay alguna entrada que machee en la tabla de reglas dinámicas, si es así se permite el tráfico.

NOTA: Si no hay una regla check-state la tabla de reglas dinámicas se comprobará con la primera regla con los parámetros keep-state o limit.

  • Cuando se machea una regla con la opción keep-state, el firewall creará una regla dinámica que coincidirá con el tráfico bidireccional entre las ips/puertos origen y destino.

  • Mantener el estado de las conexiones nos expone a ataques DoS mediante SYN-flood ya que será posible generar un gran número de reglas dinámicas. Para contrarestar este tipo de ataque se debe utilizar el parámetro limit de IPFW, esta opción limitará el número de sesiones simultáneas por host en la tabla de reglas dinámicas.

Habilitamos el filtrado de tráfico modificando el fichero rc.conf con los siguientes comandos:

sysrc firewall_enable=YES
sysrc firewall_script="/etc/ipfw.rules"
sysrc firewall_logif=YES

NOTA: Si incluimos ipfw dentro del kernel este será cargado siempre de forma independiente de lo que se especifique en el fichero /etc/rc.conf, incluso con firewall_enable=“NO” seguirá cargándolo, la única manera de deshabilitarlo es mediante firewall_type=“open”.

Si metemos alguna regla con el parámetro log podremos ver el tráfico macheado mediante tcpdump en la interfaz ipfw0:

tcpdump -ni ipfw0

En el siguiente ejemplo de traza de tráfico podemos ver que no aparece la interfaz por la que el paquete entró en el sistema:

08:39:38.748123 IP 192.168.69.4.12764 > 192.168.69.14.44: Flags [S], seq 1257330751, win 65535, options [mss 1460,nop,wscale 6,sackOK,TS val 2281838343 ecr 0], length 0

Si queremos ver mas detalles tendremos que habilitar el log a disco:

sysctl net.inet.ip.fw.verbose=1

Para que tras reiniciar siga haciéndolo:

sysrc firewall_logging=YES

NOTA: Configurar firewall_logging=YES es equivalente a configurar net.inet.ip.fw.verbose=1 en /etc/sysctl.conf solo que lo aplica IPFW en el arranque del servicio.

Con esto obtendremos trazas de este estilo:

tail -f /var/log/security

May 15 08:45:09 MightyMax kernel: ipfw: 60000 Deny TCP 192.168.69.4:21542 192.168.69.14:44 in via nfe0

Para deshabilitar el log a disco:

sysctl net.inet.ip.fw.verbose=0
sysrc firewall_logging=NO

A continuación mostramos una configuración básica statefull:

vim /etc/ipfw.rules


#!/bin/sh
# Flush out the list before we begin.
ipfw -q -f flush

# Set rules command prefix
cmd="ipfw -q add"
wanif="em0"
lanif="em1"

# No restrictions on Loopback Interface
$cmd 00010 allow all from any to any via lo0

# Allow dynamic rules table connections
$cmd 00101 check-state

# Allow access to public DNS
# DNS TCP
$cmd 00110 allow tcp from me to 8.8.8.8 53 out via $wanif setup keep-state
$cmd 00110 allow tcp from me to 8.8.4.4 53 out via $wanif setup keep-state
# DNS UDP
$cmd 00111 allow udp from me to 8.8.8.8 53 out via $wanif keep-state
$cmd 00111 allow udp from me to 8.8.4.4 53 out via $wanif keep-state

# Allow outbound HTTP and HTTPS connections
$cmd 00200 allow tcp from me to any 80 out via $wanif setup keep-state
$cmd 00220 allow tcp from me to any 443 out via $wanif setup keep-state

# Allow outbound email connections
$cmd 00230 allow tcp from me to any 25 out via $wanif setup keep-state
$cmd 00231 allow tcp from me to any 110 out via $wanif setup keep-state

# Allow outbound ping
$cmd 00250 allow icmp from me to any out via $wanif keep-state

# Allow outbound NTP
$cmd 00260 allow udp from me to any 123 out via $wanif keep-state

# Allow outbound SSH
$cmd 00280 allow tcp from me to any 22 out setup keep-state

# Allow inbound public pings
$cmd 00310 allow icmp from any to me in via $wanif

# Allow inbound SSH: With stateless rules we dont break our ssh connection each time we restart ipfw service
$cmd 00311 allow tcp from any to me 22 in
$cmd 00312 allow tcp from me 22 to any out

# Deny and log all other connections
$cmd 00499 deny log all from any to any

La misma configuración stateless quedaría así:

#!/bin/sh
# Flush out the list before we begin.
ipfw -q -f flush

# Set rules command prefix
cmd="ipfw -q add"
wanif="em0"
lanif="em1"

# No restrictions on Loopback Interface
$cmd 00010 allow all from any to any via lo0

# Allow access to public DNS
# DNS TCP
$cmd 00110 allow tcp from me to 8.8.8.8 53 out via $wanif
$cmd 00110 allow tcp from 8.8.8.8 53 to me in via $wanif

$cmd 00110 allow tcp from me to 8.8.4.4 53 out via $wanif
$cmd 00110 allow tcp from 8.8.4.4 53 to me in via $wanif

# DNS UDP
$cmd 00111 allow udp from me to 8.8.8.8 53 out via $wanif
$cmd 00111 allow udp from 8.8.8.8 53 to me in via $wanif

$cmd 00111 allow udp from me to 8.8.4.4 53 out via $wanif
$cmd 00111 allow udp from 8.8.4.4 53 to me in via $wanif

# Allow outbound HTTP and HTTPS connections
$cmd 00200 allow tcp from me to any 80 out via $wanif
$cmd 00200 allow tcp from any 80 to me in via $wanif

$cmd 00220 allow tcp from me to any 443 out via $wanif
$cmd 00220 allow tcp from any 443 to me in via $wanif

# Allow outbound email connections
$cmd 00230 allow tcp from me to any 25 out via $wanif
$cmd 00230 allow tcp from any 25 to me in via $wanif

$cmd 00231 allow tcp from me to any 110 out via $wanif
$cmd 00231 allow tcp from any 110 to me in via $wanif

# Allow outbound ping
$cmd 00250 allow icmp from me to any out via $wanif
$cmd 00250 allow icmp from any to me in via $wanif

# Allow outbound NTP
$cmd 00260 allow udp from me to any 123 out via $wanif
$cmd 00260 allow udp from any 123 to me in via $wanif

# Allow outbound SSH
$cmd 00280 allow tcp from me to any 22 out via $wanif
$cmd 00280 allow tcp from any 22 to me in via $wanif

# Allow inbound SSH
$cmd 00311 allow tcp from any to me 22 in via $wanif
$cmd 00312 allow tcp from me 22 to any out via $wanif

# Deny and log all other connections
$cmd 00499 deny log all from any to any

Arrancamos el servicio:

service ipfw start

Para listar las reglas cargadas ejecutaremos:

ipfw list

Para listar reglas con el timestamp del último match:

ipfw -t list

Un truco interesante si estamos configurando el firewall de un servidor remoto es dejar un screen con un sleep y un stop del servicio de firewalling, de este modo si nos quedamos incomunicados a los Xs se reestablecerá el acceso:

screen -S fwStop
sleep 30 && service ipfw stop

En otra consola o desatacheándonos de la sesión de screen cargamos las reglas a probar, si algo saliese mal tan solo tendríamos que esperar 30s.

Si te ha gustado el artículo puedes invitarme a un RedBull aquí