Å binde ett program til en VPN på Linux er mest et ruteproblem, og brannmurregelen avgjør bare hva som skjer etter at ruten er valgt. Hvis du matcher programmets UID i OUTPUT før tunnelen eier standardruten, slipper regelen nettopp den trafikken du ville beskytte. Samme regel ser heller ikke resolverprosessen som svarer på programmets DNS-spørringer. Få rekkefølgen riktig, og én konto uten rettigheter blir en pålitelig velger for den delte tunnelen.

Gi kontoen en rute før en dom

Eier-matchingen svarer på ett spørsmål: bygde en lokal sokkel som tilhører denne UID-en, pakken? Den velger ikke grensesnitt, og den kan ikke flytte trafikk som hovedtabellen allerede sender ut gjennom den fysiske NIC-en. Derfor blokkerer en UID-regel uten samsvarende rute programmet i stedet for å omdirigere det.

Send kontoen gjennom sin egen tabell først, og la deretter brannmuren bekrefte resultatet. Dette virker på en vert der iproute2 forstår uidrange, noe ip rule help melder på én linje. Tabell 100 holder en standardrute gjennom tunnelen, og regelen sender bare UID 1000 til den tabellen. Alt annet blir på hovedtabellen og bruker fortsatt den fysiske lenken.

ip rule add uidrange 1000-1000 table 100
ip route add default dev tun0 table 100

En annen konto som trenger en annen tunnel får tabell 101 og sin egen regel, fordi to profiler ikke kan eie standardruten i samme tabell samtidig. NetworkManager-profiler er systemomfattende, så denne delen blir manuell, og reglene forsvinner ved omstart med mindre noe gjenoppretter dem. Skriv tabellene i et oppstartsskript ved siden av tunneldefinisjonen, slik at en gjenoppkobling ikke kan etterlate én konto på feil vei.

Hvorfor loopback-unntakelsen dreper tunnelen

De fleste kopierte versjoner av regelen slipper hver pakke som ikke går ut gjennom loopback. Tunnelen er ikke loopback, så den formen slipper også tunneltrafikken, og resultatet ser ut som en død VPN og ikke som en brannmurfeil.

Når OUTPUT kjører, har kjernen allerede valgt et utgangsgrensesnitt, så -o sammenlignes med rutens svar og ikke med pakkehodet. Eier-matchingen konsulteres bare i OUTPUT og POSTROUTING, og videresendte pakker bærer ingen sokkel som den kan lese. Den kombinasjonen betyr at unntakelsen må navngi tunnelens grensesnitt og negere den matchingen, i stedet for å negere loopback.

Loopback fortjener fortsatt sin egen ACCEPT over DROP, fordi den første DNS-pakken fra programmet går til den lokale stubben via lo. Sett de to reglene i denne rekkefølgen, og kontoen når stubben, deretter tunnelen, og ingenting annet.

iptables -I OUTPUT 1 -o lo -m owner --uid-owner vpnapp -j ACCEPT
iptables -A OUTPUT -m owner --uid-owner vpnapp ! -o tun0 -j DROP

IPv6 er et eget regelsett, og et par bare for v4 lar ip6tables stå urørt. Et program som foretrekker AAAA-poster, ville da gå ut gjennom den fysiske lenken uten å nå DROP i det hele tatt. Speil begge reglene i ip6tables, eller slå av IPv6 på verten når tunnelen ikke bærer noen v6-adresse. Regler som legges til manuelt, forsvinner også ved omstart, så lagre dem med netfilter-persistent save eller bygg samme logikk på nytt som en nftables-tabell som oppstartsenheten laster.

DNS-svar kommer fra en annen prosess

Programmets spørring til 127.0.0.53 passerer loopback-ACCEPT, og det er der UID-matchingen stopper. Stub-resolveren videresender oppover fra sin egen tjenestekonto, så en regel knyttet til vpnapp ser aldri den andre spørringen. Hvis resolveren velger en LAN-server for lenken, kommer svarene tilbake over den fysiske NIC-en mens programmets egne pakker blir i tunnelen. Det synlige resultatet er en fungerende tunnel med ødelagte navn, eller navn besvart av en server du ikke valgte.

Rett navneoppløsningen på tunnelens lenke, ikke i applikasjonen. Gi tunnelprofilen en DNS-server og et rutingsdomene, og bekreft deretter med resolvectl query og resolvectl status tun0 at resolveren bruker den for navnene som betyr noe. Inne i et nettverksnavnerom forsvinner problemet, fordi navnerommets resolver bare kjenner tunnelen.

Kontroller regelen fra selve kontoen

Spør kjernen hvilken rute en UID får, og lag deretter en forespørsel som den kontoen og sammenlign utgangsadressen med din egen kontos. Hvis begge rapporterer samme adresse, matcher regelen noe annet enn trafikken du testet. Den første kommandoen nedenfor viser ruteoppslaget uten å sende en pakke, noe som skiller en ruteleif fra en brannmurfeil.

ip route get 1.1.1.1 uid 1000
sudo -u vpnapp curl -s https://ifconfig.co

Tellere viser om en regel noen gang ble utløst. Kjør iptables -vnL OUTPUT, les pakketallet ved siden av hver regel, og behandl en null ved DROP etter ekte trafikk som en matchefeil.

Videresendt trafikk ligger utenfor dette designet. En container eller VM bak en bro har ingen lokal sokkel eid av vpnapp, så eier-matchingen utløses aldri, og de pakkene følger i stedet FORWARD-policyen. Hvis den arbeidsmengden skal dekkes, test den separat og skriv en policy knyttet til broen eller containeradressen. Designet holder når tabellen, grensesnittunntakelsen, resolveren og v6-reglene alle peker samme vei; utelat én av dem, og kontoen lekker eller mister tilkoblingen.

Relaterte artikler