Páginas

Mostrando entradas con la etiqueta Cortafuegos. Mostrar todas las entradas
Mostrando entradas con la etiqueta Cortafuegos. Mostrar todas las entradas

jueves, 3 de septiembre de 2026

FreeBSD 14.4 WireGuard VPN Surfshark

1. Conectar Surfshark VPN WireGuard FreeBSD 14.4
Análisis de la tabla de rutas

ifconfig

  em0: flags=8842<BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=4e524bb<RXCSUM,TXCSUM,VLAN_MTU,VLAN_HWTAGGING,JUMBO_MTU,VLAN_HWCSUM,LRO,WOL_MAGIC,VLAN_HWFILTER,VLAN_HWTSO,RXCSUM_IPV6,TXCSUM_IPV6,HWSTATS,MEXTPG>
	ether e4:b9:7a:6b:96:cd
	media: Ethernet autoselect
	status: no carrier
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
lo0: flags=1008049<UP,LOOPBACK,RUNNING,MULTICAST,LOWER_UP> metric 0 mtu 16384
	options=680003<RXCSUM,TXCSUM,LINKSTATE,RXCSUM_IPV6,TXCSUM_IPV6>
	inet 127.0.0.1 netmask 0xff000000
	inet6 ::1 prefixlen 128
	inet6 fe80::1%lo0 prefixlen 64 scopeid 0x2
	groups: lo
	nd6 options=21<PERFORMNUD,AUTO_LINKLOCAL>
wlan0: flags=8843<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> metric 0 mtu 1500
	options=0
	ether 18:56:80:f8:98:e6
	inet 192.168.88.51 netmask 0xffffff00 broadcast 192.168.88.255
	groups: wlan
	ssid MikroTik-39F9C0 channel 1 (2412 MHz 11g) bssid c4:ad:34:39:f9:c0
	regdomain FCC country US authmode WPA2/802.11i privacy ON
	deftxkey UNDEF AES-CCM 2:128-bit AES-CCM 3:128-bit
	AES-CCM ucast:128-bit txpower 30 bmiss 10 scanvalid 60 protmode CTS
	wme roaming MANUAL
	parent interface: iwm0
	media: IEEE 802.11 Wireless Ethernet OFDM/54Mbps mode 11g
	status: associated
	nd6 options=29<PERFORMNUD,IFDISABLED,AUTO_LINKLOCAL>
pflog0: flags=1000141<UP,RUNNING,PROMISC,LOWER_UP> metric 0 mtu 33152
	options=0
	groups: pflog
wg0: flags=10080c1<UP,RUNNING,NOARP,MULTICAST,LOWER_UP> metric 0 mtu 1420
	options=80000<LINKSTATE>
	inet 10.14.0.2 netmask 0xffff0000
	groups: wg
	nd6 options=109<PERFORMNUD,IFDISABLED,NO_DAD>
tailscale0: flags=1008003<UP,BROADCAST,MULTICAST,LOWER_UP> metric 0 mtu 1280
	options=4080000<LINKSTATE,MEXTPG>
	groups: tun
	nd6 options=109<PERFORMNUD,IFDISABLED,NO_DAD>
	Opened by PID 1452

netstat -rn

Routing tables

Internet:
Destination        Gateway            Flags         Netif Expire
0.0.0.0/1          link#5             US              wg0
default            192.168.88.1       UGS           wlan0
10.14.0.2          link#2             UH              lo0
85.204.70.87       192.168.88.1       UGHS          wlan0
128.0.0.0/1        link#5             US              wg0
192.168.88.0/24    link#3             U             wlan0
192.168.88.51      link#2             UHS             lo0

Ruta por defecto

Ruta por defecto (default) 192.168.88.1 por wlan0 es la ruta genérica, pero no es la que se usa para la mayoría del tráfico.

Rutas VPN (Wireguard)
0.0.0.0/1 y 128.0.0.0/1 ambas apuntan a wg0

Estas dos rutas cubren todo el rango IPv4 (0.0.0.0/1 y 128.0.0.0/1 = 0.0.0.0/0).

Como son más específicas que default, todo el tráfico (excepto las excepciones) se envía por wg0, es decir, por la VPN

Excepción para el servidor VPN

85.204.70.87 va directamente por wlan0 (gateway local)

Esa IP es el endpoint de WireGuard de Surfshark. Sin esta ruta, el tráfico del túnel intetaría pasar por el propio túnel (bucle) y fallaría.

