Páginas

Buscar este blog

jueves, 5 de noviembre de 2026

Cómo arreglar la suspensión y el trackpad en una MacBook Pro 2012 con FreeBSD 14.5

El reto: hacer que una MacBook Pro de 2012 duerma (y despierte)

Instalar FreeBSD en hardware de Apple es un ejercicio de paciencia. Los MacBooks son máquinas excelentes, pero su firmware ACPI y sus controladores propietarios (como el del trackpad o el de la virtualización) no están pensados para colaborar con sistemas operativos que no sean macOS.

Hace unos días me propuse arreglar dos de los problemas más frustrantes de mi MacBook Pro de 2012 con FreeBSD 14.5: conseguir que el equipo suspenda correctamente (S3) sin apagarse, y lograr que el trackpad siga funcionando al despertar. Lo que sigue es el diario de a bordo de cómo lo resolví, con los comandos exactos y las trampas que encontré por el camino. Gran parte de las pistas iniciales las encontré en la excelente guía de Joshua: A Full Guide: FreeBSD on a MacBook Pro 11.4 (A1398).

El hardware: MacBook Pro de 2012 (Ivy Bridge), con FreeBSD 14.5-RELEASE. El sistema usa el driver gráfico i915kms y el sistema de gestión de energía ACPI.

Problema 1: El equipo se apaga en lugar de suspender

Al ejecutar acpiconf -s 3 o cerrar la tapa, el sistema no entraba en S3 (suspensión): se apagaba por completo. El primer paso fue activar el "modo de prueba" de ACPI para ver qué driver estaba fallando. Si el sistema sobrevive al bounce de suspensión, el problema está en la reanudación; si se apaga, el problema está en la preparación.

# Activar el modo de rebote y probar la suspensión
sysctl debug.acpi.suspend_bounce=1
acpiconf -s 3

En mi caso, el equipo se apagaba de golpe. La causa, documentada en la guía de Joshua sobre FreeBSD en MacBooks, era el módulo vmm (el hipervisor de bhyve). Al intentar suspender, el chip de virtualización de Intel se quedaba en un estado inconsistente y el kernel entraba en pánico.

La regla de oro: si usas vm_enable="YES" en /etc/rc.conf, el módulo vmm se carga automáticamente. Este módulo rompe la suspensión en hardware Apple. La solución es descargarlo antes de dormir.

Añadí los siguientes comandos a los scripts de suspensión y reanudación de FreeBSD para gestionar vmm automáticamente:

# En /etc/rc.suspend (antes del exit 0)
/sbin/kldunload -f vmm

# En /etc/rc.resume (después de los sync)
/sbin/kldload vmm

Con esto, el equipo ya entraba en suspensión sin apagarse. El primer gran obstáculo estaba superado.

Problema 2: El trackpad se queda "muerto" al despertar

Una vez resuelta la suspensión, apareció el segundo problema (y el más puñetero). Al despertar, el trackpad dejaba de responder por completo. En FreeBSD 14, los drivers para el hardware de Apple (wsp y atp) ya vienen compilados en el kernel o se cargan automáticamente. El conflicto surge porque, tras la reanudación, el driver atp se le adelanta al wsp y secuestra el dispositivo, dejando el trackpad inoperativo.

Comprobé qué driver tenía el control tras el arranque:

usbconfig -d ugen2.9 show_ifdrv

# Salida:
# ugen2.9.0: ukbd0: <Apple Inc. Apple Internal Keyboard / Trackpad>
# ugen2.9.1: atp0: <Apple Inc. Apple Internal Keyboard / Trackpad>
# ugen2.9.2: ums0: <Apple Inc. Apple Internal Keyboard / Trackpad>

Ahí estaba el conflicto: los drivers atp0 y ums0 estaban capturando el dispositivo, impidiendo que el driver correcto de Apple, wsp, pudiera inicializar el trackpad. Tras probar varios quirks en el loader.conf (sin éxito), el descubrimiento clave fue ejecutar manualmente el siguiente comando al despertar:

/usr/sbin/devctl detach atp0

¡Bingo! Al liberar atp0, el trackpad volvía a la vida inmediatamente. El problema era que atp0 secuestraba el dispositivo durante la reanudación, bloqueando la carga de wsp y dejando el hardware inoperativo.

La solución final: automatizar la liberación del driver

El comando devctl detach funcionaba a mano, pero al meterlo en /etc/rc.resume fallaba porque se ejecutaba antes de que el bus USB hubiera registrado atp0. La solución fue crear un bucle de espera que intentara desconectar el driver varias veces hasta que el dispositivo estuviera listo:

# En /etc/rc.resume (al final, antes del exit 0)
# Esperar a que atp0 aparezca y luego desconectarlo
for i in $(seq 1 20); do
    if /usr/sbin/devctl detach atp0 2>/dev/null; then
        break
    fi
    sleep 0.5
done

Este bucle espera hasta 10 segundos (20 intentos de 0,5 segundos) para que atp0 esté disponible. En cuanto lo detecta, lo desconecta, liberando el trackpad para que wsp lo recupere.

Archivos finales de configuración

Para que todo quede documentado, estos son los archivos clave tal y como quedaron en mi sistema:

/boot/loader.conf

No se necesitan módulos adicionales para los drivers del trackpad: vienen en el kernel.

kern.geom.label.disk_ident.enable="0"
kern.geom.label.gptid.enable="0"
cryptodev_load="YES"
zfs_load="YES"
asmc_load="YES"
coretemp_load="YES"
hint.hdaa.0.nid21.config="as=1 seq=15"
hint.hdaa.0.nid20.config="as=1 seq=0"
acpi_video_load="YES"
screen.font="8x14"
loader_logo="beastie"
autoboot_delay="3"

/etc/rc.suspend

# ... (código base del script)
# Descargar vmm antes de dormir
/sbin/kldunload -f vmm

/bin/rm -f /var/run/rc.suspend.pid
if [ $subsystem = "apm" ]; then
	/usr/sbin/zzz
else
	/usr/sbin/acpiconf -k 0
fi

exit 0

/etc/rc.resume

# ... (código base del script)
# Recargar vmm
/sbin/kldload vmm

# Esperar a que atp0 aparezca y luego desconectarlo
for i in $(seq 1 20); do
    if /usr/sbin/devctl detach atp0 2>/dev/null; then
        logger -t resume "Trackpad liberado (atp0 desconectado)"
        break
    fi
    sleep 0.5
