Een Linux-program aan 'n VPN koppel met UID-reëls
Reels wat op UID mik, sien net plaaslike sokke, en die gewone loopback-uitsondering maak die tonnel dood. Gee die rekening eers 'n roete, en filter en verifieer dan elke stap.
Een program onder Linux aan 'n VPN bind is meestal 'n routeringsprobleem, en die firewall-reël besluit net wat gebeur nadat die roete gekies is. As jy die program se UID in OUTPUT pas voordat die tonnel die verstekroete besit, dan laat die reël juis die verkeer val wat jy wou beskerm. Dieselfde reël kan ook nie die resolverproses sien wat die program se DNS-navrae beantwoord nie. Kry die volgorde reg, en 'n enkele rekening sonder voorregte word 'n betroubare keurger vir die verdeelde tonnel.
Gee die rekening eers 'n roete, dan 'n oordeel
Die eienaar-ooreenstemming beantwoord een vraag: het 'n plaaslike soket wat aan hierdie UID behoort, die pakket gebou? Dit kies nie 'n koppelvlak nie, en dit kan nie verkeer skuif wat die hoof-tabel reeds deur die fisiese NIC stuur nie. Daarom blokkeer 'n UID-reël sonder 'n bypassende roete die program, eerder as om dit om te lei.
Stuur die rekening eers deur sy eie tabel, en laat die firewall daarna die uitslag bevestig. Dit werk op 'n gasheer waarvan iproute2 uidrange verstaan, wat ip rule help in een reël rapporteer. Tabel 100 hou 'n verstekroete deur die tonnel, en die reël stuur net UID 1000 na daardie tabel. Alles anders bly op die hoof-tabel en gebruik steeds die fisiese skakel.
ip rule add uidrange 1000-1000 table 100 ip route add default dev tun0 table 100
'n Tweede rekening wat 'n ander tonnel nodig het, kry tabel 101 en sy eie reël, want twee profiele kan nie albei die verstekroete in dieselfde tabel besit nie. NetworkManager-profiele is stelselwyd, so hierdie deel bly handmatig, en die reëls verdwyn by herbegin as iets hulle nie herstel nie. Skryf die tabelle in 'n opstartskrip langs die tonnel-definisie, sodat 'n herverbinding nie een rekening op die verkeerde pad kan laat nie.
Waarom die loopback-uitsondering die tonnel doodmaak
Die meeste gekopieerde weergawes van die reël laat elke pakket val wat nie deur loopback uitgaan nie. Die tonnel is nie loopback nie, so daardie vorm laat ook die tonnelverkeer val, en die uitkoms lyk soos 'n dooie VPN eerder as 'n firewall-fout.
Wanneer OUTPUT loop, het die kern al 'n uitgaankoppelvlak gekies, so -o word teen die roete se antwoord vergelyk, nie teen die pakket-opskrif nie. Die eienaar-ooreenstemming word net in OUTPUT en POSTROUTING geraadpleeg, en deurgegee pakkette dra geen soket wat dit kan lees nie. Daardie kombinasie beteken die uitsondering moet die tonnel-koppelvlak noem en daardie ooreenstemming ontken, eerder as om loopback te ontken.
Loopback verdien steeds sy eie ACCEPT bo die DROP, want die eerste DNS-pakket van die program gaan na die plaaslike stut oor lo. Sit die twee reëls in hierdie volgorde, en die rekening bereik die stut, dan die tonnel, en niks anders nie.
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 is 'n aparte reëlset, en 'n paar wat net v4 dek, laat ip6tables onaangeraak. 'n Program wat AAAA-rekords voorkeur gee, sou dan deur die fisiese skakel uitgaan sonder om ooit die DROP te bereik. Spiegel albei reëls in ip6tables, of skakel IPv6 op die gasheer af wanneer die tonnel geen v6-adres dra nie. Reels wat met die hand bygevoeg is, verdwyn ook by herbegin, so stoor hulle met netfilter-persistent save of bou dieselfde logika weer as 'n nftables-tabel wat deur die opstarteenheid gelaai word.
DNS-antwoorde kom van 'n ander proses
Die program se navraag na 127.0.0.53 passeer die loopback-ACCEPT, en dit is waar die UID-ooreenstemming stop. Die stut-resolver stuur opwaarts vanaf sy eie diensrekening, so 'n reël wat op vpnapp gemik is, sien nooit die tweede navraag nie. As die resolver 'n LAN-bediener vir die skakel kies, kom antwoorde terug oor die fisiese NIC terwyl die program se eie pakkette in die tonnel bly. Die sigbare uitkoms is 'n werkende tonnel met gebroke name, of name wat deur 'n bediener beantwoord word wat jy nie gekies het nie.
Herstel naamresolusie op die tonnel-skakel, nie op die toepassing nie. Gee die tonnelprofiel 'n DNS-bediener en 'n routeringsdomein, en bevestig dan met resolvectl query en resolvectl status tun0 dat die resolver dit gebruik vir die name wat saak maak. Binne 'n netwerk-naamruimte verdwyn die probleem, want die naamruimte-resolver ken net die tonnel.
Kontroleer die reël van die rekening self af
Vra die kern watter roete 'n UID kry, maak dan 'n versoek as daardie rekening en vergelyk die uitgangsadres met die van jou eie rekening. As albei dieselfde adres rapporteer, pas die reël iets anders as die verkeer wat jy getoets het. Die eerste opdrag hieronder wys die roete-opsoek sonder om 'n pakket te stuur, wat 'n routeringsfout van 'n firewall-fout skei.
ip route get 1.1.1.1 uid 1000 sudo -u vpnapp curl -s https://ifconfig.co
Telers wys of 'n reël ooit gevuur het. Loop iptables -vnL OUTPUT, lees die pakket-telling langs elke reël, en behandel 'n nul by die DROP na regte verkeer as 'n ooreenstemmingsfout.
Deurgegee verkeer val buite hierdie ontwerp. 'n Houer of VM agter 'n brug het geen plaaslike soket wat aan vpnapp behoort nie, so die eienaar-ooreenstemming vuur nooit, en daardie pakkette volg eerder die FORWARD-beleid. As daardie werklading ingedek moet wees, toets dit apart en skryf 'n beleid gemik op die brug of die houeradres. Die ontwerp hou wanneer die tabel, die koppelvlak-uitsondering, die resolver en die v6-reëls almal dieselfde kant wys; laat enige een daarvan weg, en die rekening lek of verloor verbinding.