Red local

192.168.88.0/24 por wlan0. Así puedes acceder a tu router, impresoras, etc., sin pasar por la VPN.

IP propia (loopback)

192.168.88.51 y 10.14.0.2 están en lo0 como direcciones locales (para evitar enrutamiento externo).

¿Qué significa esto en la práctica?

Tu IP pública (la que ven los sitios web) es la de Surfshark, no la de tu router.

El tráfico de navegación (HTTP/HTTPS, DNS, etc.) pasa por el túnel WireGuard.

El tráfico local (a tu router, otros PCs en 192.168.88.x) no pasa por la VPN.

El servidor VPN se alcanza directamente por WiFi, sin pasar por el túnel (para evitar bucles).

Tailscale está presente pero no parece estar enrutando tráfico por defecto (quizás solo para acceso a otros nodos).

Destruir lagg0 y limpiar wlan0

sudo ifconfig lagg0 destroy
sudo ifconfig wlan0 destroy

Crear wlan0 limpio con la configuración correcta

sudo ifconfig wlan0 create wlandev iwm0 country ES
sudo ifconfig wlan0 up

Archivo /etc/wpa_supplicant

 
/etc/wpa_supplicant.conf written by wifimgr(8)
ctrl_interface=/var/run/wpa_supplicant
eapol_version=2
fast_reauth=1

network={
	ssid="MikroTik-39F9C0"
	psk=755862a5b1a4ef59e9e62590977a75f5317193637a8629dccb18c40e8638a68e
}

Iniciar wpa_supplicant (si no está corriendo)

sudo wpa_supplicant -B -i wlan0 -c /etc/wpa_supplicant.conf

Esperar a que se asocie (opcional, pero recomendado)

sleep 5
ifconfig wlan0 | grep status

Asignar IP fija y ruta por defecto

sudo ifconfig wlan0 inet 192.168.88.51 netmask 255.255.255.0
sudo route add default 192.168.88.1

Reiniciar WireGuard para que use la nueva interfaz

sudo wg-quick down wg0 && wg-quick up wg0 # 0 sudo service wireguard restart

Archivo /etc/pf.conf

/etc/pf.conf
ext_if="wlan0"
torrent="53541"
vpn_if="wg0"
wireguard="51820"
lan_net="192.168.88.0/24"

set block-policy return
set skip on lo

scrub in on $ext_if all fragment reassemble

table <jails> persist

nat on $ext_if from <jails> to any -> ($ext_if:0)
rdr-anchor "rdr/*"

block in all

antispoof for $ext_if inet

# Salida: todo el tráfico local permitido y trackeado
pass out quick keep state

# Entrada SSH
pass in quick inet proto tcp from $lan_net to any port ssh flags S/SA keep state

# Entrada VPN WireGuard (túnel Surfshark)
pass in quick on $vpn_if all keep state
pass out quick on $vpn_if all keep state

# Entrada qBittorrent
pass in quick on $ext_if inet proto { tcp } to port $torrent

# Entrada ICMP básico (diagnóstico)
pass in quick on $ext_if inet proto { icmp } all icmp-type { echoreq, unreach }

Verificar

¿La ruta por defecto apunta a wlan0 y las rutas VPN cubren el resto?

netstat -rn | grep -E "(default|wg0|wlan0)"

¿WireGuard está activo?

wg show 
interface: wg0
  public key: pkpZvkWaVDd6DmEb3cl9DEvsnOKl9dvZVAP+KMJLZCs=
  private key: (hidden)
  listening port: 58461

peer: AsvLuvKKAGdc67aA/vHA3vb61S6YnDGx2Pd4aP4wal8=
  endpoint: 82.102.18.179:51820
  allowed ips: 0.0.0.0/0
  latest handshake: 1 minute, 14 seconds ago
  transfer: 1.39 MiB received, 1.51 MiB sent

ping -c 8.8.8.8

Mostrar la IP pública (la IP de Surfshark)

curl -s ifconfig.me
FreeBSD es genial!.

sábado, 13 de diciembre de 2025

NFS sobre TLS FreeBSD 14.3

Configurar Cifrado NFS sobre TLS


El tráfico NFS está cifrado. Autenticación sigue siendo AUTH_SYS (UID/GID)

NFS sobre TLS proporciona cifrado en tránsito (cifrado del tráfico RPC/TLS) sin necesidad de Kerberos. Utiliza certificados X.509 (pueden ser auto-firmados para entornos locales).