done

# Ejecutar scripts de reanudación estándar
files=`rcorder ${rcorder_opts} /etc/rc.d/* ${local_rc} 2>/dev/null`
# ...
exit 0
Consejo de depuración: Añadiendo el logger -t resume dentro del bucle, dejamos constancia en /var/log/messages de que el script hizo su trabajo (o de si falló). Es muy útil para diagnosticar problemas en el futuro.

El resultado: una MacBook Pro renacida

Con estos cambios, la MacBook Pro de 2012 ahora:

  • Suspende correctamente al cerrar la tapa o pulsar el botón de encendido.
  • Despierta sin apagarse, gracias a la gestión de vmm.
  • Recupera el trackpad automáticamente, con gestos y clicks funcionando.
  • Mantiene la red y el resto de periféricos operativos al despertar.
Conclusión: FreeBSD en hardware Apple requiere paciencia, pero es totalmente funcional. El truco está en entender la guerra de drivers (wsp vs atp), gestionar los módulos del kernel (vmm) con scripts de suspensión, y usar devctl detach para liberar dispositivos secuestrados. Con estos ajustes, una MacBook de 2012 puede seguir siendo un portátil productivo con FreeBSD.

FreeBSD es genial!.

sábado, 31 de octubre de 2026

Mejorar Compatibilidad y Conexión MikroTik ax3

Para mejorar la compatibilidad y conexión entre tu MikroTik hAP ax3 y los clientes , el enfoque debe centrarse en ajustar la seguridad y el roaming del router, así como en corregir posibles configuracines del dispositivo cliente. Dado que el ax3 es un router Wi-Fi 6 potente, los problemas suelen derivar de portocolos de seguridad mixtos o funciones de traspaso de red (roaming) que el dispositivo gestiona de forma particular.

1. Si tienes RouterOS 7.13 o superior, usa el menú WiFi (no el antiguo "Wireless") para las interfaces AX.

2. Actualiza RouterOS

3. Configura la Seguridad Híbrida (WPA2/WPA3) mejora la compatibilidad y el roaming en dispositivos.

4. Desactiva "ft-over-ds" (Fast Transition) En la configuración roaming del router (WiFi Interface wifi1 FT), busca la opción FT Over DS y desactiva. (WiFi Interface wifi2 FT), busca la opción FT Over DS y desactiva. Usuarios de MikroTik reportan que esto soluciona problemas de conexión y desconexiones extrañas con dispositivos Samsung y Apple.

5. Prioridad de Conexión. Si tienes para evitar que el cliente se aferre a la banda 2.4GHHz, ajusta el parámetro connect-priority en el perfil de seguridad (prueba con 0/1) para mejorar la experiencia de roaming.

El punto 5, connect-priority (prioridad de conexión), es un mecanismo de RouterOS que controla si un cliente puede conectarse a un nuevo punto de acceso (AP) cuando su dirección MAC ya está asociada a otro AP activo. En esencia, decide qué AP "retiene" al dispositivo cuando hay señales superpuestas.

⚙️ Cómo funciona el parámetro connect-priority

Este parámetro se compone de dos valores separados por una barra: accept-priority/hold-priority (prioridad de aceptación / prioridad de retención). • accept-priority (Prioridad de Aceptación): Define la "predisposición" de un AP a aceptar la conexión de un cliente.

• hold-priority (Prioridad de Retención): Define la "fuerza" con la que un AP retiene a un cliente ya conectado.  La lógica de decisión de RouterOS se basa en comparar estos valores entre dos APs (por ejemplo, tu banda de 5GHz vs. 2.4GHz):

1. Si accept-priority del AP nuevo < hold-priority del AP actual: El cliente se conecta al nuevo AP y se desconecta del anterior. Esto permite un traspaso (roaming) rápido y agresivo.

2. Si accept-priority del AP nuevo = hold-priority del AP actual: El cliente solo se conectará al nuevo AP si ya no puede alcanzar el AP anterior. Esto provoca el efecto "cliente pegajoso" (sticky client), donde el dispositivo se aferra a una señal débil hasta que se pierde por completo.

3. Si accept-priority del AP nuevo > hold-priority del AP actual: El cliente no será aceptado en el nuevo AP, forzándolo a quedarse en el actual. 

Por qué se recomienda 0/1

Por defecto, si solo se configura un número (ej. 0), hold-priority es igual a accept-priority . Esto provoca el escenario 2, que suele ser la causa de que un cliente se quede "colgado" en la banda de 5GHz con mala señal en lugar de cambiar a 2.4GHz.

Al configurar connect-priority=0/1:
• Estableces el accept-priority del AP en 0. • Estableces el hold-priority del AP en 1. 
Como 0 < 1, el AP permitirá que el cliente se conecte a él (por ejemplo, al 2.4GHz) y suelte inmediatamente la conexión del AP anterior (el 5GHz débil), forzando el traspaso de banda de forma efectiva.

Advertencia de seguridad importante
MikroTik y la comunidad han señalado que usar connect-priority=0/1 (o cualquier configuración que permita el traspaso sin verificar que el AP anterior ya no alcanza al cliente) hace que la red sea vulnerable a un ataque conocido como "MacStealer" .‌

• ¿Qué implica?: Un atacante podría potencialmente secuestrar la sesión de un cliente al hacerle creer que está en un AP legítimo, aunque el riesgo real y la facilidad de explotación en redes domésticas son bajos.

• Recomendación: Dado que es una red doméstica, el beneficio de estabilidad y roaming para los clientes probablemente supera el riesgo. Sin embargo, si tienes dispositivos IoT sensibles o realizas actividades críticas, tenlo en cuenta. Si en el futuro configuras una red de invitados aislada (Client Isolation), quizás quieras desactivar esta opción solo para esa red. 
Si tras aplicar 0/1 notas que el móvil ya no se queda "pegado" a la señal débil y el roaming es fluido, has resuelto el problema de raíz.
FreeBSD es genial!.

domingo, 25 de octubre de 2026

Proyecto ax3 (4/4) - Doble túnel WireGuard con Address Lists

Proyecto ax³ (4/4) — Doble túnel WireGuard: España y Marsella
Serie completa: Índice · Parte 1 · Parte 2 · Parte 3 · Parte 4

Referencia de comandos: Cheatsheet RouterOS — Proyecto ax³

Introducción

