Vous montez le tunnel, faites un ping sur fe80::1 avec le tunnel comme interface source, et rien ne revient. Ce n'est pas une règle de pare-feu que vous avez oubliée. Une adresse lien-local ne signifie quelque chose que sur le seul lien où elle a été formée, et un VPN routé n'est pas ce lien. Le fe80::1 du routeur distant vit sur le segment distant du LAN ; vous êtes à un saut de distance sur un autre segment, et IPv6 n'a aucun mécanisme permettant à un routeur de transmettre des paquets lien-local.

Le préfixe fe80 décrit une portée, pas une plage

L'unicast lien-local est fe80::/10, et la propriété déterminante n'est pas le nombre mais la portée. L'adresse n'est valable que sur un seul lien, et chaque interface en forme une à partir de son propre identifiant ; c'est pourquoi deux machines sans rapport sur deux réseaux sans rapport peuvent toutes deux répondre à fe80::1 sans le moindre conflit. Le préfixe dit en substance « sur un certain lien » ; le lien lui-même vient du contexte.

Sur un hôte, ce contexte est la zone, ou l'ID de portée, que vous ajoutez après un signe pour cent : fe80::1%eth0 sous Linux, fe80::1%3 ou fe80::1%12 sous Windows et dans les outils qui exposent les index d'interface. Le noyau résout l'adresse avec l'index d'interface puis envoie. Supprimez la zone et la destination devient ambiguë, donc la pile n'a aucun moyen de choisir un segment.

Pourquoi un tunnel routé ne peut pas la livrer

Un VPN routé est une interface point à point portant ses propres adresses, généralement un /64 d'espace IPv6 unique-local ou privé à l'intérieur du tunnel. Le LAN distant est un lien séparé, atteint par le point de terminaison du tunnel qui route et transmet en votre nom. Ce sont deux segments distincts, donc une adresse de l'un n'est pas une destination valide sur l'autre.

La règle de transmission est explicite dans la norme et non une bizarrerie de votre client : les routeurs ne transmettent pas les paquets dont la source ou la destination est lien-local. C'est pourquoi le paquet meurt même lorsque la table de routage semble correcte. Ajoutez une route pour fe80::/64 vers le tunnel et une pile conforme à la norme soit la rejette, soit l'accepte et abandonne chaque paquet correspondant : la portée de destination dit « ce lien seulement », et l'interface de sortie n'est pas ce lien.

La découverte de voisins renforce la même frontière. Les hôtes résolvent les sauts suivants lien-local avec une sollicitation de voisin envoyée en multicast de portée lien avec une limite de sauts de 255, afin que les routeurs puissent rejeter tout ce qui est transmis. Faire fonctionner cela à travers un tunnel impliquerait de mandater la découverte pour un segment distant, ce qui est du pontage de couche 2 sous un autre chapeau.

Il existe une seconde panne plus discrète, et elle fait trébucher ceux qui tentent de forcer la route malgré tout : la zone. Quelle que soit la zone que vous tapez localement, elle nomme l'interface du tunnel, alors que l'adresse voulue est liée à l'interface du LAN distant. Les deux ne correspondent jamais, donc le paquet ne peut pas être dirigé vers la bonne interface à l'extrémité distante.

À quoi ressemble la panne en pratique

La sortie des outils pour une erreur de portée se lit comme une erreur de routage ou de pare-feu, et c'est précisément pourquoi les gens passent un après-midi dans la mauvaise couche.

What you runWhat you seeWhat it means
ping fe80::1 with no zoneInvalid argument on Linux, or a transmit failure on WindowsThe stack cannot pick an interface for an ambiguous destination
ping -6 -I tun0 fe80::1Destination unreachable, or a silent timeoutThe address is not on the tunnel link, so there is nothing on-link to answer
ssh user@fe80::1 after the tunnel is upHangs, then no route to hostThe SYN never left the machine in a deliverable form; the server logs nothing
ip -6 neigh show dev tun0Empty tableNo neighbor entry can exist for a link-local host that is not on this link
fe80::/64 inside AllowedIPs or route-ipv6Config accepted, traffic still droppedThe tunnel carried the packet; the receiving stack refused to forward it

La troisième ligne fait perdre le plus de temps, car un client ssh sans sortie ressemble à un problème de service à l'écoute. Si vous avez un accès quelconque, regardez le côté distant et vérifiez si sshd est lié à toutes les adresses ou à une seule.

Utilisez une adresse prévue pour être routée

Pour tout ce que vous devez atteindre par le tunnel, utilisez l'adresse donnée au service à cette fin : une adresse unicast globale, ou une adresse unique-local tirée de fc00::/7, la plage réservée exactement à ce cas interne. Vérifiez que l'écouteur la lie réellement, et vérifiez le chemin de retour et toute règle de pare-feu de l'hôte.

Regardez l'hôte distant au lieu de deviner. ip -6 addr show liste les adresses existantes, et ss -6 -ltn liste ce sur quoi le démon écoute. Un service lié uniquement à fe80:: n'est joignable que depuis son propre segment, ce qui est généralement un réglage par défaut que personne n'a choisi exprès et qui peut être modifié avec l'accord de l'administrateur.

Lorsque le service ne peut vraiment pas être relié autrement, déplacez le pont vers la couche applicative plutôt que vers la couche réseau. Un relais sur l'hôte distant qui écoute sur une adresse routable et se connecte à celle lien-local résout le problème sans étendre aucun segment :

socat TCP6-LISTEN:8080,bind=[fd00:1:2::10] TCP6:[fe80::1%eth0]:80

Ici la zone se trouve du bon côté, sur l'hôte qui a réellement eth0 sur ce lien. Votre client parle à fd00:1:2::10, qui se route normalement, et le relais rend le saut lien-local local. Le même artifice fonctionne pour l'interface web d'un appareil ou un vieux BMC qui n'annonce qu'une adresse lien-local.

Quand le pontage est vraiment la réponse, et ce qu'il faut vérifier

Certains déploiements ont vraiment besoin d'un segment partagé : un appareil qui ne parle que découverte lien-local, un appareil qui dépend du multicast, un laboratoire qui reproduit un LAN plat. C'est un problème de couche 2 et il faut une réponse de couche 2, comme un périphérique tap ponté vers l'interface distante ou un produit client avec un mode ponté explicite. Cela vous coûte du trafic de diffusion et de multicast traversant le tunnel, plus une découverte de voisins qui doit fonctionner de bout en bout.

Ne l'approximandez pas en ajoutant fe80::/64 à un profil routé. Cela produit le pire état de tous : la configuration semble terminée, la table de routage affiche une entrée, et chaque paquet est encore rejeté quelque part entre deux piles qui se comportent toutes deux correctement.

Vérifiez avec l'interface plutôt qu'avec le ping. ip -6 addr show tun0 vous dit si le lien du tunnel a formé sa propre adresse lien-local, et ip -6 route get fe80::1%tun0 vous dit ce que le noyau ferait réellement d'une destination à portée. Quand le noyau dit que la destination est injoignable sur cette interface, aucun réglage du tunnel n'y changera rien, et il est temps d'arrêter de modifier le profil.

Une courte séquence qui tranche la question :

  • Lisez l'adresse sur l'hôte distant et notez si elle est en fe80:: ou un préfixe routable.
  • Si c'est fe80::, reliez à nouveau le service, relayez sur cet hôte ou pontez le segment ; si c'est routable, corrigez la route, le pare-feu ou l'adresse de liaison.
  • Revérifiez la zone à chaque nouveau test, car une commande copiée garde généralement la mauvaise interface.

Sources : RFC 4291, architecture d'adressage IPv6.

Articles similaires