ഹോസ്റ്റ് VPN അവഗണിക്കുന്ന Docker, WSL ട്രാഫിക് ശരിയാക്കുക
കണ്ടെയ്നറുകളും WSL-ഉം സ്വന്തം റൂട്ടുകൾ, റിസോൾവർ, ഫോർവേഡ് പാത എന്നിവ സൂക്ഷിക്കുന്നു, അതിനാൽ പ്രവർത്തിക്കുന്ന ഹോസ്റ്റ് ടണൽ അവയെ പഴയ DNS അല്ലെങ്കിൽ പുറത്തുകടക്കാനാവാത്ത അവസ്ഥയിൽ വിടുന്നു. ഓരോ പാളിയും ശരിയാക്കുക.
ഈ വസന്തത്തിൽ ഒരു രാവിലെയുടെ ഭൂരിഭാഗവും ഒരു ആന്തരിക നാമം പോലും റിസോൾവ് ചെയ്യാനാകാത്ത ഒരു കണ്ടെയ്നറിനെ പിന്തുടർന്ന് ഞാൻ ചെലവഴിച്ചു, അതേസമയം അടുത്തുള്ള ബ്രൗസർ ഒരു പരാതിയുമില്ലാതെ വിക്കി തുറക്കുകയായിരുന്നു. ടണൽ ഉയർന്നിരുന്നു, ബ്രൗസർ അത് തെളിയിച്ചു, എന്നാൽ കണ്ടെയ്നർ വേറെ റൂട്ട് പട്ടികയും വേറെ റിസോൾവറും ഉള്ള മറ്റൊരു നെറ്റ്വർക്ക് നാമസ്ഥലത്തായിരുന്നു. തുടർന്ന് വരുന്നത് ഞാൻ ഇപ്പോൾ പരിശോധിക്കുന്ന ക്രമമാണ്: ആദ്യം റൂട്ട് പട്ടികകൾ, രണ്ടാമത് നാമപരിഹാരം, മൂന്നാമത് ഫോർവേഡിംഗ്, അവസാനം ഹോസ്റ്റ് പ്ലാറ്റ്ഫോം. ഇതിനകം പരാജയപ്പെടുന്ന ആദ്യ ഘട്ടത്തിൽ നിർത്തുക, കാരണം സ്റ്റാക്കിൽ താഴെ നിയമങ്ങൾ ചേർക്കുന്നത് അതിർത്തി നീക്കുന്നതിനുപകരം മറയ്ക്കുന്നു.
ഒരു നിയമം മാറ്റുന്നതിന് മുമ്പ് മൂന്ന് റൂട്ട് പട്ടികകളും താരതമ്യം ചെയ്യുക
Docker-ന്റെ സ്ഥിരസ്ഥിതി ബ്രിഡ്ജിലുള്ള കണ്ടെയ്നറിന് docker0 ഗേറ്റ്വേയിലേക്ക് ഒരു സ്ഥിരസ്ഥിതി റൂട്ട് മാത്രമുണ്ട്, tun0 നിലവിലുണ്ടെന്ന് അതിന് അറിയില്ല. ഹോസ്റ്റിന് tun0, VPN തള്ളിയ റൂട്ടുകൾ, ഒരുപക്ഷേ നിങ്ങൾ പ്രതീക്ഷിക്കുന്നതിൽ നിന്ന് വ്യത്യസ്ത ഇന്റർഫേസിലൂടെ പരിശോധനാ ട്രാഫിക് അയക്കുന്ന ഒരു പോളിസി നിയമവും ഉണ്ടാകാം. WSL തന്റെ വെർച്വൽ അഡാപ്റ്ററിന് പിന്നിൽ മൂന്നാമത്തെ പട്ടിക ചേർക്കുന്നു. ഏതെങ്കിലും എഡിറ്റ് ചെയ്യുന്നതിന് മുമ്പ് മൂന്നും പ്രിന്റ് ചെയ്യുക.
| 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 |
കണ്ടെയ്നറിന്റെ ഏക റൂട്ട് ബ്രിഡ്ജ് ആണെങ്കിൽ, അതിന്റെ നാമസ്ഥലത്ത് tun0 ഒരിക്കലും പ്രത്യക്ഷപ്പെടുന്നില്ലെങ്കിൽ, താഴെയുള്ള ഒന്നും സഹായിക്കില്ല: ഒരു നെയിംസർവർ മാറ്റവും റൂട്ട് സൃഷ്ടിക്കുന്നില്ല, ഒരു റൂട്ടും പിയർ സ്വീകരിക്കുന്ന ടണൽ ഐഡന്റിറ്റി സൃഷ്ടിക്കുന്നില്ല. ക്രമം പ്രധാനമാണ്, കാരണം ഷെല്ലിനുള്ളിൽ നിന്ന് DNS പരാജയവും റൂട്ട് പരാജയവും ഒരുപോലെ തോന്നുന്നു.
റിസോൾവറിനെ പൊതുവായ ഒന്നിലേക്കല്ല, ടണലിലേക്ക് വിരൽ ചൂണ്ടിക്കുക
ഹോസ്റ്റിൽ, resolvectl status ഓരോ ലിങ്കിനും DNS സർവറുകൾ ലിസ്റ്റ് ചെയ്യുന്നു, കൂടാതെ readlink -f /etc/resolv.conf ഫയൽ systemd സ്റ്റബ് ആണോ, NetworkManager ഫയലാണോ, അതല്ലെങ്കിൽ ഒരു വെണ്ടർ ക്ലയന്റ് മാറ്റിയെഴുതിയതാണോ എന്ന് പറയുന്നു. ഉപയോക്താവ് നിർവചിച്ച നെറ്റ്വർക്കിലെ കണ്ടെയ്നറിനുള്ളിൽ, /etc/resolv.conf പേരു നൽകുന്നു 127.0.0.11, Docker-ന്റെ ഉൾച്ചേർത്ത റിസോൾവറിന്, അത് ഡീമൺ കോൺഫിഗർ ചെയ്ത upstream-ലേക്ക് ഫോർവേഡ് ചെയ്യുന്നു. എന്നാൽ സ്ഥിരസ്ഥിതി ബ്രിഡ്ജിലെ കണ്ടെയ്നർ സൃഷ്ടിക്കപ്പെട്ടപ്പോൾ ഹോസ്റ്റ് ഫയലിന്റെ ഒരു പകർപ്പ് സ്വീകരിച്ചു, അത് സൂക്ഷിക്കുന്നു.
ആ പകർപ്പാണ്, കണ്ടെയ്നർ ആരംഭിച്ചതിന് ശേഷം ഉയരുന്ന ടണൽ കണ്ടെയ്നറിനെ പഴയ upstream-നോട് ചോദിക്കാൻ വിടുന്നതിന്റെ കാരണം. ഒന്നുകിൽ VPN റിസോൾവർ വ്യക്തമായി ഇതിലൂടെ കൈമാറുക docker run --dns 10.8.0.53, അല്ലെങ്കിൽ "dns": ["10.8.0.53"] എന്നതിൽ /etc/docker/daemon.json സജ്ജീകരിച്ച് ഡീമൺ പുനരാരംഭിക്കുക, അല്ലെങ്കിൽ ടണൽ ഉയർന്നതിന് ശേഷം കണ്ടെയ്നർ വീണ്ടും സൃഷ്ടിക്കുക. വീണ്ടും സൃഷ്ടിക്കുന്നത് സാധാരണയായി ഒരു മണിക്കൂർ മുമ്പ് ശരിയായിരുന്ന ഒരു റിസോൾവർ ഡീബഗ് ചെയ്യുന്നതിനേക്കാൾ വിലകുറഞ്ഞതാണ്.
ഒരു പൊതു റിസോൾവർ ഉപയോഗിക്കുന്നത് ലക്ഷണം നിലനിർത്തുന്ന അറ്റകുറ്റപ്പണിയാണ്. അത് ഇന്റർനെറ്റ് റിസോൾവ് ചെയ്യുന്നു, എന്നാൽ ഓരോ സ്വകാര്യ മേഖലയിലും പരാജയപ്പെടുന്നു, കൂടാതെ ടണൽ നിലനിൽക്കുന്നതിന്റെ കാരണമായ ഫിൽട്ടറിംഗ് നിശബ്ദമായി ഒഴിവാക്കാനും കഴിയും. പ്രവർത്തിക്കുന്ന കണ്ടെയ്നറിന്റെ /etc/resolv.conf ഉള്ളിൽ എഴുതാൻ ശ്രമിച്ചാൽ, പ്രതീക്ഷിക്കുക Device or resource busy: Docker ആ ഫയൽ bind-mount ചെയ്യുന്നു, അതിനാൽ എഡിറ്റിന് ആദ്യം അൺമൗണ്ട് വേണം. --dns സൃഷ്ടിക്കുമ്പോൾ സജ്ജീകരിക്കുന്നതാണ് പുനരാരംഭത്തെ അതിജീവിക്കുന്ന ക്രമം.
കണ്ടെയ്നറുകൾ ടണൽ കടം വാങ്ങുമ്പോൾ ഫോർവേഡ് ചെയ്ത് വിവർത്തനം ചെയ്യുക
സ്ഥിരസ്ഥിതി ബ്രിഡ്ജിനൊപ്പം, ഹോസ്റ്റ് docker0-നും tun0-നും ഇടയിലുള്ള റൂട്ടറാണ്, സ്ഥിരസ്ഥിതിയായി അത് രണ്ടു ജോലികളും ചെയ്യുന്നില്ല. ഫോർവേഡിംഗ് ഓണാക്കി സ്രോതസ്സ് വിലാസം വിവർത്തനം ചെയ്യുക, അതുവഴി പിയർ തിരികെ റൂട്ട് ഇല്ലാത്ത ഒരു വിലാസത്തിനുപകരം ഹോസ്റ്റിന്റെ ടണൽ വിലാസം കാണും (tun0-നെ നിങ്ങളുടെ ക്ലയന്റ് ഇന്റർഫേസിന് നൽകുന്ന പേര് കൊണ്ട് മാറ്റുക):
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 ACCEPTFORWARD നിയമങ്ങൾ ഫോർവേഡ് പോളിസി DROP ആയ ഹോസ്റ്റുകളിൽ പ്രധാനമാണ്. Docker സ്വന്തം ചെയിനുകൾ ചേർക്കുന്നു, അതിനാൽ വായിക്കുന്നതിനുപകരം പാക്കറ്റ് കൊണ്ട് പരിശോധിക്കുക iptables -S: കണ്ടെയ്നറിൽ നിന്ന്, ip route get 10.8.0.20 ബ്രിഡ്ജ് ഗേറ്റ്വേയെ പേരു പറയണം, കൂടാതെ nc -vz 10.8.0.20 443 റിസോൾവറിലല്ല, ടണലിൽ ബന്ധിപ്പിക്കുകയോ സമയം കഴിയുകയോ വേണം.
MASQUERADE ഇല്ലാതെ പിയറിന് 172.17.0.0/16-ലേക്ക് തിരികെ റൂട്ട് വേണം, അത് മിക്ക റിമോട്ട് ആക്സസ് VPN-കളും തള്ളില്ല. ഇവിടെയാണ് പോളിസി അടിസ്ഥാനമാക്കിയ ക്ലയന്റ് പദ്ധതി തകർക്കുന്നതും: അത് നിർദ്ദിഷ്ട UID-കളുടെയോ cgroups-ന്റെയോ ട്രാഫിക് മാത്രം പിടിക്കുന്നുവെങ്കിൽ, നിങ്ങളുടെ ഫോർവേഡ് നിയമങ്ങൾ ടണലിനുള്ളിലെ പാക്കറ്റ് ഒരിക്കലും കാണുന്നില്ല, തിരുത്ത് iptables-ലല്ല, ക്ലയന്റിന്റെ റൂട്ടിംഗ് പോളിസിയിലാണ്. കൈകൊണ്ട് ചേർത്ത നിയമങ്ങൾ റീബൂട്ടിൽ അപ്രത്യക്ഷമാകുന്നു, അതിനാൽ അവ systemd യൂണിറ്റിലോ netfilter-persistent പട്ടികയിലോ ഇട്ട് റീബൂട്ടിന് ശേഷം വീണ്ടും പരിശോധിക്കുക, കാരണം വൈകി ഉയരുന്ന ടണൽ അവയെ കഴുകിക്കളയാം.
ലക്ഷ്യം ഒറ്റപ്പെടുത്തലാണെങ്കിൽ ടണൽ കണ്ടെയ്നറിനുള്ളിൽ വയ്ക്കുക
ഒരു കണ്ടെയ്നർ ഒരു നിർദ്ദിഷ്ട നോഡിലൂടെ പുറത്തുപോകണമെങ്കിൽ, ആ കണ്ടെയ്നറിൽ ക്ലയന്റ് പ്രവർത്തിപ്പിക്കുക. അതിന് --cap-add NET_ADMIN ഉം --device /dev/net/tun ഉം വേണം, അപ്പോൾ അതിന് സ്വന്തം tun0, റൂട്ടുകൾ, ഫയർവാൾ ഉണ്ടാകും. മറ്റ് കണ്ടെയ്നറുകൾ അതിലൂടെ കടന്നുപോകുന്നുവെങ്കിൽ, കണ്ടെയ്നറിനുള്ളിൽ ഫോർവേഡിംഗും MASQUERADE നിയമവും കൂടി വേണം, ആ പിയർമാർക്ക് അതിലേക്ക് ചൂണ്ടുന്ന വ്യക്തമായ റൂട്ടോ പ്രോക്സിയോ വേണം; Docker-ന്റെ സ്ഥിരസ്ഥിതി ബ്രിഡ്ജ് ആ റൂട്ട് നിങ്ങൾക്കുവേണ്ടി ചേർക്കുന്നില്ല.
ഹോസ്റ്റ് നെറ്റ്വർക്കിംഗ്, docker run --network host, വിലകുറഞ്ഞ പതിപ്പാണ്: കണ്ടെയ്നർ ഹോസ്റ്റിന്റെ നാമസ്ഥലത്ത് ചേരുന്നു, ടണൽ റൂട്ടുകൾ നേരിട്ട് കാണുന്നു. എന്നാൽ അത് നെറ്റ്വർക്ക് ഒറ്റപ്പെടുത്തൽ ഉപേക്ഷിക്കുന്നു, പോർട്ട് കൂട്ടിയിടികൾ ക്ഷണിക്കുന്നു, പ്രായോഗികമായി ഇത് Linux ഓപ്ഷനാണ്. പ്രസിദ്ധീകരിച്ച പോർട്ട് അതിന് പകരമല്ല. -p 8080:80 ഒരു സേവനത്തെ ഹോസ്റ്റിൽ നിന്ന് എത്താവുന്നതാക്കുന്നു; ആന്തരിക 10.x വിലാസങ്ങളെ കണ്ടെയ്നറിനുള്ളിൽ നിന്ന് എത്താവുന്നതാക്കുന്നില്ല, രണ്ടും കൂട്ടിക്കുഴയ്ക്കുന്നതാണ് റൂട്ടിംഗ് പ്രശ്നം തുറന്ന ഡാറ്റാബേസ് പോർട്ടാകുന്ന വഴി.
നാമ പരാജയത്തെ ഓവർലാപ്പിംഗ് സബ്നെറ്റിൽ നിന്ന് വേർതിരിക്കുക
Docker-ന്റെ സ്ഥിരസ്ഥിതി ബ്രിഡ്ജ് 172.17.0.0/16 ആണ്, കൂടാതെ ധാരാളം കോർപ്പറേറ്റ് VPN പൂളുകൾ 172.16.0.0/12-നുള്ളിൽ കിടക്കുന്നു. ടണൽ ആ പരിധി കൈവശപ്പെടുത്തിയാൽ, കണ്ടെയ്നറിന് ഉദ്ദേശിച്ച ട്രാഫിക് പകരം ടണലിലേക്ക് റൂട്ട് ചെയ്യപ്പെടാം. നാമങ്ങൾ പരാജയപ്പെടുന്നു, പിശക് DNS പോലെ തോന്നുന്നു, പ്രശ്നം വിലാസങ്ങളിലാണ്. ലക്ഷ്യം പരിശോധിക്കുക, റിസോൾവറല്ല: ip route get 172.17.0.5 ഹോസ്റ്റിൽ, തുടർന്ന് ബ്രിഡ്ജ് പ്രിഫിക്സ് VPN പൂളുമായും docker network inspect bridge --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}'-മായും താരതമ്യം ചെയ്യുക.
പരിധികളിൽ ഒന്ന് നീക്കുകയാണ് അറ്റകുറ്റപ്പണി: ഒന്നുകിൽ Docker-ന് daemon.json -ൽ വേറെ സ്ഥിരസ്ഥിതി വിലാസ പൂൾ, അല്ലെങ്കിൽ കോൺസെൻട്രേറ്ററിൽ വേറെ പൂൾ. ഇവിടെ മറ്റൊരു നെയിംസർവർ ചേർക്കുന്നത് ഒന്നും ചെയ്യുന്നില്ല, ssh -b ഉം അല്ല: ക്ലയന്റിനെ ഇന്റർഫേസിലേക്ക് ബന്ധിപ്പിക്കുന്നത് സ്രോതസ്സ് വിലാസത്തെ മാറ്റുന്നു, ടണലിലേക്ക് ചൂണ്ടുന്ന ലക്ഷ്യ റൂട്ടിനെയല്ല. വേഗത്തിലുള്ള ജോലിവിഭജനം: ഹോസ്റ്റിൽ റിസോൾവ് ചെയ്യുന്നതും കണ്ടെയ്നറിൽ ചെയ്യാത്തതുമായ നാമം റിസോൾവർ പ്രശ്നമാണ്, അതേസമയം കണ്ടെയ്നറിൽ തൂങ്ങിക്കിടക്കുന്നതും ഹോസ്റ്റിൽ പ്രവർത്തിക്കുന്നതുമായ നേരിട്ടുള്ള IP ബന്ധം റൂട്ട് അല്ലെങ്കിൽ ഫോർവേഡ്-ചെയിൻ പ്രശ്നമാണ്.
WSL-ഉം Docker Desktop-ഉം Linux നിയമങ്ങൾ പാലിക്കുന്നില്ല
സ്വന്തം സ്ഥിരസ്ഥിതി NAT മോഡിൽ, WSL തന്റെ വെർച്വൽ അഡാപ്റ്ററിന് പിന്നിലിരിക്കുന്നു, Windows VPN-ന്റെ ആന്തരിക റൂട്ടുകളോ DNS പ്രത്യയങ്ങളോ സ്വീകരിക്കുന്നില്ല, അതുകൊണ്ടാണ് ബ്രൗസർ പ്രവർത്തിക്കുന്നതും ping വിതരണത്തിനുള്ളിൽ പ്രവർത്തിക്കാത്തതും. സമീപകാല Windows 11 ബിൽഡുകളിൽ ലഭ്യമായ മിറർ നെറ്റ്വർക്കിംഗ് പകരം ഹോസ്റ്റ് ഇന്റർഫേസുകൾ പങ്കിടുന്നു, പക്ഷേ അത് .wslconfig -ൽ പ്രവർത്തനക്ഷമമാക്കി വിതരണം wsl --shutdown ഉപയോഗിച്ച് പുനരാരംഭിക്കണം. സജീവ മോഡ് wslinfo --networking-mode ഉപയോഗിച്ച് സ്ഥിരീകരിക്കുക, തിരുത്ത് പ്രയോഗിക്കുന്നതിന് മുമ്പ്, കാരണം NAT-ന്റെ ഉത്തരം മിറർ മോഡിന് തെറ്റാണ്, തിരിച്ചും.
Docker Desktop ഒരു പാളി കൂടി ചേർക്കുന്നു. Windows-ലെ Linux കണ്ടെയ്നറുകൾ ചരിത്രപരമായി vpnkit എന്ന് വിളിക്കപ്പെടുന്ന NAT നടപ്പാക്കലിന് പിന്നിലാണ്, അവയുടെ പാത നേറ്റീവ് Linux ഹോസ്റ്റിൽ നിന്ന് വ്യത്യസ്തമാണ്. Windows കണ്ടെയ്നറുകൾ Hyper-V വെർച്വൽ സ്വിച്ചിലൂടെ ബന്ധിപ്പിക്കുന്നു, ഒരു കോർപ്പറേറ്റ് ക്ലയന്റിന് ആ സ്വിച്ചിൽ നിന്നുള്ള ട്രാഫിക് തടയാം, അതിനാൽ ഒരേ മെഷീനിലെ Linux കണ്ടെയ്നറുകൾ നെറ്റ്വർക്കിൽ എത്തിയേക്കാം, എന്നാൽ Windows കണ്ടെയ്നറുകൾക്ക് ഒന്നുമില്ല. ഫിസിക്കൽ അഡാപ്റ്ററിലേക്ക് ബന്ധിച്ച ഒരു എക്സ്റ്റേണൽ സ്വിച്ചാണ് സാധാരണ പരിഹാരം, അത് കണ്ടെയ്നറിന്റെ നെറ്റ്വർക്ക് ഐഡന്റിറ്റി പോളിസി അനുവദിച്ചേക്കാത്ത രീതികളിൽ മാറ്റുന്നു.
മറ്റൊരു നിയമം എഴുതുന്നതിന് മുമ്പ്, നാല് പാളികളും ക്രമത്തിൽ സഞ്ചരിച്ച് ഏതെങ്കിലും തെറ്റായിടത്ത് നിർത്തുക:
- കണ്ടെയ്നറിനുള്ളിൽ:
ip routeസ്വകാര്യ പ്രിഫിക്സിൽ എത്തുന്നുണ്ടോ, കൂടാതെ/etc/resolv.confഅത് റിസോൾവ് ചെയ്യുന്ന ഒരു upstream-ന് പേരു നൽകുന്നുണ്ടോ? - ഹോസ്റ്റിൽ: ഫോർവേഡിംഗ് ഓണാണോ, NAT ടണൽ ഇന്റർഫേസിലേക്ക് ബന്ധിച്ചിട്ടുണ്ടോ, ഫോർവേഡ് ചെയിൻ ബ്രിഡ്ജിൽ നിന്ന് ടണലിലേക്ക് സ്വീകരിക്കുന്നുണ്ടോ?
- പിയറിൽ: അതിന് തിരികെയുള്ള പാത അറിയാമോ, അതല്ലെങ്കിൽ കണ്ടെയ്നർ സബ്നെറ്റ് മറയ്ക്കാൻ NAT-നെ ആശ്രയിക്കുന്നുണ്ടോ?
- പ്ലാറ്റ്ഫോമിൽ: WSL NAT-ലോ മിറർ മോഡിലോ, കണ്ടെയ്നർ Linux-ഓ Windows-ഓ?
ഓരോ പരിശോധനയും പുതിയ കണ്ടെയ്നറിലോ ഷെല്ലിലോ വീണ്ടും പ്രവർത്തിപ്പിക്കുക. കാഷ് ചെയ്ത ഉത്തരമോ സ്ഥാപിത ബന്ധമോ ഉള്ള ദീർഘകാല പ്രോസസ് കോൺഫിഗറേഷൻ ശരിയായതിന് ശേഷവും പരാജയപ്പെട്ടുകൊണ്ടിരിക്കും, ആ പരാജയം പ്രവർത്തിക്കാത്ത തിരുത്തിനെപ്പോലെ കൃത്യമായി തോന്നും.