En la Parte 3 dejamos el hAP ax³ funcionando con un túnel WireGuard apuntando a un servidor de ProtonVPN en Barcelona. En esta cuarta y última parte, vamos a levantar un segundo túnel simultáneo hacia Marsella y usaremos Address Lists para enrutar el tráfico por dispositivo.

Este enfoque no solo nos permite organizar la red de forma granular, sino que separa una configuración doméstica de una infraestructura profesional: podremos añadir decenas de dispositivos y cambiar su país de salida con un solo clic, sin tocar el firewall.

Requisito previo: Esta parte asume que el túnel principal Barcelona de la Parte 3 funciona correctamente. Haz un backup antes de empezar.

Copia de seguridad

/system backup save name=ax3-dual-20261024-vpn-marsella-barcelona-OK 
/export compact file=ax3-dual-20261024-vpn-marsella-barcelona-OK

Fase 8 — El desafío del doble túnel

Configurar dos túneles VPN simultáneos hacia el mismo proveedor (ProtonVPN) nos obligará a sortear tres problemas que, si no se controlan, romperán la red:

  1. Conflicto de IP interna: ProtonVPN asigna la misma IP interna a todos los perfiles (ej. 10.2.0.2/32).
  2. Conflicto de puerto: Dos interfaces WireGuard no pueden usar el mismo puerto de escucha local.
  3. El bucle del retorno: El tráfico de vuelta del nuevo túnel viene desde una subred interna (10.3.0.0/24) que debe ser excluida del enrutamiento.

Paso 1 — Preparar el perfil de Marsella

Descarga el archivo WireGuard de ProtonVPN para Marsella y edítalo con un editor de texto:

# Original
Address = 10.2.0.2/32

# Modificado
Address = 10.3.0.2/32

Paso 2 — Importar y ajustar la interfaz

En WinBox, ve a WireGuard → Interface → + → Import from file y selecciona el archivo de Marsella.

  • Name: proton-vpn-marsella
  • Listen Port: 13232 (distinto al 13231 de Barcelona).
  • MTU: 1380 (ajustado para evitar fragmentación).

Paso 3 - Tabla de enrutamiento personalizada con FIB activado

El parámetro fib es fundamental para que las rutas de esa tabla se instalen en el Forwarding Information Table y el tráfico realmente se enrute.

/routing table add name=via-vpn-marsella fib

Paso 4 - Crear la tabla de rutas y el Kill Switch

/ip route add dst-address=0.0.0.0/0 gateway=proton-vpn-marsella routing-table=via-vpn-marsella distance=1 comment="Salida por Marsella"
/ip route add dst-address=0.0.0.0/0 blackhole=yes routing-table=via-vpn-marsella distance=2 comment="Kill switch Marsella"

Paso 5 - El detalle de oro: Excluir la red interna del túnel

Este es el paso que evita que la red se rompa. Cuando el tráfico vuelve del túnel, llega a través de la IP interna del mismo. Si no le decimos al router que esa red es "tráfico local", intentará enrutarla por el túnel otra vez, creando un bucle.
/ip firewall address-list add list=lan-directa address=10.3.0.0/24 comment="Red interna Marsella"

Paso 6 - Reglas de Firewall y NAT

# NAT (Masquerade para Marsella)
/ip firewall nat add chain=srcnat action=masquerade src-address=192.168.88.0/24 out-interface=proton-vpn-marsella comment="NAT para Marsella"

# Filter (Permitir LAN a Marsella)
/ip firewall filter add chain=forward in-interface-list=LAN out-interface=proton-vpn-marsella action=accept comment="Permitir LAN a VPN Marsella" place-before=[find comment="Drop todo lo dems"]

Paso 7 - Address Lists y Mangle (La magia)

En lugar de reglas individuales, agrupamos los dispositivos en listas:

# Lista para Marsella
/ip firewall address-list
add list=vpn-marsella address=192.168.88.100 comment="pc100"
add list=vpn-marsella address=192.168.88.101 comment="movil101"
add list=vpn-marsella address=192.168.88.102 comment="tablet102"
add list=vpn-marsella address=192.168.88.103 comment="portatil103"

# Lista para Barcelona
/ip firewall address-list
add list=vpn-barcelona address=192.168.88.201 comment="portatil201"
add list=vpn-barcelona address=192.168.88.202 comment="movil202"
add list=vpn-barcelona address=192.168.88.203 comment="movil203"

Y creamos las reglas genéricas de Mangle (Marcar primero, Enrutar después):

# --- MARSELLA ---
/ip firewall mangle add chain=prerouting src-address-list=vpn-marsella in-interface=bridge action=mark-connection new-connection-mark=conn-marsella passthrough=yes comment="Mangle: Marcar lista Marsella"
/ip firewall mangle add chain=prerouting connection-mark=conn-marsella action=mark-routing new-routing-mark=via-vpn-marsella passthrough=no comment="Mangle: Enrutar lista Marsella"

# --- BARCELONA (ESPAÑA) ---
/ip firewall mangle add chain=prerouting src-address-list=vpn-barcelona in-interface=bridge action=mark-connection new-connection-mark=conn-barcelona passthrough=yes comment="Mangle: Marcar lista Barcelona"
/ip firewall mangle add chain=prerouting connection-mark=conn-barcelona action=mark-routing new-routing-mark=via-vpn passthrough=no comment="Mangle: Enrutar lista Barcelona"
¡Atención con las IPs dinámicas! Las Address Lists funcionan buscando la IP del dispositivo. Si el servidor DHCP de tu router le asigna mañana una IP diferente al dispositivo (ej. pasa de la .100 a la .105), las reglas de Mangle no lo reconocerán y se saltará la VPN.

Obligatorio: Ve a IP → DHCP Server → Leases, busca los dispositivos de tus listas, haz clic derecho y selecciona "Make Static" (o usa el comando /ip dhcp-server lease make-static [find]). Así te aseguras de que su IP nunca cambie y el enrutamiento sea siempre perfecto.

Paso 8 - Ajustar el MSS (Crucial para el rendimiento)

El cálculo del MSS es crítico. Debe ser siempre 40 bytes menor que el MTU de la interfaz. Si el MTU de Marsella es 1380, el MSS debe ser 1340. Un MSS incorrecto provocará que las webs se queden a medio cargar.
/ip firewall mangle add chain=forward protocol=tcp tcp-flags=syn out-interface=proton-vpn-marsella action=change-mss new-mss=1340 passthrough=yes comment="MSS para tunel Marsella (MTU 1380)"

