Sådan bliver en OpenVPN-klient bag NAT internettets udgang
Udgangen ringer selv ud, så dens router behøver ingen indgående port. Følg hvad hubben ruter, hvad udgangen videresender, og hvor returvejen kommer fra.
Tre Linux-værter, ét design: en offentligt tilgængelig OpenVPN-hub, en forbrugerbærbar og en udgangsmaskine bag en almindelig hjemmerouter, der ikke videresender noget indad. Udgangen ringer selv til hubben. Forbrugerens internettrafik går derefter ind i tunnelen ved den bærbare og ud gennem udgangens egen uplink. Alt overraskende ved dette følger af én detalje: udgangen startede forbindelsen, så vejen indad findes allerede, og der kræves ingen portforwarding for at skabe den.
Det følgende følger pakkens vej frem for konfigurationsrækkefølgen, fordi konfigurationen først giver mening, når man ved, hvilken komponent der ejer hvilken beslutning. Hvert lag ejer præcis én beslutning, og fejlene klumper sig sammen, hvor to lag antages at være ét.
To transportssessioner, én indre vej
Hver vært holder sin egen ydre forbindelse til hubben, og ingen af dem kender den anden. Forbrugerens trafik til internettet er en separat indre strøm, som tilfældigvis bæres inde i forbrugerens tunnel og derefter sendes ud igen fra udgangens tunnel. Den indre strøm er det, hubben skal rute, og det, udgangen skal videresende.
outer: consumer --TLS--> hub
outer: exit --TLS--> hub
inner: consumer --tun--> hub --internal--> exit --tun--> uplink
Fordi begge ydre forbindelser går udad fra klientsiden, ser udgangens router aldrig et indgående SYN og har aldrig brug for en destination-NAT-regel. Den skal blot holde den etablerede transport i live, hvilket den allerede gør for enhver langvarig forbindelse. Intet på det offentlige internet behøver først at nå udgangen, og derfor er en dynamisk adresse på den uplink ikke et problem. Routeren skal stadig tillade den udgående session, men det er den samme tilladelse, en browser allerede bruger.
Hvad iroute egentlig installerer inde i serveren
Hubben er den eneste enhed, der afgør, hvilken peer der ejer hvilken destination, og den træffer den beslutning i sin egen brugertilstands-rutetabel, ikke i kernens. En client-config-dir-post for udgangen med navnet exit-node kan gøre krav på standardpræfikset der:
# /etc/openvpn/server/ccd/exit-node
iroute 0.0.0.0 0.0.0.0
Den linje fortæller serverprocessen "indre pakker med enhver destination tilhører denne klient". Den tilføjer ikke en standardrute til hubbens operativsystem og gør ikke hubben til en internetgateway. OpenVPN 2.6-reference holder klientspecifik intern routing og kernel-routing som separate mekanismer, og den adskillelse er grunden til, at designet virker uden at røre hubbens standardrute.
Forbrugeren skal have den spejlvendte instruktion leveret som push, så dens egen trafik går ind i tunnelen i stedet for ud gennem dens lokale gateway. Med subnettopologi er poolen en forbundet rute på udgangens tun-enhed, så returretningen kræver ingen ekstra push; det, udgangen ikke må modtage, er omdirigeringen nedenfor, som ville sende dens egen uplinktrafik tilbage i den tunnel, den forsøger at bruge. Send den kun til forbrugeren, og læs de anvendte ruter på klienten i stedet for at stole på, at CCD-filen blev valgt.
# /etc/openvpn/server/ccd/consumer-01
push "redirect-gateway def1"
Udgangens kerne står for videresendelsen
Inde i udgangen ankommer en pakke fra forbrugeren på tun-interfacet adresseret til en eller anden internetvært. Kernen slår op i sin rutetabel, finder den rigtige uplink som det bedste match og anvender derefter to uafhængige politikker: må denne pakke videresendes overhovedet, og må den forlade den interface med den kildeadresse. Videresendelse er en sysctl, og den er slået fra som standard på mange distributioner.
Så udgangen har brug for vedvarende aktiveret IPv4-videresendelse, en videresendelsesregel, der lukker forbrugerens tunnelkilder ind mod uplinken, og returvejen tilbage gennem tun. At aktivere videresendelse for hele værten ændrer også adfærden for alt andet, der ruter gennem den, og derfor bør reglen navngive kilderne og interfacene i stedet for at acceptere alt.
Kildeoversættelse er det, der køber returvejen
En internetvært har ingen rute til en 10.90.0.x-adresse, så svar ville blive droppet, før de nåede udgangen. At omskrive kilden, når pakken forlader uplinken, løser det, og forbindelsessporing vender omskrivningen på vejen tilbage.
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -s 10.90.0.0/24 -o enp1s0 -j MASQUERADE
ip -4 route get 10.90.0.9 # run on the exit: must point at the tun
Reglen ovenfor er et udgangspunkt for ét uplink-interface, ikke en firewallpolitik. Indsnævr kilden til de tildelinger, du faktisk har autoriseret, og hold udgangens egen inputpolitik adskilt, så maskering af tunneltrafik ikke stiltiende blotlægger lokale tjenester. På en vært med dynamisk uplinkadresse sparer maskering dig også for at spore adressen manuelt.
Hvor hubben kan håndhæve, og hvor den ikke kan
Med client-to-client og den traditionelle brugerrums-datasti overdrager hubben indre pakker mellem peers inde i serverprocessen. De passerer aldrig hubbens kernel-FORWARD-kæde, så en kernelregel der kan ikke begrænse peer-til-peer-transit, uanset hvor omhyggeligt den er skrevet. Håndhævelse må ligge i serverens egen politik: hvem må forbinde, hvilken CCD-fil de får, og om udgangens standardejerskab overhovedet gives.
Det er også derfor, en standard-iroute er en bred tillidsbeslutning. Udgangen skal legitimt acceptere returtrafik fra vilkårlige internetadresser, og den skal være en maskine, du kontrollerer, patcher og overvåger. At give samme ejerskab til en peer, du ikke ville give en router er den fejl, dette design indbyder til.
Medlemskab er den egentlige kontrol. Enhver klient, der kan konfigurere sine egne ruter, kan forsøge at bruge udgangen, så at begrænse, hvem der må forbinde, eller hvilke peers udgangen betjener, er en del af designet og ikke en eftertanke.
Sikker fejl, når udgangen forsvinder
Tag udgangen offline, og det interne standardejerskab forsvinder med dens session. Det, der ikke må ske, er at hubben stille bliver erstatningsudgangen: ingen standardrute fra VPN-poolen til hubbens uplink og ingen bred maskeringsregel på hubben, der villigt ville videresende den samme trafik. Test den fejl med vilje, og test derefter gendannelse med en frisk strøm i stedet for en side, der allerede var åben.
# on the consumer, with the exit up and then down
ip -4 route get 1.1.1.1
curl -sS -o /dev/null -w '%{http_code}\n' https://example.com
Hvis forbrugerens trafik stadig når internettet, efter udgangen er væk, bærer noget andet den, og den grænse, du havde tænkt, findes ikke. Behandl DNS og IPv6 som separate beslutninger: en IPv4-rute plus maskering siger intet om AAAA-trafik, og en resolver, som hubben skubber, svarer fra hvor forespørgslen faktisk forlader.