Preparación (en el servidor y cliente) Resolución DNS correcta (tormenta.local.com -> 192.168.88.160)
El kernel en FreeBSD 14.3 soporta KTLS (está en Generic desde FreeBSD 13+)


En ambos dos editar /etc/rc.conf para habilitar los daemons TLS:

tlsservd_enable="YES"  # Demonio servidor TLS (necesario para mounts TLS)
tlsclntd_enable="YES"  # Demonio cliente TLS


En el servidor tormenta.local.com - 192.168.88.160


Instalar y configurar Unbound en el servidor


Generación y Colocación de Certificados


Generar los certificados y moverlos a la carpeta que tlsservd exige por defecto.

Crear directorio temporal para trabajar

mkdir -p /root/certs-work
cd /root/certs-work

Crear CA

openssl genrsa -out ca.key 4096
openssl req -new -x509 -days 3650 -key ca.key -out ca.crt -subj "/CN=HomeLabRootCA"

Crear Certificado Servidor (tormenta)

openssl genrsa -out server.key 4096
openssl req -new -key server.key -out server.csr -subj "/CN=tormenta.local.com"
openssl x509 -req -days 3650 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

Crear Certificado Cliente (solaris) - se usará luego

openssl genrsa -out client.key 4096
openssl req -new -key client.key -out client.csr -subj "/CN=solaris.local.com"
openssl x509 -req -days 3650 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 02 -out client.crt

Instalacion en rutas por defecto del servidor


Crear el directorio

mkdir /etc/rpc.tlsservd

Copiar archivos con los nombres que FreeBSD espera:

cp server.crt /etc/rpc.tlsservd/cert.pem
cp server.key /etc/rpc.tlsservd/certkey.pem
cp ca.crt     /etc/rpc.tlsservd/cacert.pem

Crear lista de revocación vacía (necesaria por defecto)

touch /etc/rpc.tlsservd/crl.pem

Permisos estrictos

chmod 700 /etc/rpc.tlsservd
chmod 600 /etc/rpc.tlsservd/certkey.pem
chmod 444 /etc/rpc.tlsservd/cert.pem
chmod 444 /etc/rpc.tlsservd/cacert.pem

En el cliente (solaris.local.com) IP 192.168.88.51


Preparar directorios y certificados

mkdir /etc/rpc.tlsclntd

Copiar los archivos generados en tormenta hacia solaris y renombrarlos

scp tormenta.local.com:/root/certs-work/client.crt /etc/rpc.tlsclntd/cert.pem
scp tormenta.local.com:/root/certs-work/client.key /etc/rpc.tlsclntd/certkey.pem
scp tormenta.local.com:/root/certs-work/ca.crt /etc/rpc.tlsclntd/cacert.pem

Aplicar permisos estrictos

chmod 700 /etc/rpc.tlsclntd
chmod 600 /etc/rpc.tlsclntd/certkey.pem
chmod 444 /etc/rpc.tlsclntd/cert.pem
chmod 444 /etc/rpc.tlsclntd/cacert.pem
chmod 644 /etc/rpc.tlsclntd/crl.pem

client.crt Es el certificado público del cliente. Identifica quién es el cliente. client.key Es la clave privada del cliente. Nunca debe compartirse. Sirve para firmar la comunicación. cacert.pem Es el certificado de la Autoridad Certificadora. Sirve para que el cliente verifique que el servidor es confiable.

Es importante saber que cambiar la extensión del archivo no cambia su contenido, pero ayuda al software a entender qué formato esperar.

PEM (Privacy Enhanced Mail): Es el formato estándar de texto (Base64) que empieza con 
-----BEGIN CERTIFICATE-----

Verificar que la Clave Privada y el Certificado coinciden

Este es el paso más crítico. Ambos archivos deben tener el mismo "Módulo" (un identificador matemático único). Si los códigos hash que obtienes son idénticos, son pareja.

Ejecuta estos dos comandos:

# Extraer el módulo del certificado público
openssl x509 -noout -modulus -in cert.pem | openssl md5

# Extraer el módulo de la clave privada
openssl rsa -noout -modulus -in certkey.pem | openssl md5

Resultado esperado: Ambos comandos deben devolver exactamente la misma cadena de caracteres (ej. (stdin)= 68b19a0d...). Si son diferentes, esa clave no pertenece a ese certificado.

