Páginas

sábado, 6 de diciembre de 2025

FreeBSD 14.3 Cortafuegos PF

Sintaxis actualizada (FreeBSD 14 usa PF de OpenBSD 6.9–7.0 aproximadamente, hay cambios importantes).

# Macros
lan_if   = "re0"
zt_if    = "zt1ocu1pr8e2sac"
wg_if    = "wg0"
lan_net  = "192.168.88.0/24"
zt_net   = "192.168.192.0/24"
my_zt_ip = "192.168.192.204"
lan_ip   = "192.168.88.160"

ssh_port     = "{ 22 }"
nfs_ports_tcp = "{ 111, 892, 2049 }"
nfs_ports_udp = "{ 111, 892 }"

# Opciones
set block-policy return
set ruleset-optimization none
set skip on lo0

match in all scrub (no-df random-id max-mss 1440)

# Tablas
table <bruteforce> persist
table <wg_peers> { 192.168.88.51 }

# LAN confiable
pass in quick on $lan_if from $lan_net to $lan_ip keep state

# WireGuard
pass in quick on $lan_if proto udp from <wg_peers> to $lan_ip port 51820 keep state
pass in quick on $wg_if from $lan_net to any keep state

# Anti-spoofing (excluyendo interfaces internas)
block in quick on ! { $lan_if, $zt_if, $wg_if } from { 192.168.0.0/16, 172.16.0.0/12, 10.0.0.0/8 } to any
block in quick from any to { 127.0.0.0/8, 0.0.0.0/8 }

# Lista negra
block in quick from <bruteforce>

# Salida
pass out quick inet keep state

# ICMP esencial
pass in inet proto icmp all icmp-type { unreach, timex, paramprob } keep state

# ====================== SSH DESDE LAN ======================
pass in quick on $lan_if proto tcp \
    from $lan_net to $lan_ip port $ssh_port \
    flags S/SFRA keep state

# SSH desde ZeroTier con rate-limit
pass in on $zt_if proto tcp from $zt_net to $my_zt_ip port $ssh_port \
    flags S/SFRA keep state \
    (max-src-conn-rate 15/5, overload <bruteforce> flush global)

# DNS para ZeroTier
pass in on $zt_if proto { tcp udp } from $zt_net to $my_zt_ip port 53

# ZeroTier control
pass in quick on $zt_if proto udp from any to any port 9993

# Bloqueo final
block drop in log all

Pasos típicos una vez aplicado el ruleset

Validar sin aplicar

pfctl -nf /etc/pf.conf

Aplicar y verificar

pfctl -f /etc/pf.conf
pfctl -sr          # reglas activas
pfctl -ss          # estados actuales
pfctl -t bruteforce -T show   # IPs en la tabla

Test desde fuera (desde otro host, no desde la propia máquina):

nmap -Pn -p 22,53,111,2049,51820,9993 192.168.88.160

Ver logs en vivo de lo bloqueado:

tcpdump -n -e -ttt -i pflog0

Integrar sshguard o pf-badhost para que <bruteforce> se llene y expire solo:

pkg install sshguard
sysrc sshguard_enable=YES

Y en /usr/local/etc/sshguard.conf apuntar el backend a PF con pfctl.

Cómo crear el archivo de configuración?
Ejecutar el siguiente comando para crear el archivo a partir de la plantilla:

cp /usr/local/etc/sshguard.conf.sample /usr/local/etc/sshguard.conf

Una vez creado, editar /usr/local/etc/sshguard.conf con los parámetros esenciales para que funcione con el firewall PF:

# Backend para PF (requerido)
BACKEND="/usr/local/libexec/sshg-fw-pf"

# Archivos de log a monitorizar
FILES="/var/log/auth.log"

# Umbral de bloqueo (ej: 120 segundos de bloqueo por defecto)
# Formato: <segundos_bloqueo>:<ruta_al_archivo_de_lista_negra>
BLACKLIST_FILE=120:/var/db/sshguard/blacklist.db

# Opcional: subnet a bloquear
IPV4_SUBNET=32
IPV6_SUBNET=128
Nota sobre el BLACKLIST_FILE: Si se encuentra que el umbral de bloqueo definido en sshguard.conf no surte efecto, puede deberse a una configuración por defecto en el script rc.d. Para solucionarlo, se añade la siguiente línea en el archivo /etc/rc.conf:
sshguard_blacklist=""
De esta forma, solo se aplicarán los valores que se definan en el archivo sshguard.conf

Habilitar e iniciar SSHGuard:

sysrc sshguard_enable=YES
service sshguard start

Hacer persistente PF en el arranque:

sysrc pf_enable=YES
sysrc pflog_enable=YES

Comprobar el estado y las IPs bloqueadas:

service sshguard status
pfctl -t sshguard -T show
FreeBSD es genial!.

No hay comentarios:

Publicar un comentario