Sådan binder du én Linux-app til en VPN med UID-regler
En UID-regel ser kun lokale sockets, og den sædvanlige loopback-undtagelse dræber tunnelen. Rut kontoen først, og filtrér og verificér derefter hvert trin.
At binde ét program til en VPN på Linux er mest et routingproblem, og firewall-reglen afgør kun, hvad der sker, efter ruten er valgt. Hvis du matcher programmets UID i OUTPUT, før tunnelen ejer standardruten, dropper reglen netop den trafik, du ville beskytte. Samme regel kan heller ikke se den resolverproces, der svarer på programmets DNS-forespørgsler. Få rækkefølgen rigtig, og én konto uden rettigheder bliver en pålidelig vælger til den delte tunnel.
Giv kontoen en rute før en dom
Owner-matchningen besvarer ét spørgsmål: byggede en lokal socket, der tilhører denne UID, pakken? Den vælger ikke et interface, og den kan ikke flytte trafik, som hovedtabellen allerede sender ud gennem det fysiske NIC. Derfor blokerer en UID-regel uden en matchende rute programmet i stedet for at omdirigere det.
Send kontoen gennem dens egen tabel først, og lad derefter firewallen bekræfte resultatet. Det virker på en vært, hvis iproute2 forstår uidrange, hvilket ip rule help melder på én linje. Tabel 100 rummer en standardrute gennem tunnelen, og reglen sender kun UID 1000 til den tabel. Alt andet bliver på hovedtabellen og bruger fortsat det fysiske link.
ip rule add uidrange 1000-1000 table 100 ip route add default dev tun0 table 100
En anden konto, der har brug for en anden tunnel, får tabel 101 og sin egen regel, fordi to profiler ikke begge kan eje standardruten i samme tabel. NetworkManager-profiler er systemomfattende, så denne del forbliver manuel, og reglerne forsvinder ved genstart, medmindre noget gendanner dem. Skriv tabellerne ind i et opstartsskript ved siden af tunneldefinitionen, så en genopkobling ikke kan efterlade én konto på den forkerte vej.
Hvorfor loopback-undtagelsen dræber tunnelen
De fleste kopierede versioner af reglen dropper hver pakke, der ikke forlader gennem loopback. Tunnelen er ikke loopback, så den form dropper også tunnelens trafik, og resultatet ligner en død VPN frem for en firewallfejl.
Når OUTPUT kører, har kernen allerede valgt et udgangsinterface, så -o sammenlignes med rutens svar i stedet for pakkens header. Owner-matchningen konsulteres kun i OUTPUT og POSTROUTING, og videresendte pakker bærer ingen socket, som den kan læse. Den kombination betyder, at undtagelsen skal navngive tunnelens interface og negere den matchning i stedet for at negere loopback.
Loopback fortjener stadig sin egen ACCEPT over DROP, fordi den første DNS-pakke fra programmet går til den lokale stub over lo. Sæt de to regler i denne rækkefølge, og kontoen når stubben, derefter tunnelen, og intet andet.
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 separat regelsæt, og et par kun til v4 efterlader ip6tables urørt. Et program, der foretrækker AAAA-poster, ville så forlade gennem det fysiske link uden nogensinde at nå DROP. Spejl begge regler i ip6tables, eller slå IPv6 fra på værten, når tunnelen ikke bærer nogen v6-adresse. Håndtilføjede regler forsvinder også ved genstart, så gem dem med netfilter-persistent save eller genopbyg samme logik som en nftables-tabel, der indlæses af opstartsenheden.
DNS-svar kommer fra en anden proces
Programmets forespørgsel til 127.0.0.53 passerer loopback-ACCEPT, og det er der, UID-matchningen stopper. Stub-resolveren videresender opad fra sin egen tjenestekonto, så en regel, der er knyttet til vpnapp ser aldrig den anden forespørgsel. Hvis resolveren vælger en LAN-server til linket, kommer svarene tilbage over det fysiske NIC, mens programmets egne pakker bliver i tunnelen. Det synlige resultat er en fungerende tunnel med ødelagte navne, eller navne besvaret af en server, du ikke valgte.
Ret navneopløsningen på tunnellens link, ikke i applikationen. Giv tunnelprofilen en DNS-server og et routingdomæne, og bekræft derefter med resolvectl query og resolvectl status tun0 at resolveren bruger den til de navne, der betyder noget. Inde i et netværksnavnerum forsvinder problemet, fordi navnerummets resolver kun kender tunnelen.
Kontrollér reglen fra selve kontoen
Spørg kernen, hvilken rute en UID får, og lav derefter en anmodning som den konto og sammenlign udgangsadressen med din egen kontos. Hvis begge rapporterer den samme adresse, matcher reglen noget andet end den trafik, du testede. Den første kommando nedenfor viser ruteopslaget uden at sende en pakke, hvilket skelner en routingfejl fra en firewallfejl.
ip route get 1.1.1.1 uid 1000 sudo -u vpnapp curl -s https://ifconfig.co
Tællere viser, om en regel nogensinde blev udløst. Kør iptables -vnL OUTPUT, læs pakketallet ved siden af hver regel, og behandl et nul ved DROP efter rigtig trafik som en matchningsfejl.
Videresendt trafik ligger uden for dette design. En container eller VM bag en bro har ingen lokal socket ejet af vpnapp, så owner-matchningen udløses aldrig, og de pakker følger i stedet FORWARD-politikken. Hvis den arbejdsbyrde skal dækkes, test den separat og skriv en politik knyttet til broen eller containerens adresse. Designet holder, når tabellen, interface-undtagelsen, resolveren og v6-reglerne alle peger samme vej; udelad en af dem, og kontoen lækker eller mister forbindelsen.