Verificar que el Certificado fue firmado por la CA

Ahora comprobaremos la cadena de confianza. Queremos confirmar que cert.pem es "hijo" legítimo de cacert.pem. Ejecutando

openssl verify -CAfile cacert.pem cert.pem
cert.pem: OK

Resultado esperado: Deberías ver un mensaje final que diga: cert.pem: OK

Comprobar validez de las fechas

openssl x509 -noout -dates -in cert.pem
notBefore=Dec  9 20:38:11 2025 GMT
notAfter=Dec  7 20:38:11 2035 GMT

Crear lista de revocación vacía (necesaria por defecto)

touch /etc/rpc.tlsservd/crl.pem

Modificar /etc/exports para requerir TLS

Solo la linea V4: puede tener opciones de seguridad.

V4: /nfsv4 -tls
/nfsv4/dellhome		-maproot=root -network 192.168.88.0/24
/nfsv4/poolrecovery 	-maproot=root -network 192.168.88.0/24
/nfsv4/docs 		-maproot=root -network 192.168.88.0/24
/nfsv4/confsolaris 	-maproot=root -network 192.168.88.0/24
/nfsv4/conftormenta 	-maproot=root -network 192.168.88.0/24

Aplicar cambios

service nfsuserd restart
service mountd restart
service nfsd restart

Cliente solaris.local.com (192.168.88.51)


Montar con TLS (temporal)

mount -t nfs -o nfsv4,tls tormenta.local.com:/docs /punto/de/montaje

Permanente (en /etc/fstab)

...
# nfs
tormenta:/poolrecovery    /nisc4    nfs     rw,nfsv4,tls,noatime,bg    	0  	0
tormenta:/confsolaris     /nics4    nfs     rw,nfsv4,tls,noatime,bg	0  	0
tormenta:/docs            /nids4    nfs     rw,nfsv4,tls,noatime,bg    	0  	0
tormenta:/dellhome 	  /nihs4    nfs     ro,nfsv4,tls,noatime,bg	0  	0
mount -a

Servidor - configuración de servicios /etc/rc.conf


NFS y RPC

nfs_server_enable="YES"
nfsv4_server_enable="YES"
nfsuserd_enable="YES"

TLS demonio (servidor)

sysrc tlsservd_enable="YES"

Habilitar Kernel TLS

sysctl kern.ipc.tls.enable=1
echo 'kern.ipc.tls.enable=1' >> /etc/sysctl.conf

Recomendación: La seguridad debe ser en capas (Defensa en profundidad): Firewall + Restricción de IP NFS + Certificados TLS.

sysrc statd_enable="YES"   # Para bloqueo de archivos (opcional pero recomendado)
sysrc lockd_enable="YES    # Para bloqueo de archivos 
sysrc mountd_flags="-r"    # Recarga automatica al compartir datasets

Iniciar servicios

service tlsservd start
service nfsuserd restart
service mountd restart
service nfsd restart

Cliente (solaris.local.com) Configuración (/etc/rc.conf)

nfs_client_enable="YES"
nfsv4_client_enable="YES"
nfsuserd_enable="YES"

# TLS demonio (cliente)
tlsclntd_enable="YES"

Iniciar servicios

service nfsclient start
service nfsuserd start

Habilitar Kernel TLS

sysctl kern.ipc.tls.enable=1
echo 'kern.ipc.tls.enable=1' >> /etc/sysctl.conf

Iniciar cliente

service nfsuserd start
service tlsclntd start

Prueba de montaje

mkdir -p /mnt/docs
mount -t nfs -o nfsv4,tls 192.168.88.160:/docs /mnt/docs

Verificar cifrado

root@solaris:~# nfsstat -m
tormenta:/docs on /nids4
nfsv4,minorversion=2,tcp,resvport,tls,nconnect=1,hard,cto,sec=sys,acdirmin=3,acdirmax=60,acregmin=5,acregmax=60,nametimeo=60,negnametimeo=60,rsize=65536,wsize=65536,readdirsize=65536,readahead=1,wcommitsize=16777216,timeout=120,retrans=2147483647

Debe aparecer tls en las banderas (flags)

nfsstat -m
root@solaris:~# nfsstat -m
tormenta:/poolrecovery on /nisc4
nfsv4,minorversion=2,tcp,resvport,tls,nconnect=1,hard,cto,sec=sys,acdirmin=3,acdirmax=60,acregmin=5,acregmax=60,nametimeo=60,negnametimeo=60,rsize=65536,wsize=65536,readdirsize=65536,readahead=1,wcommitsize=16777216,timeout=120,retrans=2147483647

