Paano i-route ang isang app sa VPN nang hindi buong makina
Walang hindi pinamamahalaang desktop na nag-aalok ng VPN switch kada proseso. Piliin ang layer na pumipili ng trapiko: nakatali na socket, UID rule, firewall profile, o SOCKS hop.
Kumokonekta ang VPN client, gumagana ang browser, at ang nag-iisang command na talagang mahalaga sa iyo ay lumalabas pa rin sa iyong koneksyon sa bahay. O kabaligtaran ang nangyayari: kinukuha ng tunnel ang default na ruta at nawawala ang lokal na file server sa desktop. Naranasan ko ito sa isang build agent na kailangang maabot ang panloob na salamin ng artifact habang ang natitirang host ay nanatili sa LAN ng opisina, at eksaktong dalawang pagpipilian lang ang inalok ng client, lahat ng trapiko o wala. Pareho ang kahilingan sa magkabilang direksyon, ang program na ito at hindi ang buong makina, at karamihan ng client ay walang checkbox para dito, dahil hindi kailanman alam ng routing table kung ano ang isang program.
Bakit hindi makita ng routing table ang iyong program
Kapag nagpadala ang isang proseso ng packet, hinahanap ng stack ang destination address sa routing table. Ni ang pangalan ng executable ni ang port ay hindi pumapasok sa paghahanap na iyon. Nabibigo rin ang mga domain name sa parehong dahilan: dinadala ng tunnel ang trapiko sa isang address, at sa oras na ma-resolve ang isang pangalan sa isang address, ang routing na lang ang natitirang lever ng kernel. Kaya ang "VPN para sa site na ito lang" ay nauuwi sa proxy, at ang "VPN para sa program na ito lang" ay nauuwi sa isa sa maliit na hanay ng mekanismo.
| Mekanismo | Ano ang pumipili | Sakop | Kapag bumagsak ang tunnel |
|---|---|---|---|
| Pagtali ng socket | source address | client na kontrolado mo | nabibigo ang mga koneksyon |
| UID rule (Linux) | may-ari na user | bawat proseso ng isang account | nabibigo ang mga koneksyon |
| Firewall profile (Windows) | profile ng adapter | isang program | bumabagsak nang sarado |
| Network namespace | pagiging miyembro ng namespace | lahat ng sinimulan sa loob | nabibigo ang mga koneksyon |
| SOCKS hop | proxy setting ng app | isang app o isang profile ng browser | nabibigo ang mga koneksyon |
Wala sa mga ito ang ruta kada proseso. Inililipat ng bawat isa ang desisyon sa layer na nakakakita ng program, user, o sariling configuration ng app.
Ang isang destinasyon ay ruta pa rin, hindi patakaran ng program. Sa macOS ang karaniwang recipe ay alisin ang tsek sa "Ipadala ang lahat ng trapiko sa VPN" at magdagdag ng host route: sudo route add -host internal-tuner.example -interface ppp0, na tinatanggal muli gamit ang sudo route delete -host internal-tuner.example -interface ppp0. Basahin muna ang pangalan ng interface mula sa ifconfig, dahil ang ppp0 ay halimbawa lamang. Hindi gumagana ang wildcard sa host route, kaya ang serbisyong nakikipag-usap sa maraming pangalan ay nangangailangan ng isang entry kada pangalan, at sinasaklaw ng patakaran ang bawat proseso sa makina, hindi ang nasa isip mo.
Itali ang socket sa address ng tunnel
Kapag kontrolado mo ang client, ang pagtali ang pinakamurang selector. Ang socket na nakatali sa lokal na address ng tunnel ay lumalabas sa interface na iyon hangga't may ruta papunta sa destinasyon doon, at ang iba pa sa makina ay nagpapanatili ng normal na landas. Ang subtle ay ang pagtali ang pumipili ng source address habang ang routing table pa rin ang pumipili ng labasan. Ang pagtali lamang ay hindi naglilipat ng trapikong walang ruta papasok sa tunnel, at iyon ang pagkakamali sa likod ng karamihan ng ulat na "tinali ko na at mali pa rin ang labasan".
import socket
s = socket.socket()
s.bind(("10.8.0.2", 0))
s.connect(("build.internal.example", 443))Ang mas matataas na tool ay nagpapakita ng parehong ideya: curl --interface 10.8.0.2, CURLOPT_INTERFACE sa PHP at ang argumentong source_address sa mga HTTP client ng Python. Dapat pag-aari ng tunnel ang address, at ang typo dito ay nabibigo bilang ordinaryong error sa koneksyon, hindi bilang reklamo sa routing. Ang pagtali sa pangalan ng device sa halip na address ay pribilehiyo ng Linux at hindi umaabot sa Windows o macOS, kaya ipinapasa ng portable script ang address.
Linux: itugma ang may-ari, hindi ang pangalan ng program
Kayang itugma ng kernel ang may-ari na user ng socket, kaya nagiging selector ang dedikadong account. Ilagay ang tunnel sa sarili nitong routing table at doon lang ipadala ang trapiko ng account na iyon:
ip rule add uidrange 1001-1001 lookup 100
ip route add default dev tun0 table 100Gumagana lang ito kung hindi pa default na ruta ang tunnel. Simulan ang client gamit ang --route-nopull, o i-filter ang itinulak na redirect gamit ang --pull-filter ignore "redirect-gateway" sa OpenVPN 2.4 at mas bago, pagkatapos ay idagdag mo mismo ang entry sa table. Kung hindi, may dalawang default at ang mas mababang priority ang nananalo. Ang sinadyang bersyon niyan ay ituro ang default na ruta sa gateway ng tunnel, o gawin ito mula sa disconnect script: pinipigilan nito ang trapiko sa internet kapag bumagsak ang tunnel, pero kill switch iyon, hindi selector, at nananatili hanggang may mag-alis.
Ang mas matibay na bersyon ay network namespace. Gumawa, patakbuhin ang client sa loob, at simulan ang app gamit ang ip netns exec. Walang nakikita sa labas ng namespace ang interface ng tunnel, kaya hindi aksidenteng makakabalik ang app sa ruta ng host. Totoong may gastos: kailangan ng namespace ng veth pair para maabot ang pisikal na network at sariling resolver file, dahil hindi ibinabahagi ng mount namespace ang resolution setting ng host.
Dalawang failure mode ang nagpapaliwanag sa karamihan ng leak. Nangyayari pa rin ang name resolution sa resolver ng host, kaya lumalabas ang query sa labas ng tunnel kahit papasok ang TCP connection. At kailangan ng IPv6 ng sarili nitong ip -6 rule, dahil hindi ito sinasaklaw ng v4 rule.
Windows at macOS: limitahan ang firewall o magbigay ng proxy
Wala rin sa Windows ang ruta selector kada app, pero ang firewall rule nito ay maaaring limitahan sa isang profile, at ang VPN adapter ay maaaring uriin bilang Public habang nananatiling Private ang LAN sa bahay. Gumawa ng outbound block rule para sa program sa Private at Domain profile, hayaang bukas ang Public, at maaabot lang ng app ang network sa tunnel. Itakda muna ang network category ng koneksyon, pagkatapos ay kumpirmahin sa monitor pane ng firewall na tumugma ang rule. Block ito, hindi ruta: bumabagsak nang sarado kapag bumagsak ang tunnel, at hindi mapipigilan ang app na binabalewala ang firewall.
Sinusunod ng macOS ang parehong lohika sa ibang tool. Ang SOCKS listener na naabot sa SSH ang pinakamaliit na interbensyon, dahil ssh -D 1080 user@host ay gumagawa ng isang lokal na port at ang mga app lang na naka-configure para gamitin ito ang dumadaan doon. Ang pf rule ay makakapigil ng program ayon sa user o grupo, pero hindi pa rin mapipili ang tunnel para sa program na iyon lang. Hindi kayang mag-filter ng domain ang Tunnelblick, dahil gumagana sa address ang ruta; ang mga gumagamit ng OpenConnect ay humihingi ng vpn-slice kapag masyadong malawak ang prefix list na itinutulak ng server.
Dalawang workaround ang sumasaklaw sa kulang ng platform tool. Ang browser extension na nagpapalit ng proxy kada domain ang praktikal na sagot sa "site na ito lang", dahil kumikilos sila sa application layer kung saan may mga pangalan pa; isang browser lang ang sakop at wala nang iba. Ang magaspang na paraan ay patakbuhin ang vendor client sa virtual machine para ang guest ang may-ari ng pagbabago ng ruta habang pinapanatili ng host ang landas nito, kapalit ng dalawang network stack na aalagaan.
SOCKS hop para sa mga tool na walang pagpipiliang pagtali
Karamihan ng app ay maaaring ituro sa HTTP o SOCKS proxy kahit walang alam sa interface. Nagbibigay ang SSH client ng isa nang walang pagbabago sa server:
ssh -N -D 127.0.0.1:9999 [email protected]Lahat ng naka-configure na gumamit ng port na iyon ay lumalabas sa bastion habang ang natitirang desktop ay nagpapanatili ng normal na koneksyon. Ang lokal na 3proxy instance na nakatali sa address ng tunnel ay gumagawa rin ng ganoon para sa isang port nang walang SSH, at sinasaklaw ng stunnel ang isang port na nakabalot sa TLS. Praktikal ang limitasyon: ang proxy ay nagdadala lang ng protocol na marunong gumamit nito, kailangan ng UDP ng SOCKS5 UDP association na hindi binubuksan ng "SOCKS5" setting ng maraming client, at dapat i-resolve ng proxy ang DNS (socks5h sa curl) kundi lumalabas ang pangalan sa lokal na resolver.
Panatilihin ang listener sa loopback maliban kung kailangan ito ng ibang makina.
I-verify ang landas sa capture, hindi sa status message
Inilalarawan ng status window ng app ang setting, hindi ang packet. Mag-capture sa dalawang interface at ihambing:
tcpdump -i any -n port 443
ss -tnp | grep 443Kung lumalabas ang koneksyon sa pisikal na interface na walang tugmang entry sa tunnel, hindi gumagana ang selector, ano man ang iulat ng client. Suriin nang hiwalay ang IPv6 at ang resolver, at maghanap ng pangalawang landas gaya ng helper process o namamana na system proxy.
Pagkatapos piliin ang hangganang tumutugma sa pangangailangan: sapat ang proxy para sa isang site, sapat ang UID rule para sa isang account, sapat ang firewall profile kapag kailangang bumagsak nang sarado ang koneksyon, at namespace lang ang pagpipiliang nagtatago ng tunnel mula sa lahat ng nasa labas nito.