Puse net.ipv6.conf.all.forwarding=1 en una puerta de enlace Debian para que pudiera reenviar el tráfico de los clientes VPN, y unos tres cuartos de hora después la máquina ya no tenía ninguna ruta predeterminada IPv6. El router ascendente funcionaba, el vecino link-local seguía respondiendo y el enlace ascendente conservaba su dirección global. Lo que se había detenido era la disposición del núcleo a seguir aceptando router advertisements en esa interfaz. La ruta no desapareció cuando escribí el sysctl; desapareció cuando caducó la vida de la ruta predeterminada aprendida del RA y nada la renovó.

Nada parecía roto a primera vista. El reenvío funcionaba, los clientes seguían pasando mientras la ruta antigua estaba en la caché, y el fallo llegó más tarde que el cambio que lo provocó. Ese retraso es la razón por la que se culpa al enlace ascendente o a una regla de cortafuegos que nunca estuvo implicada.

Lea la tabla de rutas antes de tocar cualquier sysctl

Empiece con ip -6 route show default y lea los atributos, no solo la puerta de enlace. Una ruta predeterminada aprendida del RA está marcada con proto ra, lleva una preferencia y muestra una cuenta atrás expires. Una ruta añadida a mano no tiene ninguna de las dos, y esa diferencia le dice qué mecanismo posee la ruta.

$ ip -6 route show default
default via fe80::1 dev eth0 proto ra metric 1024 expires 1432sec hoplimit 64 pref medium

Después mire la dirección: ip -6 addr show dev eth0. Una dirección global con vidas preferida y válida medidas en horas sobrevivirá a una ruta predeterminada cuya vida de router se mide en minutos. Dirección presente y ruta predeterminada ausente es la firma de un problema de anuncios. Si también falta la dirección, primero hay que perseguir el enlace, la información de prefijo o la detección de direcciones duplicadas.

Por qué el reenvío desactiva el procesamiento de RA

Un RA es un paquete ICMPv6 de tipo 134, enviado desde un origen link-local con límite de salto 255. Antes de usarlo, el núcleo consulta el accept_ra de la interfaz. El valor predeterminado es 1, y 1 no significa sí. Significa: acepta solo mientras este host no reenvíe. Ponga forwarding=1 y esa condición falla, así que el anuncio se descarta antes de que se considere cualquier prefijo o router predeterminado que contenga.

Existen tres valores, y solo el tercero sobrevive al reenvío:

accept_raforwarding=0forwarding=1
0ignoredignored
1 (default)acceptedignored
2acceptedaccepted

Otras dos marcas deciden qué se instala realmente. accept_ra_defrtr controla si el router predeterminado del anuncio se convierte en ruta, y accept_ra_pinfo controla si la información de prefijo se usa para la configuración de direcciones. Desactivar accept_ra_defrtr es la forma habitual de mantener direcciones SLAAC en un host que reenvía sin aprender una ruta predeterminada. Es una palanca distinta de accept_ra, y es la que se usa cuando se quieren direcciones pero no una ruta. La referencia del núcleo sobre IP sysctl enumera las tres.

Confírmelo con tres comandos

Primero, lea los valores en vivo en lugar del archivo que cree cargado:

sysctl net.ipv6.conf.eth0.forwarding net.ipv6.conf.all.forwarding \
       net.ipv6.conf.eth0.accept_ra net.ipv6.conf.eth0.accept_ra_defrtr

Segundo, demuestre que los anuncios siguen llegando. Filtrar por el byte de tipo ICMPv6 es suficiente y le ahorra leer una pared de tráfico de descubrimiento de vecinos:

tcpdump -ni eth0 'icmp6 and ip6[40] == 134'

Si no aparece nada durante varios minutos, accept_ra no es su problema. El enlace ascendente dejó de anunciar, algo en el camino filtra ICMPv6, o esa interfaz no está realmente en el segmento que cree. Tercero, solicite un anuncio usted mismo y lea sus campos:

rdisc6 eth0

rdisc6 viene en el paquete ndisc6 en Debian y Ubuntu. En la salida, mire la vida del router y la preferencia antes de cambiar nada más. Un anuncio con una vida de router 0 es una orden de eliminar el router predeterminado, y ningún valor de accept_ra lo convierte en una ruta utilizable. También así se detecta un CPE ascendente en modo puente que reparte prefijos pero nunca se ofrece como router.

Haga del enlace ascendente la única interfaz permisiva

Si el enlace ascendente debe ser el router predeterminado, acepte allí anuncios a pesar del reenvío, y en ningún otro sitio:

# /etc/sysctl.d/60-ipv6-router.conf
net.ipv6.conf.all.forwarding = 1
net.ipv6.conf.eth0.accept_ra = 2
net.ipv6.conf.eth0.accept_ra_defrtr = 1

El alcance importa porque el reenvío IPv6 en Linux es un solo conmutador global, no uno por enlace. Escriba 1 en net.ipv6.conf.wg0.forwarding y luego lea net.ipv6.conf.all.forwarding: el valor global se invierte y cada interfaz empieza a reenviar. No puede ser router en el túnel y un host normal en la LAN. Lo que sí puede acotar es la aceptación. Mantenga accept_ra=2 en el enlace ascendente y deje las interfaces del túnel y de la LAN en 1 o 0, para que un anuncio perdido que llegue por el túnel no pueda instalar una ruta predeterminada que apunte hacia él.

Un sysctl -w temporal no sobrevivirá al siguiente arranque, y tanto systemd-networkd como NetworkManager escriben estos valores desde su propia configuración. En networkd, ponga IPv6Forwarding=yes y IPv6AcceptRA=yes en el archivo .network del enlace ascendente; networkd documenta IPv6Forwarding como global por el mismo motivo del núcleo. Con NetworkManager, ipv6.method=auto en el enlace ascendente es lo que gobierna el valor de accept_ra, así que vuelva a leer el sysctl después de nmcli connection up en lugar de confiar en la primera comprobación.

La alternativa estática, ip -6 route add default via fe80::1 dev eth0, sí funciona, y es una respuesta razonable cuando el router ascendente tiene una dirección link-local estable. Tenga claro qué cede. Una ruta predeterminada estática nunca se renueva ni se retira, así que sigue apuntando a un vecino muerto después de cambiar el enlace ascendente. La ruta por RA falla de forma segura; la estática falla en silencio.

Pruebe un paquete reenviado, no el de la propia puerta de enlace

Los ping propios de la puerta de enlace pueden tener éxito en una ruta que ningún cliente puede usar, y también pueden tener éxito porque la puerta de enlace es el origen. Pruebe desde un cliente conectado y luego pregunte a la puerta de enlace qué haría para la dirección de ese cliente:

# on the VPN client
ping -6 -c 3 2001:4860:4860::8888

# on the gateway, using a client address
ip -6 route get 2001:4860:4860::8888 from fd42:20::2

Después espere una vida de router y vuelva a mirar. El estado estable que quiere es una ruta predeterminada marcada con proto ra cuyo valor expires se reinicia constantemente, más all.forwarding=1. Si expires solo cuenta atrás, los anuncios todavía se descartan en algún sitio, y el culpable habitual es un gestor de red que reescribe accept_ra después de que el sysctl de arranque ya se haya ejecutado.

Antes de cerrar esto, confirme cuatro cosas: la ruta predeterminada es proto ra y se renueva, accept_ra=2 solo se aplica al enlace ascendente, el reenvío sigue siendo 1 después de un reinicio y de reiniciar el gestor, y es un cliente, no la puerta de enlace, quien completa un ping IPv6. Si el cliente sigue fallando con una ruta sana, el siguiente sospechoso es el camino de vuelta o un cortafuegos ascendente, no el anuncio.

Artículos relacionados