Paso 9 - Limpiar conexiones y probar

/ip firewall connection remove [find src-address~"192.168.88.10"]
/ip firewall connection remove [find src-address~"192.168.88.20"]

Comandos de verificación (El "Checklist" del Administrador)

Para asegurarte de que todo está fluyendo correctamente, ejecuta estas comprobaciones en el MikroTik:

# 1. ¿Los túneles están vivos y con handshake reciente?
/interface wireguard peers print detail

# 2. ¿Puede el router hacer ping a través de Marsella? (Debe ser 0% packet-loss)
/ping 1.1.1.1 interface=proton-vpn-marsella count=3

# 3. ¿Está la tabla de rutas de Marsella activa y con su Kill Switch?
/ip route print where routing-table=via-vpn-marsella

# 4. ¿Están los dispositivos generando tráfico y con la marca correcta?
/ip firewall connection print where src-address~"192.168.88.10"
# (Fíjate en la columna CONNECTION-MARK: debería decir conn-marsella)

# 5. ¿Están subiendo los contadores de las reglas de Mangle?
/ip firewall mangle print stats

Resolución de problemas (Lo que aprendimos a golpes)

Si el túnel se levanta pero los dispositivos no tienen Internet, revisa estos cinco puntos:

  • El "Peer Fantasma": Si al importar el archivo se creó una interfaz con un asterisco (ej. *D) o un peer duplicado con la misma clave pública, el túnel se volverá loco y perderá paquetes. Elimina cualquier peer que no corresponda con su interfaz.
    /interface wireguard peers remove [find name="peerX"]
  • El conflicto de IP: Comprueba en /ip address print que no existe ninguna interfaz llamada unknown. Si existe, bórrala: /ip address remove [find interface=unknown].
  • El firewall bloquea el retorno: Asegúrate de que tienes la regla de accept para out-interface=proton-vpn-marsella antes del Drop general en la cadena forward.
  • El DNS: Si el ping por IP funciona pero las webs no cargan, es un problema de DNS. Asegúrate de que el dispositivo usa Pi-Hole (192.168.88.244) y que el tráfico hacia esa IP no está siendo enrutado por error hacia la VPN (la regla lan-directa lo evita).
  • Las IPs han cambiado: Si de repente un dispositivo deja de ir por la VPN, comprueba en IP → DHCP Server → Leases que sigue teniendo la misma IP que pusiste en la Address List. Si no lo hiciste en su momento, haz clic derecho y selecciona "Make Static".

El flujo de trabajo para alternar países

La ventaja de las Address Lists es que el cambio es instantáneo. Para pasar un dispositivo de Marsella a Barcelona:

  1. Ve a IP → Firewall → Address Lists.
  2. Busca su IP y cambia la columna List de vpn-marsella a vpn-barcelona.
  3. Borra su sesión en el router para forzar el cambio:
    /ip firewall connection remove [find src-address~"192.168.88.100"]
Muy importante: Orden de las reglas
/ip firewall mangle print
Flags: D - DYNAMIC
 0 D ;;; special dummy rule to show fasttrack counters
     chain=prerouting action=passthrough
 
 1 D ;;; special dummy rule to show fasttrack counters
     chain=forward action=passthrough
 
 2 D ;;; special dummy rule to show fasttrack counters
     chain=postrouting action=passthrough
 
 3   ;;; evita problemas de fragmentacion de paquetes
     chain=forward action=change-mss new-mss=1452 passthrough=yes tcp-flags=syn protocol=tcp out-interface=pppoe-o2 log=no
     log-prefix=""
 
 4   ;;; No marcar Trafico LAN
     chain=prerouting action=return dst-address-list=lan-directa log=no log-prefix=""
 
 5   ;;; Mangle: Marcar lista Barcelona
     chain=prerouting action=mark-connection new-connection-mark=conn-barcelona passthrough=yes src-address-list=vpn-barcelona
     in-interface=bridge
 
 6   ;;; Mangle: Marcar lista Marsella
     chain=prerouting action=mark-connection new-connection-mark=conn-marsella passthrough=yes src-address-list=vpn-marsella
     in-interface=bridge
 
 7   ;;; Mangle: Enrutar lista Marsella
     chain=prerouting action=mark-routing new-routing-mark=via-vpn-marsella passthrough=no connection-mark=conn-marsella
 
 8   ;;; Mangle: Enrutar lista Barcelona
     chain=prerouting action=mark-routing new-routing-mark=via-vpn passthrough=no connection-mark=conn-barcelona
 
 9   ;;; MSS para tunel WireGuard (MTU 1420)
     chain=forward action=change-mss new-mss=1380 passthrough=yes tcp-flags=syn protocol=tcp out-interface=proton-vpn
 
10   ;;; MSS para tunel Marsella (MTU 1380)
     chain=forward action=change-mss new-mss=1340 passthrough=yes tcp-flags=syn protocol=tcp out-interface=proton-vpn-marsella
Consejo de administración: A partir de ahora, añadir un dispositivo nuevo es tan simple como añadirlo a la lista correspondiente. Las reglas de Mangle ya no se tocan nunca. Esto reduce el consumo de CPU del router al evaluar una sola regla por lista.
Conclusión de la serie: Con esta cuarta parte, el hAP ax³ deja de ser un simple router doméstico y se convierte en un verdadero concentrador de enrutamiento avanzado. Hemos eliminado el doble NAT, montado un sistema de VPN multi-región por dispositivo con Address Lists, asegurado el DNS con Pi-Hole y Unbound, y añadido failover (Kill Switch) a cada túnel. Una infraestructura de red de nivel profesional, documentada paso a paso y con un plan de reversión en cada fase.
Serie: este artículo es la Parte 4 de Proyecto ax³. Viene de la Parte 3 — Monopuesto, VPN y corte final.

Volver al índice de la serie · Cheatsheet RouterOS
FreeBSD es genial!.

viernes, 16 de octubre de 2026

Restaurar red tras resume ACPI en FreeBSD

Objetivo

Ejecutar automáticamente un script al despertar el equipo de suspensión (S3) para restaurar:

  • Ethernet con IP fija
  • Reglas de pf
  • Ratón USB
  • Cliente NFS

Piezas necesarias

Pieza Ruta
Script de restauración /usr/local/sbin/resume-network.sh
Regla de devd /etc/devd/resume-network.conf
Log del script /var/log/resume-network.log
Syslog (logger) /var/log/messages

