Maak Docker- en WSL-verkeer reg wat die gasheer-VPN ignoreer
Houers en WSL hou hul eie roetes, resolveerder en deurstuurpad, so 'n werkende gasheer-tonnel laat hulle met verouderde DNS of geen uitgang. Maak elke laag reg.
Ek het die grootste deel van 'n oggend hierdie lente bestee aan 'n houer wat nie 'n enkele interne naam kon resolveer nie, terwyl die blaaier langsaan die wiki sonder klagte oopgemaak het. Die tonnel was op, die blaaier het dit bewys, en die houer het in 'n ander netwerk-naamruimte met 'n ander roetetabel en 'n ander resolveerder. Wat volg is die orde wat ek nou volg: eers roetetabelle, dan resolving, dan deurstuur, en laastens die gasheerplatform. Stop by die eerste stap wat al klaar misluk, want om reëls verder af in die stapel by te voeg versteek die grens eerder as om dit te verskuif.
Vergelyk die drie roetetabelle voordat jy 'n reël verander
'n Houer op Docker se standaardbrug het een standaardroete wat na die docker0-poort wys, en geen idee dat tun0 bestaan nie. Die gasheer het tun0, die roetes wat die VPN gestoot het, en moontlik 'n beleidsreël wat ondersoekverkeer deur 'n ander koppelvlak stuur as wat jy verwag. WSL voeg 'n derde tabel agter sy eie virtuele adapter by. Druk al drie voordat jy enigeen daarvan wysig.
| Context | Command | What a wrong answer looks like |
|---|---|---|
| Host | ip route get 10.8.0.20 | Leaves a physical interface instead of tun0 |
| Container | ip route | Only 172.17.0.0/16 via 172.17.0.1 |
| Container DNS | cat /etc/resolv.conf | A public resolver, or an upstream the tunnel never pushed |
| WSL | ip addr; ip route | Only the WSL subnet, no Windows VPN adapter |
As die houer se enigste roete die brug is en tun0 nooit in sy naamruimte verskyn nie, sal niks hieronder help nie: geen naambediener-verandering skep 'n roete nie, en geen roete skep 'n tonnel-identiteit wat die eweknie sal aanvaar nie. Orde maak saak, want 'n DNS-fout en 'n roetefout lyk identies van binne 'n shell.
Wys die resolveerder na die tonnel eerder as na 'n openbare een
Op die gasheer, resolvectl status lys DNS-bedienerers per skakel, en readlink -f /etc/resolv.conf vertel jou of die lêer die systemd-stub is, 'n NetworkManager-lêer, of iets wat 'n verskaffer se kliënt herskryf het. Binne 'n houer op 'n gebruikergedefinieerde netwerk, /etc/resolv.conf noem 127.0.0.11, Docker se ingeboude resolveerder, wat deurstuur na watter opstroom die daemon ook al mee gekonfigureer is. 'n Houer op die standaardbrug het eerder 'n kopie van die gasheer se lêer gekry toe dit geskep is, en hou dit.
Daardie kopie is die rede waarom 'n tonnel wat opkom nadat die houer begin het, die houer die ou opstroom laat bevraagteken. Gee die VPN-resolveerder óf eksplisiet met docker run --dns 10.8.0.53, of stel "dns": ["10.8.0.53"] in /etc/docker/daemon.json en herbegin die daemon, of herskep die houer sodra die tonnel op is. Herskep is gewoonlik goedkoper as om 'n resolveerder te ontfout wat 'n uur gelede korrek was.
Om 'n openbare resolveerder in te ruil, is die herstelling wat die simptoom laat voortduur. Dit resolveer die internet en misluk in elke private sone, en dit kan stilweg die filtering omseil wat die tonnel bestaan om af te dwing. As jy probeer skryf binne 'n lopende houer se /etc/resolv.conf, verwag Device or resource busy: Docker bind-mount daardie lêer, so die wysiging het eers 'n ontkoppeling nodig. Om --dns by skepping te stel, is die volgorde wat 'n herbegin oorleef.
Stuur deur en vertaal wanneer houers die tonnel leen
Met die standaardbrug is die gasheer 'n roeteerder tussen docker0 en tun0, en dit doen by verstek nie een van die twee take nie. Skakel deurstuur aan, en vertaal die bronadres sodat die eweknie 'n gasheer-tonneladres sien eerder as een waarna dit geen terugroete het nie (vervang tun0 met wat jou kliënt sy koppelvlak noem):
sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE
iptables -A FORWARD -i docker0 -o tun0 -j ACCEPT
iptables -A FORWARD -i tun0 -o docker0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPTDie FORWARD-reëls maak saak op gashere wie se deurstuurbeleid DROP is. Docker voeg sy eie kettings in, so toets met 'n pakket eerder as om te lees iptables -S: van die houer af, ip route get 10.8.0.20 moet die brugpoort noem, en nc -vz 10.8.0.20 443 moet by die tonnel konnekteer of tyd uitloop eerder as by die resolveerder.
Sonder MASQUERADE het die eweknie 'n terugroete na 172.17.0.0/16 nodig, wat die meeste afstandtoegang-VPN's nie sal stoot nie. Dit is ook waar 'n beleidsgebaseerde kliënt die plan breek: as dit net verkeer van spesifieke UID's of cgroups vasvang, sien jou deurstuurreëls nooit die pakket binne die tonnel nie, en die regstelling hoort in die kliënt se roetebeleid eerder as in iptables. Reëls wat met die hand bygevoeg is, verdwyn by herbegin, so sit hulle in 'n systemd-eenheid of 'n netfilter-persistent-tabel en toets weer ná 'n herbegin, want 'n tonnel wat laat opkom, kan hulle uitwis.
Plaas die tonnel binne die houer wanneer isolasie die doel is
As een houer deur 'n spesifieke nodus moet uitgaan, hardloop die kliënt in daardie houer. Dit benodig --cap-add NET_ADMIN en --device /dev/net/tun, en dan besit dit sy eie tun0, roetes en vuurmuur. As ander houers daardeur gaan, het dit ook deurstuur en 'n MASQUERADE-reël binne die houer nodig, en daardie eweknieë het 'n eksplisiete roete of proxy nodig wat daarheen wys; Docker se standaardbrug voeg nie daardie roete vir jou by nie.
Gasheer-netwerking, docker run --network host, is die goedkoop weergawe: die houer sluit by die gasheer se naamruimte aan en sien die tonnelroetes direk. Dit laat ook netwerkisolasie vaar, nooi poortbotsings uit, en is in die praktyk 'n Linux-opsie. 'n Gepubliseerde poort is nie 'n plaasvervanger nie. -p 8080:80 maak 'n diens bereikbaar vanaf die gasheer; dit maak nie interne 10.x-adresse bereikbaar van binne die houer nie, en om die twee te verwar is hoe 'n roeteprobleem 'n blootgestelde databasispoort word.
Onderskei 'n naamfout van 'n oorvleuelende subnet
Docker se standaardbrug is 172.17.0.0/16, en baie korporatiewe VPN-poelle sit binne 172.16.0.0/12. Sodra die tonnel daardie reeks besit, kan verkeer wat vir 'n houer bedoel is, eerder in die tonnel ingeroeteer word. Name misluk, die fout lyk soos DNS, en die adresse is die probleem. Kontroleer die bestemming, nie die resolveerder nie: ip route get 172.17.0.5 op die gasheer, en vergelyk dan die brugvoorvoegsel met die VPN-poel en met docker network inspect bridge --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'.
Die regstelling is om een van die reekse te skuif, hetsy 'n ander standaard-adrespoel vir Docker in daemon.json of 'n ander poel op die konsentrator. Om nog 'n naambediener by te voeg, doen hier niks, en dit doen ook nie ssh -b: om die kliënt aan 'n koppelvlak te bind, verander die bronadres, nie 'n bestemmingsroete wat in die tonnel in wys nie. Vinnige arbeidsverdeling: 'n naam wat op die gasheer resolveer maar nie in die houer nie, is 'n resolveerderprobleem, terwyl 'n direkte IP-verbinding wat in die houer hang maar op die gasheer werk, 'n roete- of deurstuurkettingsprobleem is.
WSL en Docker Desktop volg nie die Linux-reëls nie
In sy standaard NAT-modus sit WSL agter sy eie virtuele adapter en ontvang nie die Windows-VPN se interne roetes of DNS-agtervoegsels nie, wat is hoekom die blaaier werk en ping binne die verspreiding nie. Gespieëlde netwerking, beskikbaar op onlangse Windows 11-bouwe, deel eerder die gasheer se koppelvlakke, maar dit moet geaktiveer word in .wslconfig en die verspreiding herbegin met wsl --shutdown. Bevestig die aktiewe modus met wslinfo --networking-mode voordat jy 'n regstelling toepas, want die NAT-antwoord is verkeerd vir gespieëlde modus en omgekeerd.
Docker Desktop voeg nog 'n laag by. Linux-houers op Windows sit agter 'n NAT-implementering wat histories vpnkit genoem word, en hul pad verskil van 'n native Linux-gasheer. Windows-houers koppel deur 'n Hyper-V virtuele skakelaar, en 'n korporatiewe kliënt kan verkeer van daardie skakelaar blokkeer, so Linux-houers op dieselfde masjien kan die netwerk bereik terwyl Windows-houers niks het nie. 'n Eksterne skakelaar wat aan die fisiese adapter gebind is, is die gewone oplossing, en dit verander die houer se netwerkidentiteit op maniere wat beleid dalk nie toelaat nie.
Voordat jy nog 'n reël skryf, loop die vier lae in orde deur en stop waar een van hulle verkeerd is:
- Binne die houer: bereik
ip routedie private voorvoegsel, en noem/etc/resolv.conf'n opstroom wat dit resolveer? - Op die gasheer: is deurstuur aan, is NAT aan die tonnelkoppelvlak gebind, en aanvaar die deurstuurketting brug na tonnel?
- Op die eweknie: ken dit 'n terugpad, of maak jy staat op NAT om die houer-subnet te versteek?
- Op die platform: is WSL in NAT- of gespieëlde modus, en is die houer Linux of Windows?
Voer elke toets weer uit in 'n nuwe houer of shell. 'n Langdurige proses met 'n gekasde antwoord of 'n gevestigde verbinding sal aanhou misluk nadat die konfigurasie korrek is, en daardie mislukking lyk presies soos 'n regstelling wat nie gewerk het nie.