El escenario
La instancia EC2 en AWS tiene IP pública y hace de servidor WireGuard. Mi equipo en casa está detrás de CGNAT, así que no puede recibir conexiones: es siempre el cliente y marca hacia afuera por UDP 51820. Al otro lado del túnel, las máquinas vulnerables corren en libvirt, cada proyecto en su propia red NAT aislada.
El síntoma
El túnel establecía el handshake sin problemas, pero las conexiones nuevas desde AWS hacia la VM nunca llegaban. No había errores visibles, solo silencio.
Las pistas falsas
Investigué primero UFW y Docker, que eran los sospechosos naturales. Ninguno tenía relación con el problema.
La causa
libvirt aplica su propio filtrado con nftables en las redes de tipo NAT (tabla libvirt_network, cadena guest_input). Por defecto rechaza cualquier conexión nueva entrante y solo deja pasar el tráfico de retorno de conexiones ya establecidas. Eso descartaba en silencio todo lo que llegaba por el túnel.
La solución
Un hook de red de libvirt (/etc/libvirt/hooks/network) que inserta una regla de excepción en nftables cada vez que arranca la red de destino. La regla usa oifname, que identifica la interfaz por nombre y se mantiene entre reinicios, y no oif, que usa el índice numérico y se rompe en el siguiente reinicio.
Lo que me llevo
- Diagnosticar con evidencia, con
tcpdumpy los contadores deiptablesynft, y no por ensayo y error. - Todo lo que no está en el código de infraestructura se pierde cuando se recrea el entorno.
- La causa real puede estar varias capas más abajo de donde aparece el síntoma.
El detalle completo está en elrepositorio de CloudLab.