1️⃣ Crear el script

doas vim /usr/local/sbin/resume-network.sh

Puntos clave:

  • Shebang: #!/bin/sh
  • PATH completo al inicio (devd lo ejecuta con PATH mínimo):
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
export PATH

Redirigir toda la salida a un log para depurar:

exec >> /var/log/resume-network.log 2>&1
  • Función log() que escribe a archivo y a syslog
log() {
    echo "[$(date '+%F %T')] $*"
    logger -t resume-network "$*"
}
  • Usar rutas absolutas en comandos críticos (/sbin/pfctl, /usr/local/bin/wg-quick, etc.).
  • Esperar a que el enlace esté active antes de reasignar IP.
  • Al reasignar IP fija: borrar primero la IP previa y borrar la ruta por defecto antes de volver a añadirla.

Dar permisos:

doas chmod +x /usr/local/sbin/resume-network.sh

2️⃣ Script completo

#!/bin/sh
# =========================================================
# /usr/local/sbin/resume-network.sh
# Restaura Ethernet (em0, IP fija), ratón USB y NFS
# tras un resume ACPI.
# (WireGuard y qBittorrent excluidos)
# =========================================================

# PATH completo: devd ejecuta los scripts con un PATH mínimo
PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin
export PATH

LOG="/var/log/resume-network.log"
exec >> "$LOG" 2>&1

# Función para loguear en archivo y en syslog
log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*"
    logger -t resume-network "$*"
}

log "=== $(date) - Resume detectado ==="

# ---------------------------------------------------------
# 1. Ethernet: reactivar em0 y aplicar IP fija
# ---------------------------------------------------------
sleep 3

ifconfig em0 down
sleep 1
ifconfig em0 up

# Esperar a que el enlace esté activo (hasta 15s)
i=0
status=""
while [ $i -lt 15 ]; do
    status=$(ifconfig em0 | awk '/status:/ {print $2}')
    [ "$status" = "active" ] && break
    sleep 1
    i=$((i + 1))
done

log "em0 status=$status tras ${i}s"

if [ "$status" != "active" ]; then
    log "ERROR - em0 sin enlace tras ${i}s"
    exit 1
fi

# Eliminar IP previa (si existe) y reaplicar IP fija y ruta
ifconfig em0 inet 192.168.88.50 delete 2>/dev/null
ifconfig em0 inet 192.168.88.50 netmask 255.255.255.0
route delete default 2>/dev/null
route add default 192.168.88.1

log "Ethernet OK (IP fija y ruta activas)"

# ---------------------------------------------------------
# 2. Recargar pf para limpiar estados obsoletos
# ---------------------------------------------------------
/sbin/pfctl -f /etc/pf.conf 2>/dev/null
log "pf recargado"

# ---------------------------------------------------------
# 3. Verificar conectividad con reintentos
# ---------------------------------------------------------
connected=0
for attempt in 1 2 3; do
    if ping -c 1 -t 3 192.168.88.1 >/dev/null 2>&1; then
        connected=1
        break
    fi
    sleep 2
done

if [ "$connected" != "1" ]; then
    log "ERROR - sin conectividad a la puerta de enlace"
    exit 1
fi
log "Conectividad verificada tras ${attempt} intento(s)"

# ---------------------------------------------------------
# 4. Reactivar ratón USB
# ---------------------------------------------------------
if kldstat -q -m ums 2>/dev/null; then
    kldunload ums 2>/dev/null
    sleep 1
    kldload ums
    log "módulo ums recargado"
elif kldstat -q -m uhid 2>/dev/null; then
    kldunload uhid 2>/dev/null
    sleep 1
    kldload uhid
    log "módulo uhid recargado"
else
    log "ni ums ni uhid cargados, ratón sin cambios"
fi

# Reiniciar moused si está corriendo
if pgrep -q moused; then
    service moused restart 2>/dev/null || {
        pkill -f moused 2>/dev/null
        sleep 1
        service moused start 2>/dev/null
    }
    log "moused reiniciado"
fi

# ---------------------------------------------------------
# 5. Reiniciar el cliente NFS
# ---------------------------------------------------------
service nfsclient restart
log "nfsclient reiniciado"

# Opcional: remontar sistemas NFS si se quedan colgados
# mount -a -t nfs
# log "sistemas NFS remontados"

log "=== $(date) - Resume completado ==="
exit 0

3️⃣ Crear la regla de devd

# cat /etc/devd/resume-network.conf 
notify 100 {
    match "system"      "ACPI";
    match "subsystem"   "Resume";
    action "/usr/local/sbin/resume-network.sh";
};

Aplicar cambios

doas service devd restart

Comprobar que devd ve el evento

Verifica que el subsystem sea exactamente el correcto. Algunos equipos emiten Resume y otros resume. Para ver qué llega:

doas devd -d

Suspende y despierta el equipo. Si no aparece el evento ACPI/Resume, ajusta la regla con el subsystem que realmente emita tu hardware (puedes verlo también en /var/log/messages).

4️⃣ Probar sin suspender

Ejecuta el script manualmente como root:

doas sh -x /usr/local/sbin/resume-network.sh

Y revisa el log:

tail -f /var/log/resume-network.log

5️⃣ Depurar tras un resume real

Log propio del script:

tail -n 50 /var/log/resume-network.log
add net default: gateway 192.168.88.1
[2026-10-16 15:02:49] Ethernet OK (IP fija y ruta activas)
[2026-10-16 15:02:49] pf recargado
[2026-10-16 15:02:51] Conectividad verificada tras 1 intento(s)
[2026-10-16 15:02:51] ni ums ni uhid cargados, ratón sin cambios
Starting default moused.
[2026-10-16 15:02:51] moused reiniciado
NFS access cache time=60
[2026-10-16 15:02:51] nfsclient reiniciado
[2026-10-16 15:02:51] === Fri Oct 16 15:02:51 CEST 2026 - Resume completado ===
[2026-10-16 15:03:28] === Fri Oct 16 15:03:28 CEST 2026 - Resume detectado ===
[2026-10-16 15:03:36] em0 status=active tras 2s