tormenta:/confsolaris on /nics4
nfsv4,minorversion=2,tcp,resvport,tls,nconnect=1,hard,cto,sec=sys,acdirmin=3,acdirmax=60,acregmin=5,acregmax=60,nametimeo=60,negnametimeo=60,rsize=65536,wsize=65536,readdirsize=65536,readahead=1,wcommitsize=16777216,timeout=120,retrans=2147483647

tormenta:/docs on /nids4
nfsv4,minorversion=2,tcp,resvport,tls,nconnect=1,hard,cto,sec=sys,acdirmin=3,acdirmax=60,acregmin=5,acregmax=60,nametimeo=60,negnametimeo=60,rsize=65536,wsize=65536,readdirsize=65536,readahead=1,wcommitsize=16777216,timeout=120,retrans=2147483647

tormenta:/dellhome on /nihs4
nfsv4,minorversion=2,tcp,resvport,tls,nconnect=1,hard,cto,sec=sys,acdirmin=3,acdirmax=60,acregmin=5,acregmax=60,nametimeo=60,negnametimeo=60,rsize=65536,wsize=65536,readdirsize=65536,readahead=1,wcommitsize=16777216,timeout=120,retrans=2147483647

Regla simple:

tlsservd (TLS Server Daemon): Es para la máquina que OFRECE los archivos (el Servidor). Escucha las peticiones de cifrado entrantes.
tlsclntd (TLS Client Daemon): Es para la máquina que MONTA los archivos (el Cliente). Inicia la petición de cifrado hacia afuera.

Verificar con tcpdump que el tráfico NFS sobre TLS está cifrado

Una vez que el montaje NFS con TLS funciona correctamente, se puede confirmar que el tráfico está realmente cifrado ejecutando tcpdump en el servidor o en el cliente.

Comando básico (en servidor)

tcpdump -i re0 -nn port 2049

O más específico, ver sólo NFS

tcpdump -i re0 -nn port 2049 and host 192.168.88.51

Qué esperar

Si TLS está funcionado correctamente - cifrado activo Verás paquetes TCP en el puerto 2049 Después del handshake TLS inicial, todo el payload de los paquetes estará cifrado.

...
13:35:28.349050 IP 192.168.88.160.2049 > 192.168.88.51.773: Flags [P.], seq 469255:469785, ack 251188, win 29128, options [nop,nop,TS val 505937474 ecr 417283551], length 530
13:35:28.349301 IP 192.168.88.51.773 > 192.168.88.160.2049: Flags [.], ack 469785, win 4344, options 
...

No verás texto legible como nombre de archivos, rutas, ni datos de ficheros. Todo será binario cifrado.

Ejemplo típico de texto claro

NFS request xid ... read fh .../poolrecovery/backup-2025-12-10.gz offset 0 count 32768
Comando más detallado para ver el handshake TLS
tcpdump -i re0 -nn -s 0 -A port 2049
-i <interfaz>
-A imprime cada paquete en formato ASCII (crucial para leer contenido)
-n No convierte direcciones IP a nombres de host (más rápido)

En el cliente solaris echo 'Garantizar cifrado' > /nids4/prueba.txt no podrás ver ni el nombre del archivo ni su contenido.

...
14:10:09.830256 IP 192.168.88.160.2049 > 192.168.88.51.890: Flags [P.], seq 1:115, ack 162, win 29128, options [nop,nop,TS val 3871689747 ecr 1810578769], length 114
E....V..@.....X...X3...z.C........q.2......
...
tcpdump -i re0 -nn port 2049 -c 50

Genera activida en el cliente solaris

ls -ltr /nihs4
...
14:12:35.627829 IP 192.168.88.160.2049 > 192.168.88.51.698: Flags [.], ack 230, win 29128, options [nop,nop,TS val 1928012123 ecr 3657311778], length 0
14:12:35.628036 IP 192.168.88.160.2049 > 192.168.88.51.698: Flags [P.], seq 1:303, ack 230, win 
...

Si solo ves números de secuencia y longitudes, sin nombres de archivos -> cifrado Si ves rutas y operaciones NFS -> sin cifrado (TLS inactivo).

FreeBSD es genial!.

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!.