IPv6 link-local fungerer ikke over VPN: hvorfor fe80 stopper ved lenken
En fe80:: adresse har bare betydning på én lenke. Se hvorfor en rutet VPN ikke kan bære den, hvordan feilen ser ut, og hvilken adresse du bør bruke i stedet.
Du får opp tunnelen, pinger fe80::1 med tunnelen som kildegrensesnitt, og får ingenting tilbake. Det er ikke en brannmurregel du glemte. En link-local-adresse har bare betydning på den ene lenken der den ble dannet, og en rutet VPN er ikke den lenken. fe80::1 til den eksterne ruteren ligger på det eksterne LAN-segmentet; du sitter ett hopp unna på et annet segment, og IPv6 har ingen mekanisme for at en ruter videresender link-local-pakker i det hele tatt.
fe80-prefikset beskriver et omfang, ikke et område
Link-local unicast er fe80::/10, og den definerende egenskapen er ikke tallet, men omfanget. Adressen er gyldig bare på én lenke, og hvert grensesnitt danner én fra sin egen identifikator, og derfor kan to ubeslektede maskiner på to ubeslektede nettverk begge svare på fe80::1 uten den minste konflikt. Prefikset sier i praksis «på en eller annen lenke»; selve lenken kommer fra konteksten.
På en vert er den konteksten sonen, eller scope ID, som du legger til etter et prosenttegn: fe80::1%eth0 på Linux, fe80::1%3 eller fe80::1%12 på Windows og i verktøy som viser grensesnittindekser. Kjernen løser adressen sammen med grensesnittindeksen og sender deretter. Fjerner du sonen, blir målet tvetydig, så stakken har ingen måte å velge et segment på.
Hvorfor en rutet tunnel ikke kan levere den
En rutet VPN er et punkt-til-punkt-grensesnitt som bærer sine egne adresser, vanligvis et /64 av unique-local eller privat IPv6-rom inne i tunnelen. Det eksterne LAN-et er en separat lenke, nådd av tunnelendepunktet som ruter og videresender på dine vegne. Det er to forskjellige segmenter, så en adresse fra det ene er ikke et gyldig mål på det andre.
Videresendingsregelen står eksplisitt i standarden og er ikke en særhet ved klienten din: rutere videresender ikke pakker med link-local kilde eller mål. Derfor dør pakken selv når rutetabellen ser riktig ut. Legger du til en rute for fe80::/64 mot tunnelen, vil en standardkonform stakk enten avvise den eller godta den og droppe hver samsvarende pakke: målets omfang sier «bare denne lenken», og det utgående grensesnittet er ikke den lenken.
Nabooppdagelse forsterker samme grense. Verter løser link-local neste hopp med en nabo-forespørsel sendt til multicast med lenkeomfang og hoppgrense 255, så rutere kan avvise alt som videresendes. Å få det til å virke over en tunnel ville bety å proxy oppdagelsen for et eksternt segment, som er Layer 2-broing i en annen hatt.
Det finnes en stillere andre feil, og den fanger folk som likevel prøver å tvinge ruten: sonen. Uansett hvilken sone du skriver lokalt, navngir den tunnelgrensesnittet, mens adressen du vil ha er bundet til det eksterne LAN-grensesnittet. De to stemmer aldri overens, så pakken kan ikke styres til riktig grensesnitt i den andre enden.
Hvordan feilen ser ut i praksis
Verktøyutdata for en omfangsfeil leses som en ruting- eller brannmurfeil, og det er nettopp derfor folk bruker en ettermiddag i feil lag.
| What you run | What you see | What it means |
|---|---|---|
| ping fe80::1 with no zone | Invalid argument on Linux, or a transmit failure on Windows | The stack cannot pick an interface for an ambiguous destination |
| ping -6 -I tun0 fe80::1 | Destination unreachable, or a silent timeout | The address is not on the tunnel link, so there is nothing on-link to answer |
| ssh user@fe80::1 after the tunnel is up | Hangs, then no route to host | The SYN never left the machine in a deliverable form; the server logs nothing |
| ip -6 neigh show dev tun0 | Empty table | No neighbor entry can exist for a link-local host that is not on this link |
| fe80::/64 inside AllowedIPs or route-ipv6 | Config accepted, traffic still dropped | The tunnel carried the packet; the receiving stack refused to forward it |
Den tredje raden kaster bort mest tid, fordi en ssh-klient uten utdata ser ut som et problem med en lyttende tjeneste. Hvis du har noen måte å komme inn på, sjekk den eksterne siden og bekreft om sshd er bundet til alle adresser eller bare én.
Bruk en adresse som var ment for ruting
For alt du må nå gjennom tunnelen, bruk adressen tjenesten fikk til nettopp dette formålet: en global unicast-adresse, eller en unique-local-adresse fra fc00::/7, området som er reservert nettopp for dette interne tilfellet. Bekreft at lytteren faktisk binder den, og kontroller returveien og enhver brannmurregel på verten.
Se på den eksterne verten i stedet for å gjette. ip -6 addr show lister adressene som finnes, og ss -6 -ltn lister hva daemonen lytter på. En tjeneste som bare er bundet til fe80::, er bare tilgjengelig fra sitt eget segment, noe som vanligvis er en standard ingen valgte med vilje, og som kan endres med administratorens samtykke.
Når tjenesten virkelig ikke kan bindes på nytt, flytt broen opp til applikasjonslaget i stedet for nettverkslaget. En relay på den eksterne verten som lytter på en rutbar adresse og kobler til den link-local adressen, løser problemet uten å utvide noe segment:
socat TCP6-LISTEN:8080,bind=[fd00:1:2::10] TCP6:[fe80::1%eth0]:80Her sitter sonen på riktig side, på verten som faktisk har eth0 på den lenken. Klienten din snakker med fd00:1:2::10, som rutes normalt, og relayen gjør link-local-hoppet lokalt. Samme triks fungerer for et webgrensesnitt på et apparat eller en gammel BMC som bare annonserer en link-local-adresse.
Når broing virkelig er svaret, og hva du bør sjekke
Noen utplasseringer trenger virkelig ett delt segment: en enhet som bare snakker link-local-oppdagelse, et apparat som er avhengig av multicast, et laboratorium som reproduserer et flatt LAN. Det er et Layer 2-problem, og det trenger et Layer 2-svar, som en tap-enhet broet til det eksterne grensesnittet eller et klientprodukt med en eksplisitt bro-modus. Det koster deg broadcast- og multicast-trafikk som krysser tunnelen, pluss nabooppdagelse som må virke ende til ende.
Ikke tilnærm dette ved å legge fe80::/64 til en rutet profil. Det gir den verste tilstanden: konfigurasjonen ser ferdig ut, rutetabellen viser en oppføring, og hver pakke forkastes fortsatt et sted mellom to stakker som begge oppfører seg riktig.
Verifiser med grensesnittet i stedet for med ping. ip -6 addr show tun0 forteller om tunnellenken dannet sin egen link-local-adresse, og ip -6 route get fe80::1%tun0 forteller hva kjernen faktisk ville gjøre med et mål med omfang. Når kjernen sier at målet er uoppnåelig på det grensesnittet, vil ingen tunnelinnstilling endre det, og det er på tide å slutte å redigere profilen.
En kort sekvens som avgjør spørsmålet:
- Les adressen på den eksterne verten og legg merke til om den er fe80:: eller et rutbart prefiks.
- Hvis den er fe80::, bind tjenesten på nytt, relay på den verten, eller bro segmentet; hvis den er rutbar, rett opp ruten, brannmuren eller bind-adressen.
- Sjekk sonen på nytt hver gang du tester på nytt, fordi en kopiert kommando vanligvis beholder feil grensesnitt.