add net default: gateway 192.168.88.1
[2026-10-16 15:03:37] Ethernet OK (IP fija y ruta activas)
[2026-10-16 15:03:37] pf recargado
[2026-10-16 15:03:42] Conectividad verificada tras 2 intento(s)
[2026-10-16 15:03:42] ni ums ni uhid cargados, ratón sin cambios
Starting default moused.
[2026-10-16 15:03:42] moused reiniciado
NFS access cache time=60
[2026-10-16 15:03:42] nfsclient reiniciado
[2026-10-16 15:03:42] === Fri Oct 16 15:03:42 CEST 2026 - Resume completado ===
[2026-10-16 18:34:14] === Fri Oct 16 18:34:14 CEST 2026 - Resume detectado ===
[2026-10-16 18:34:23] em0 status=active tras 2s

add net default: gateway 192.168.88.1
[2026-10-16 18:34:23] Ethernet OK (IP fija y ruta activas)
[2026-10-16 18:34:23] pf recargado
[2026-10-16 18:34:26] Conectividad verificada tras 1 intento(s)
[2026-10-16 18:34:26] ni ums ni uhid cargados, ratón sin cambios
Starting default moused.
[2026-10-16 18:34:26] moused reiniciado
NFS access cache time=60
[2026-10-16 18:34:26] nfsclient reiniciado
[2026-10-16 18:34:26] === Fri Oct 16 18:34:26 CEST 2026 - Resume completado ===
[2026-10-16 21:58:08] === Fri Oct 16 21:58:08 CEST 2026 - Resume detectado ===
[2026-10-16 21:58:16] em0 status=active tras 2s

add net default: gateway 192.168.88.1
[2026-10-16 21:58:17] Ethernet OK (IP fija y ruta activas)
[2026-10-16 21:58:17] pf recargado
[2026-10-16 21:58:22] Conectividad verificada tras 2 intento(s)
[2026-10-16 21:58:22] ni ums ni uhid cargados, ratón sin cambios
Starting default moused.
[2026-10-16 21:58:22] moused reiniciado
NFS access cache time=60
[2026-10-16 21:58:22] nfsclient reiniciado
[2026-10-16 21:58:22] === Fri Oct 16 21:58:22 CEST 2026 - Resume completado ===

Mensajes que ha escrito devd y el script vía logger:

grep resume /var/log/messages
Oct 16 21:58:08 solaris resume-network[18841]: === Fri Oct 16 21:58:08 CEST 2026 - Resume detectado ===
Oct 16 21:58:16 solaris resume-network[18862]: em0 status=active tras 2s
Oct 16 21:58:17 solaris resume-network[18871]: Ethernet OK (IP fija y ruta activas)
Oct 16 21:58:17 solaris resume-network[18877]: pf recargado
Oct 16 21:58:22 solaris resume-network[18891]: Conectividad verificada tras 2 intento(s)
Oct 16 21:58:22 solaris resume-network[18898]: ni ums ni uhid cargados, ratón sin cambios
Oct 16 21:58:22 solaris resume-network[18929]: moused reiniciado
Oct 16 21:58:22 solaris resume-network[18945]: nfsclient reiniciado
Oct 16 21:58:22 solaris resume-network[18951]: === Fri Oct 16 21:58:22 CEST 2026 - Resume completado ===

Errores frecuentes

Síntoma Causa Solución
Nada ocurre al despertar & al final del action Quitarlo
Nada ocurre al despertar subsystem distinto (resume vs Resume) Ajustar en el .conf
Script falla silenciosamente Comando no encontrado (logger, route, …) Añadir PATH completo
IP fija no se aplica La IP ya estaba asignada ifconfig em0 inet X delete antes
Ratón no vuelve Módulo incorrecto cargado Probar ums, uhid, usbhid
NFS colgado service nfsclient restart no remonta Añadir umount -f + mount -a

Comandos útiles de referencia

service devd restart            # recargar reglas
devd -d                         # ver eventos en directo
ifconfig em0                    # ver estado del enlace
netstat -rn                     # ver rutas
pfctl -s info                   # estado de pf
kldstat                         # módulos cargados
mount | grep nfs                # montajes NFS activos

Todo el flujo en un solo vistazo: script → regla devd → restart → log → depuración.

FreeBSD es genial!.

jueves, 15 de octubre de 2026

Cheatsheet RouterOS — Proyecto ax³

Qué es esta entrada

Resumen de comandos útiles de RouterOS y del cliente SSH, agrupados por tema y con comentarios. Todo lo que aparece aquí es lo que se usó realmente durante el Proyecto ax³: la migración del hAP ac² al hAP ax³ con monopuesto de O2, policy routing multi-región con ProtonVPN y Address Lists, DNS con Pi-Hole y Unbound, y backups.

Cómo usar esta entrada: usa el índice para saltar al bloque que necesites. Cada bloque de código tiene un botón Copiar en la esquina superior derecha. Los comandos están pensados para pegarse en la terminal de RouterOS (New Terminal en WinBox o SSH) o en el cliente (FreeBSD/Linux/Windows).

Índice

SSH y acceso remoto

# Ver la configuración SSH actual
/ip ssh print

# Permitir autenticación por contraseña
/ip ssh set password-authentication=yes

# Solo permitir contraseña a usuarios SIN clave (recomendado tras importar claves)
/ip ssh set password-authentication=yes-if-no-key

# Forzar algoritmos criptográficos modernos (AES-GCM, ChaCha20, Ed25519)
/ip ssh set strong-crypto=yes

# Ver las claves SSH importadas de los usuarios
/user ssh-keys print

# Ver detalle (incluye fingerprint)
/user ssh-keys print detail

# Importar una clave pública a un usuario
/user ssh-keys import public-key-file=mikrotik_axe.pub user=carlos

# Eliminar una clave por índice
/user ssh-keys remove 1

# Eliminar una clave por fingerprint (más seguro)
/user ssh-keys remove [find fingerprint="SHA256:..."]
Valores de password-authentication:
  • yes — Login por contraseña siempre permitido.
  • no — Nunca permitido, solo clave SSH.
  • yes-if-no-key — Solo si el usuario no tiene clave asociada. Recomendado tras importar las claves.

Usuarios

# Listar todos los usuarios
/user print

# Habilitar un usuario y asignarle contraseña
/user set admin disabled=no password="TuContraseñaSegura"

# Asignar grupo (full = control total)
/user set admin disabled=no group=full password="TuContraseñaSegura"

# Dejar un usuario sin contraseña (solo entrará con clave SSH)
/user set carlos password=""

# Deshabilitar un usuario temporalmente
/user set carlos disabled=yes

Backups

# Backup binario (restaurable, incluye todo)
/system backup save name=ax3-2026-10-25-dual-vpn-OK

