Je zet de tunnel op, pingt fe80::1 met de tunnel als broninterface, en krijgt niets terug. Het is geen firewallregel die je bent vergeten. Een link-local adres heeft alleen betekenis op de ene link waarop het is gevormd, en een gerouteerde VPN is die link niet. De fe80::1 van de externe router staat op het externe LAN-segment; jij zit één hop verderop op een ander segment, en IPv6 heeft helemaal geen mechanisme waarmee een router link-local pakketten doorstuurt.

Het fe80-prefix beschrijft een bereik, geen range

Link-local unicast is fe80::/10, en de bepalende eigenschap is niet het nummer maar het bereik. Het adres is alleen geldig op één link, en elke interface vormt er een uit zijn eigen identificatie, daarom kunnen twee ongerelateerde machines op twee ongerelateerde netwerken allebei op fe80::1 antwoorden zonder de minste conflicten. Het prefix zegt in feite “op een of andere link”; de link zelf komt uit de context.

Op een host is die context de zone, of scope ID, die je achter een procentteken zet: fe80::1%eth0 op Linux, fe80::1%3 of fe80::1%12 op Windows en in tools die interface-indexen tonen. De kernel lost het adres samen met de interface-index op en verstuurt dan. Laat je de zone weg, dan is de bestemming dubbelzinnig, dus heeft de stack geen manier om een segment te kiezen.

Waarom een gerouteerde tunnel het niet kan afleveren

Een gerouteerde VPN is een punt-tot-punt-interface met eigen adressen, meestal een /64 van unique-local of private IPv6-ruimte binnen de tunnel. Het externe LAN is een aparte link, bereikt doordat het tunneleindpunt namens jou routeert en doorstuurt. Dat zijn twee verschillende segmenten, dus een adres van het ene is geen geldige bestemming op het andere.

De doorstuurregel staat expliciet in de standaard en is geen eigenaardigheid van jouw client: routers sturen geen pakketten door met een link-local bron of bestemming. Daarom sterft het pakket ook als de routetabel er correct uitziet. Voeg een route voor fe80::/64 naar de tunnel toe en een conforme stack verwerpt hem of accepteert hem en laat elk passend pakket vallen: het bereik van de bestemming zegt “alleen deze link”, en de uitgaande interface is die link niet.

Buuropsporing versterkt dezelfde grens. Hosts lossen link-local volgende hops op met een buurverzoek dat naar multicast met linkbereik wordt gestuurd met een hoplimiet van 255, zodat routers alles wat doorgestuurd wordt kunnen weigeren. Dat over een tunnel laten werken zou betekenen dat je opsporing voor een extern segment proxyt, wat Layer 2-bridging met een andere hoed is.

Er is een stillere tweede fout, en die vangt mensen die de route toch proberen te forceren: de zone. Welke zone je lokaal ook typt, hij noemt de tunnelinterface, terwijl het adres dat je wilt aan de externe LAN-interface is gebonden. De twee komen nooit overeen, dus het pakket kan aan de andere kant niet naar de juiste interface worden gestuurd.

Hoe de fout er in de praktijk uitziet

Tooluitvoer voor een bereikfout leest als een routerings- of firewallfout, en dat is precies waarom mensen een middag in de verkeerde laag doorbrengen.

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

De derde rij kost de meeste tijd, omdat een ssh-client zonder uitvoer op een probleem met een luisterende dienst lijkt. Als je er op wat voor manier dan ook in kunt, controleer de externe kant en bevestig of sshd aan alle adressen of slechts aan één is gebonden.

Gebruik een adres dat bedoeld was om te routeren

Voor alles wat je via de tunnel moet bereiken, gebruik je het adres dat de dienst juist daarvoor heeft gekregen: een wereldwijd unicastadres, of een unique-local adres uit fc00::/7, het bereik dat precies voor dit interne geval is gereserveerd. Bevestig dat de listener het echt bindt, en controleer het retourpad en elke firewallregel van de host.

Kijk naar de externe host in plaats van te gokken. ip -6 addr show somt de adressen op die bestaan, en ss -6 -ltn somt op waar de daemon naar luistert. Een dienst die alleen aan fe80:: is gebonden, is alleen bereikbaar vanaf zijn eigen segment, wat meestal een standaardwaarde is die niemand bewust heeft gekozen en die met instemming van de beheerder kan worden gewijzigd.

Als de dienst echt niet opnieuw kan worden gebonden, til de brug dan op naar de applicatielaag in plaats van de netwerklaag. Een relay op de externe host die op een routeerbaar adres luistert en met het link-local adres verbindt, lost het probleem op zonder een segment uit te breiden:

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

Hier zit de zone aan de juiste kant, op de host die echt eth0 op die link heeft. Je client praat met fd00:1:2::10, dat normaal wordt gerouteerd, en de relay doet de link-local hop lokaal. Dezelfde truc werkt voor een webinterface van een apparaat of een oude BMC die alleen een link-local adres aankondigt.

Wanneer bridging echt het antwoord is, en wat je moet controleren

Sommige implementaties hebben echt één gedeeld segment nodig: een apparaat dat alleen link-local opsporing spreekt, een apparaat dat van multicast afhankelijk is, een lab dat een plat LAN reproduceert. Dat is een Layer 2-probleem en het vraagt een Layer 2-antwoord, zoals een tap-apparaat dat aan de externe interface is gebrugd of een clientproduct met een expliciete gebrugde modus. Het kost je broadcast- en multicastverkeer dat de tunnel oversteekt plus buuropsporing die van begin tot eind moet werken.

Benader dit niet door fe80::/64 aan een gerouteerd profiel toe te voegen. Dat levert de slechtste toestand op: de configuratie ziet er af uit, de routetabel toont een vermelding, en elk pakket wordt nog steeds ergens tussen twee stacks weggegooid die zich allebei correct gedragen.

Controleer met de interface in plaats van met ping. ip -6 addr show tun0 vertelt of de tunnellink een eigen link-local adres heeft gevormd, en ip -6 route get fe80::1%tun0 vertelt wat de kernel werkelijk met een bestemming met bereik zou doen. Als de kernel zegt dat de bestemming op die interface onbereikbaar is, verandert geen enkele tunnelinstelling dat, en is het tijd om te stoppen met het profiel te bewerken.

Een korte reeks die de vraag beslecht:

  • Lees het adres op de externe host en let op of het fe80:: is of een routeerbaar prefix.
  • Is het fe80::, bind de dienst opnieuw, relay op die host of overbrug het segment; is het routeerbaar, repareer dan de route, firewall of bindadres.
  • Controleer de zone elke keer opnieuw als je opnieuw test, want een gekopieerd commando houdt meestal de verkeerde interface.

Bronnen: RFC 4291, IPv6-adresseringsarchitectuur.

Gerelateerde artikelen