Riparu la trafikon de Docker kaj WSL, kiu ignoras la gastigan VPN
Ujoj kaj WSL tenas proprajn itinerojn, solvilon kaj plusendan vojon, do funkcianta gastiga tunelo lasas ilin kun malnova DNS aŭ sen eliro. Riparu ĉiun tavolon.
Mi pasigis la plej grandan parton de unu mateno ĉi-printempe postkurante ujon, kiu ne povis solvi eĉ unu internan nomon, dum la retumilo apude malfermis la vikion sen plendo. La tunelo estis supre, la retumilo pruvis ĝin, kaj la ujo restis en alia reta nomspaco kun alia itinertabelo kaj alia solvilo. Tio, kio sekvas, estas la ordo, kiun mi nun kontrolas: unue itinertabeloj, due solvado, trie plusendo kaj laste la gastiga platformo. Haltu ĉe la unua paŝo, kiu jam malsukcesas, ĉar aldoni regulojn pli malsupre en la stako kaŝas la limon anstataŭ movi ĝin.
Komparu la tri itinertabelojn antaŭ ol ŝanĝi regulon
Ujo sur la defaŭlta ponto de Docker havas unu defaŭltan itineron al la pordego docker0 kaj neniun ideon, ke tun0 ekzistas. La gastiganto havas tun0, la itinerojn, kiujn la VPN puŝis, kaj eble politikan regulon, kiu sendas sondan trafikon tra alia interfaco ol vi atendas. WSL aldonas trian tabelon malantaŭ sia propra virtuala adaptilo. Presu ĉiujn tri antaŭ ol redakti iun ajn el ili.
| 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 |
Se la sola itinero de la ujo estas la ponto kaj tun0 neniam aperas en ĝia nomspaco, nenio malsupre helpos: neniu nomservila ŝanĝo kreas itineron, kaj neniu itinero kreas tunelan identecon, kiun la samtavolano akceptos. La ordo gravas, ĉar DNS-malsukceso kaj itinera malsukceso aspektas identaj de interne de ŝelo.
Direktu la solvilon al la tunelo anstataŭ al publika
Sur la gastiganto, resolvectl status listigas DNS-servilojn laŭ ligilo, kaj readlink -f /etc/resolv.conf diras al vi, ĉu la dosiero estas la systemd-stub, NetworkManager-dosiero aŭ io, kion reverkis kliento de vendisto. Ene de ujo sur uzantdifinita reto, /etc/resolv.conf nomas 127.0.0.11, la enkonstruitan solvilon de Docker, kiu plusendas al tiu supravojo, kun kiu la demono estis agordita. Ujo sur la defaŭlta ponto male ricevis kopion de la gastiga dosiero, kiam ĝi estis kreita, kaj tenas ĝin.
Tiu kopio estas la kialo, ke tunelo, kiu leviĝas post la starto de la ujo, lasas la ujon demandi la malnovan supravojon. Aŭ transdonu la VPN-solvilon eksplicite per docker run --dns 10.8.0.53, aŭ agordu "dns": ["10.8.0.53"] en /etc/docker/daemon.json kaj restartigu la demonon, aŭ rekrei la ujon, kiam la tunelo estas supre. Rekreado kutime malpli kostas ol sencimigi solvilon, kiu estis ĝusta antaŭ horo.
Anstataŭigi per publika solvilo estas la riparo, kiu konservas la simptomon. Ĝi solvas la interreton kaj malsukcesas en ĉiu privata zono, kaj ĝi povas kviete preterpasi la filtradon, por kiu la tunelo ekzistas. Se vi provas skribi ene de /etc/resolv.conf de funkcianta ujo, atendu Device or resource busy: Docker bind-muntas tiun dosieron, do la redakto unue bezonas malmuntadon. Agordi --dns ĉe kreado estas la sinsekvo, kiu postvivas restartigon.
Plusendu kaj traduku, kiam ujoj pruntas la tunelon
Kun la defaŭlta ponto, la gastiganto estas enkursigilo inter docker0 kaj tun0, kaj defaŭlte ĝi faras neniun el la du taskoj. Ŝaltu plusendadon kaj traduku la fontadreson, por ke la samtavolano vidu tunelan adreson de la gastiganto anstataŭ unu, al kiu ĝi havas neniun revenan itineron (anstataŭigu tun0 per tio, kion via kliento nomas la interfacon):
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 ACCEPTLa reguloj FORWARD gravas sur gastigantoj, kies plusenda politiko estas DROP. Docker enmetas proprajn ĉenojn, do testu per pako anstataŭ per legado de iptables -S: de la ujo, ip route get 10.8.0.20 devus nomi la pontan pordegon, kaj nc -vz 10.8.0.20 443 devus konekti aŭ tempolimi ĉe la tunelo anstataŭ ĉe la solvilo.
Sen MASQUERADE la samtavolano bezonas revenan itineron al 172.17.0.0/16, kiun plej multaj foraj VPN-oj ne puŝos. Ĉi tie ankaŭ politika kliento rompas la planon: se ĝi kaptas nur trafikon de specifaj UID-oj aŭ cgroups, viaj plusendaj reguloj neniam vidas la pakon interne de la tunelo, kaj la riparo apartenas al la enkursiga politiko de la kliento, ne al iptables. Mane aldonitaj reguloj malaperas ĉe restartigo, do metu ilin en systemd-unuon aŭ netfilter-persistent-tabelon kaj retestu post restartigo, ĉar tunelo, kiu leviĝas malfrue, povas forbalai ilin.
Metu la tunelon interne de la ujo, kiam izoliteco estas la celo
Se unu ujo devas eliri tra specifa nodo, ruligu la klienton en tiu ujo. Ĝi bezonas --cap-add NET_ADMIN kaj --device /dev/net/tun, kaj tiam ĝi posedas sian propran tun0, itinerojn kaj fajroŝirmilon. Se aliaj ujoj pasas tra ĝi, ĝi ankaŭ bezonas plusendadon kaj MASQUERADE-regulon interne de la ujo, kaj tiuj samtavolanoj bezonas eksplicitan itineron aŭ prokuron montrantan al ĝi; la defaŭlta ponto de Docker ne aldonas tiun itineron por vi.
Gastiga retado, docker run --network host, estas la malmultekosta versio: la ujo aliĝas al la nomspaco de la gastiganto kaj vidas la tunelajn itinerojn rekte. Ĝi ankaŭ forĵetas retan izolitecon, invitas porthompuŝiĝojn kaj praktike estas Linux-opcio. Publikigita pordo ne estas anstataŭaĵo. -p 8080:80 igas servon atingebla de la gastiganto; ĝi ne igas internajn 10.x-adresojn atingeblaj de interne de la ujo, kaj konfuzi la du estas la maniero, kiel enkursiga problemo fariĝas elmetita datumbaza pordo.
Distingi nommalsukceson de interkovra subreto
La defaŭlta ponto de Docker estas 172.17.0.0/16, kaj multaj entreprenaj VPN-basenoj kuŝas ene de 172.16.0.0/12. Post kiam la tunelo posedas tiun intervalon, trafiko destinita al ujo povas esti enkursigita en la tunelon anstataŭe. Nomoj malsukcesas, la eraro aspektas kiel DNS, kaj la adresoj estas la problemo. Kontrolu la celon, ne la solvilon: ip route get 172.17.0.5 sur la gastiganto, poste komparu la pontan prefikson kun la VPN-baseno kaj kun docker network inspect bridge --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'.
La riparo estas movi unu el la intervaloj: aŭ alian defaŭltan adresbasenon por Docker en daemon.json aŭ alian basenon sur la koncentrilo. Aldoni alian nomservilon faras nenion ĉi tie, kaj same faras ssh -b: ligi la klienton al interfaco ŝanĝas la fontadreson, ne celan itineron, kiu montras en la tunelon. Rapida labordivido: nomo, kiu solviĝas sur la gastiganto sed ne en la ujo, estas solvila problemo, dum rekta IP-konekto, kiu pendas en la ujo sed funkcias sur la gastiganto, estas itinera aŭ plusendaĉena problemo.
WSL kaj Docker Desktop ne sekvas la regulojn de Linux
En sia defaŭlta NAT-reĝimo, WSL sidas malantaŭ sia propra virtuala adaptilo kaj ne ricevas la internajn itinerojn aŭ DNS-sufiksojn de la Windows-VPN, kaj tial la retumilo funkcias kaj ping interne de la distribuo ne. Spegula retado, disponebla en lastatempaj Windows 11-konstruoj, anstataŭe kunhavas la gastigantajn interfacojn, sed ĝi devas esti ŝaltita en .wslconfig kaj la distribuo restartigita per wsl --shutdown. Konfirmu la aktivan reĝimon per wslinfo --networking-mode antaŭ ol apliki riparon, ĉar la NAT-respondo malĝustas por spegula reĝimo kaj inverse.
Docker Desktop aldonas alian tavolon. Linux-ujoj sur Windows sidas malantaŭ NAT-implementaĵo historie nomata vpnkit, kaj ilia vojo diferencas de tiu de indiĝena Linux-gastiganto. Windows-ujoj konektiĝas per virtuala Hyper-V-komutilo, kaj entreprena kliento povas bloki trafikon de tiu komutilo, do Linux-ujoj sur la sama maŝino povas atingi la reton, dum Windows-ujoj havas neniun. Ekstera komutilo ligita al la fizika adaptilo estas la kutima solvo, kaj ĝi ŝanĝas la retan identecon de la ujo laŭ manieroj, kiujn politiko eble ne permesas.
Antaŭ ol skribi alian regulon, trairu la kvar tavolojn laŭ ordo kaj haltu, kie unu el ili malĝustas:
- Interne de la ujo: ĉu
ip routeatingas la privatan prefikson, kaj ĉu/etc/resolv.confnomas supravojon, kiu solvas ĝin? - Sur la gastiganto: ĉu plusendado estas ŝaltita, ĉu NAT ligiĝas al la tunela interfaco, kaj ĉu la plusenda ĉeno akceptas ponton al tunelo?
- Ĉe la samtavolano: ĉu ĝi konas revenan vojon, aŭ ĉu vi fidas je NAT por kaŝi la ujan subreton?
- Sur la platformo: ĉu WSL estas en NAT aŭ spegula reĝimo, kaj ĉu la ujo estas Linux aŭ Windows?
Relanĉu ĉiun teston en freŝa ujo aŭ ŝelo. Longdaŭra procezo kun kaŝmemorita respondo aŭ establita konekto daŭre malsukcesos post kiam la agordo estas ĝusta, kaj tiu malsukceso aspektas ĝuste kiel riparo, kiu ne funkciis.