# Backup con contraseña (recomendado si sale del router)
/system backup save name=ax3-2026-10-25-dual-vpn-OK password="clave"

# Export legible (.rsc, sin contraseñas)
/export compact file=ax3-2026-10-25-dual-vpn-OK

# Export con datos sensibles (¡cuidado con dónde se guarda!)
/export file=ax3-2026-10-25-dual-vpn-OK show-sensitive

# Listar archivos existentes
/file print

# Restaurar un backup binario
/system backup load name=ax3-2026-10-25-dual-vpn-OK.backup

# Reiniciar el router
/system reboot
Nomenclatura recomendada: ax3-AAAA-MM-DD-HHMM-<estado>.ext. Guardar siempre una copia fuera del router (en tormenta, por ejemplo, con ZFS y snapshots).

Firewall — Filter

# Ver reglas
/ip firewall filter print
/ip firewall filter print stats

# Permitir LAN → WAN (con prioridad antes del drop final)
/ip firewall filter add chain=forward in-interface-list=LAN out-interface-list=WAN \
    action=accept comment="Permitir LAN a WAN"

# Permitir LAN → VPN España
/ip firewall filter add chain=forward in-interface-list=LAN out-interface=proton-vpn \
    action=accept comment="Permitir LAN a VPN España"

# Permitir LAN → VPN Marsella
/ip firewall filter add chain=forward in-interface-list=LAN out-interface=proton-vpn-marsella \
    action=accept comment="Permitir LAN a VPN Marsella"

# Colocar una regla antes de otra (ej. antes del Drop final)
/ip firewall filter add ... place-before=[find comment="Drop todo lo dems"]

# Mover una regla después de crearla
/ip firewall filter move [find comment~"Permitir LAN a VPN"] \
    destination=[find comment~"Drop todo lo dems"]

# Resetear contadores
/ip firewall filter reset-counters [find]

Firewall — Mangle (Policy Routing)

# Ver reglas y contadores
/ip firewall mangle print
/ip firewall mangle print stats

# 1. Excluir tráfico LAN del marcado (DEBE IR PRIMERO)
/ip firewall mangle add chain=prerouting dst-address-list=lan-directa \
    action=return comment="No marcar tráfico LAN"

# 2. Marcar la conexión (usando Address Lists en lugar de IPs sueltas)
/ip firewall mangle add chain=prerouting src-address-list=vpn-marsella in-interface=bridge \
    action=mark-connection new-connection-mark=conn-marsella passthrough=yes \
    comment="Mangle: Marcar lista Marsella"

# 3. Enrutar por la tabla correspondiente
/ip firewall mangle add chain=prerouting connection-mark=conn-marsella \
    action=mark-routing new-routing-mark=via-vpn-marsella passthrough=no \
    comment="Mangle: Enrutar lista Marsella"

# --- MSS (Cálculo correcto = MTU - 40) ---
# PPPoE: MTU 1492 -> MSS 1452
/ip firewall mangle add chain=forward protocol=tcp tcp-flags=syn \
    out-interface=pppoe-o2 action=change-mss new-mss=1452 passthrough=yes \
    comment="MSS para PPPoE"

# WireGuard España: MTU 1420 -> MSS 1380
/ip firewall mangle add chain=forward protocol=tcp tcp-flags=syn \
    out-interface=proton-vpn action=change-mss new-mss=1380 passthrough=yes \
    comment="MSS para túnel España"

# WireGuard Marsella: MTU 1380 -> MSS 1340
/ip firewall mangle add chain=forward protocol=tcp tcp-flags=syn \
    out-interface=proton-vpn-marsella action=change-mss new-mss=1340 passthrough=yes \
    comment="MSS para túnel Marsella"
Orden crítico: la regla "No marcar tráfico LAN" debe ir antes de cualquier mark-connection o mark-routing. Además, es vital excluir las redes internas de los túneles (ej. 10.3.0.0/24) en la lista lan-directa para evitar bucles.

Firewall — NAT

# Ver reglas
/ip firewall nat print
/ip firewall nat print stats

# Masquerade general (salida por PPPoE)
/ip firewall nat add chain=srcnat action=masquerade src-address=192.168.88.0/24 \
    out-interface=pppoe-o2 comment="NAT general por PPPoE"

# Masquerade para el túnel España (debe ir ANTES que la general)
/ip firewall nat add chain=srcnat action=masquerade src-address=192.168.88.0/24 \
    out-interface=proton-vpn comment="NAT para ProtonVPN España"

# Masquerade para el túnel Marsella
/ip firewall nat add chain=srcnat action=masquerade src-address=192.168.88.0/24 \
    out-interface=proton-vpn-marsella comment="NAT para ProtonVPN Marsella"

# Masquerade para acceder al HGU (activar solo cuando se necesite)
/ip firewall nat add chain=srcnat action=masquerade src-address=192.168.88.0/24 \
    out-interface=ether1 disabled=yes comment="NAT para entrar al HGU O2"

Listas de direcciones (Address Lists)

# Ver todas las listas
/ip firewall address-list print

# Añadir red a la lista "lan-directa" (Para evitar que vaya por la VPN)
/ip firewall address-list add list=lan-directa address=192.168.88.0/24 \
    comment="LAN principal"
/ip firewall address-list add list=lan-directa address=10.2.0.0/24 \
    comment="Red interna VPN España"
/ip firewall address-list add list=lan-directa address=10.3.0.0/24 \
    comment="Red interna VPN Marsella"

# Añadir dispositivos a las listas de VPN
/ip firewall address-list add list=vpn-marsella address=192.168.88.100 comment="Dispositivo 1"
/ip firewall address-list add list=vpn-barcelona address=192.168.88.201 comment="Dispositivo 2"

Rutas y Tablas de Enrutamiento

# Ver todas las rutas
/ip route print

# Crear una tabla de enrutamiento personalizada (RouterOS v7 requiere FIB)
/routing table add name=via-vpn-marsella fib

# Salida por ProtonVPN Marsella
/ip route add dst-address=0.0.0.0/0 gateway=proton-vpn-marsella routing-table=via-vpn-marsella \
    distance=1 comment="Salida por Marsella"

# Kill switch: blackhole si el túnel cae (Sintaxis correcta en v7)
/ip route add dst-address=0.0.0.0/0 blackhole=yes routing-table=via-vpn-marsella \
    distance=2 comment="Kill switch Marsella"
Kill switch por blackhole: si el túnel está arriba, la ruta 1 (distance=1) está activa y la 2 nunca se usa. Si el túnel cae, la ruta 1 se vuelve inactiva y entra la 2 (blackhole), descartando el tráfico marcado. No hay fuga posible hacia la WAN normal. (Nota: en RouterOS v6 se usaba type=blackhole, en v7 es blackhole=yes).

DHCP y PPPoE

# Ver red DHCP configurada
/ip dhcp-server network print

# Forzar DNS a Pi-Hole
/ip dhcp-server network set [find] dns-server=192.168.88.244

# Fijar las IPs de los dispositivos (CRUCIAL para que las Address Lists no fallen)
/ip dhcp-server lease make-static [find]

# Ver cliente PPPoE
/interface pppoe-client print detail

# Asegurar que PPPoE añade ruta por defecto
/interface pppoe-client set [find name=pppoe-o2] add-default-route=yes

# DHCP client de ether1 sin añadir ruta (evita doble NAT)
/ip dhcp-client set [find interface=ether1] add-default-route=no
Doble NAT y VPNs: el DHCP client de ether1 debe tener siempre add-default-route=no. Además, si usas Address Lists para enrutar por VPN, las IPs deben ser estáticas (reservas DHCP) para que el router siempre reconozca al dispositivo.

DNS

# Ver configuración DNS del router
/ip dns print

# Desactivar el resolver del router (los clientes usan Pi-Hole)
/ip dns set allow-remote-requests=no
Cadena DNS: clientes → Pi-Hole (192.168.88.244) → Unbound (192.168.88.160) → resolución recursiva. El router no participa. Por eso allow-remote-requests debe estar en no.

WireGuard

# Ver interfaces WireGuard
/interface wireguard print

# Ver peers (comprobar que el Last-Handshake es reciente)
/interface wireguard peers print detail

# Ping por el túnel (desde el propio router)
/ping 10.2.0.1 count=3 interface=proton-vpn

# Ping a Internet usando la interfaz del túnel
/ping 1.1.1.1 interface=proton-vpn-marsella count=3

Diagnóstico, Monitorización y Rescate

# Ver interfaces activas y sus MTU
/interface print

# Ver direcciones IP asignadas (¡comprueba que no haya ninguna 'unknown'!)
/ip address print

# Ver conexiones activas con marca VPN
/ip firewall connection print where connection-mark~"vpn"

# Ver conexiones de un dispositivo concreto
/ip firewall connection print where src-address~"192.168.88.100"

# Ver logs de PPPoE o Firewall
/log print where topics~"pppoe"
/log print where message~"DROP"

# Ver contadores de mangle (las reglas de Arriba deben sumar paquetes)
/ip firewall mangle print stats

# --- RESOLUCIÓN DE PROBLEMAS ---
# Eliminar un peer WireGuard fantasma que rompe el túnel
/interface wireguard peers remove [find name="peerX"]

# Limpiar la interfaz 'unknown' si falla una importación de WireGuard
/ip address remove [find interface=unknown]

# Resetear las conexiones de una IP tras cambiar de VPN
/ip firewall connection remove [find src-address~"192.168.88.100"]

# Activar Safe Mode (revierte cambios si se pierde la sesión)
/system safe-mode

Cliente — comandos útiles

# Generar par de claves ed25519
ssh-keygen -t ed25519 -f ~/.ssh/mikrotik_axe -C "carlos@mikrotik-ax3"

# Ver fingerprint de una clave pública
ssh-keygen -lf ~/.ssh/mikrotik_axe.pub

# Limpiar entrada antigua de known_hosts
ssh-keygen -R 192.168.88.1

# Subir clave pública al router
scp ~/.ssh/mikrotik_axe.pub carlos@192.168.88.1:/mikrotik_axe.pub

# Conectar con clave específica
ssh -i ~/.ssh/mikrotik_axe carlos@192.168.88.1

# Descargar backups
scp carlos@192.168.88.1:/ax3-2026-10-25-dual-vpn-OK.backup .
scp carlos@192.168.88.1:/ax3-2026-10-25-dual-vpn-OK.rsc .

# Ver IP pública actual y ubicación geográfica
curl -s ifconfig.me
curl -s ipinfo.io/city

# Probar fugas DNS
nslookup whoami.akamai.net
nslookup dnsleaktest.com

~/.ssh/config (cliente)

Host mikrotik-ax3
    HostName 192.168.88.1
    User carlos
    IdentityFile ~/.ssh/mikrotik_axe
    IdentitiesOnly yes

Host mikrotik-admin
    HostName 192.168.88.1
    User admin

Con eso:

ssh mikrotik-ax3
scp archivo.bin mikrotik-ax3:/

Buenas prácticas aplicadas

Elemento Valor correcto
strong-cryptoyes
password-authenticationyes-if-no-key (tras importar claves)
FasttrackDeshabilitado (rompe policy routing)
allow-remote-requests (DNS)no
DHCP client de ether1add-default-route=no
PPPoE clientadd-default-route=yes
Kill switch VPNRuta blackhole en tabla via-vpn
Regla de exclusión LANPrimera en prerouting
MSSMTU - 40 (Ej: 1452 PPPoE, 1380 España, 1340 Marsella)
Backups.backup + .rsc, copia externa en tormenta
DHCP LeasesHacer estáticas (make-static) para que no cambien de IP

Arquitectura de referencia

O2 / Internet
   │
Fibra óptica
   │
┌──────────────────────────┐
│ MitraStar GPT-2541GNAC   │
│ MONOPUESTO               │
│ VoIP: teléfono fijo      │
└────────────┬─────────────┘
             │ Ethernet / PPPoE
             ▼
┌──────────────────────────┐
│ hAP ax³                  │
│ PPPoE + NAT + Firewall   │
│ WireGuard + ProtonVPN    │
│ Policy routing           │
└────────────┬─────────────┘
             │
       192.168.88.0/24
             │
   ├── tormenta   .160  FreeBSD 14.5 (Unbound, NFSv4, Kerberos, ZFS, Samba)
   ├── solaris    .50   FreeBSD 14.5
   ├── raspberry  .244  Raspberry Pi 3B + Pi-Hole
   └── demás dispositivos

Cadena DNS: clientes → Pi-Hole (.244) → Unbound (.160) → recursivo


Cheatsheet de Proyecto ax³. Última actualización: 2026-10-25.

FreeBSD es genial!.