Маршрутызацыя трафіку хоста праз VPN у VM: шэсць праверак
Шэсць паслядоўных праверак, каб ператварыць VM у VPN-шлюз, праз які маршрутызуецца трафік яго ўласнага хоста: рэжым адаптара, перасылка, NAT, маршруты хоста, DNS, MTU.
Шэсць праверак, выкананых па чарзе, вызначаюць, ці можа VM быць VPN-шлюзам для свайго ўласнага хоста. Гіпервізар нічога з гэтага не робіць за вас: тунель належыць госцю, маршрут належыць хосту, а сетка паміж імі — звычайная маршрутызацыя. Я трымаю гэты спіс, бо пропуск аднаго кроку заўсёды дае адзін і той жа сімптом, цішыню, калі хост спакойна пінгуе госця і не дасягае нічога ўнутранага.
Пачніце з прычыны. Або карпаратыўны кліент усталёўваецца толькі ўнутры госця, або палітыка трымае яго там, а вам усё яшчэ патрэбны ўнутраны build-сервер з хоста. Калі хосту дазволены ўласны кліент, зрабіце лепш так: адзін тунель на хосце заўсёды лепш за дзве сеткі плюс NAT.
Праверка 1: хосту патрэбна сувязь, якую ён можа адрасаваць
Хост павінен мець інтэрфейс у тым жа прэфіксе, што і другі адаптар госця. Host-only у VirtualBox, host-only або карыстальніцкі VMnet у VMware Workstation, унутраны маст або tap-прылада ў QEMU/KVM і Internal switch у Hyper-V — усе падыходзяць. Госць 192.168.56.2, хост 192.168.56.1, прэфікс 192.168.56.0/24 — гэта схема, якую я выкарыстоўваю ў лабараторыях.
Сетка QEMU у карыстальніцкім рэжыме (-netdev user, стандартны бэкенд SLIRP) і NAT у VirtualBox цалкам правальваюць гэтую праверку. Пакеты госця дасягаюць праксі-працэса на хосце, таму хост ніколі не бачыць прылады з адрасамі госця і не мае да чаго накіраваць маршрут. Default Switch у Hyper-V — тая ж гісторыя. Калі ping 192.168.56.2 з хоста не праходзіць, спыніцеся: ніякі маршрут, дададзены пазней, гэтага не выправіць.
Праверка 2: госць перасылае і транслюе
Пакеты з хоста прыходзяць з адрасам-крыніцай з host-only сеткі і ўнутраным прызначэннем, таму госць павінен іх пераслаць, а затым схаваць за сваім адрасам тунелю. На Linux-госці гэта азначае перасылку, пару правіл FORWARD accept і source NAT у бок тунелю:
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -A FORWARD -i eth1 -o tun0 -j ACCEPT
sudo iptables -A FORWARD -i tun0 -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT
sudo iptables -t nat -A POSTROUTING -s 192.168.56.0/24 -o tun0 -j MASQUERADE
Правіла MASQUERADE — гэта тая частка, якую звычайна забываюць. Карпаратыўныя маршрутызатары рэдка ведаюць, што 192.168.56.0/24 існуе; з гэтым правілам унутраныя серверы бачаць адрас тунелю госця і адказваюць на яго, а адказ знаходзіць шлях назад да госця.
Windows-госць няўклюднейшы. IPEnableRouter=1 пад SYSTEM\CurrentControlSet\Services\Tcpip\Parameters уключае перасылку без трансляцыі, таму гэта працуе толькі там, дзе карпаратыўная маршрутызацыя ўжо паказвае назад на ваш host-only прэфікс. Internet Connection Sharing транслюе, але перанумяроўвае агульны адаптар на 192.168.137.1, таму прачытайце адрас, які ён фактычна заняў, перш чым пісаць маршруты хоста.
Праверка 3: маршруты хоста называюць госця, а не тунель
Перадавайце праз госця толькі тыя прэфіксы, якія патрэбны хосту. На Linux аднаго маршруту на прэфікс дастаткова, і ён чыста адкотваецца:
sudo ip route add 10.20.0.0/16 via 192.168.56.2
ip route get 10.20.30.40
На Windows эквівалент — route add 10.20.0.0 mask 255.255.0.0 192.168.56.2. Пакуль вы тэсціруеце, пакідайце -p, каб дрэнны маршрут паміраў пры перазагрузцы, і дадайце яго, калі шлях запрацуе. Не выдаляйце маршрут па змаўчанні хоста, калі толькі ўсе праграмы хоста не павінны ісці праз тунель; калі поўны тунель сапраўды патрэбны, дадайце два маршруты /1 і пакіньце прамы маршрут да сеткі гіпервізара:
sudo ip route add 0.0.0.0/1 via 192.168.56.2
sudo ip route add 128.0.0.0/1 via 192.168.56.2
На Windows-хосце праверце таксама метрыку інтэрфейсу. Маршрут, дададзены, пакуль host-only адаптар быў адключаны, застаецца ў табліцы, але ніколі не нясе трафік, а другі адаптар з меншай метрыкай можа выйграць пошук для таго ж прэфікса.
Праверка 4: DNS ідзе за маршрутам, а не за тунелем па змаўчанні
Маршруты рухаюць пакеты; рэзалвер вырашае, якія імёны ствараюць пакеты. Абмяжуйце карпаратыўны рэзалвер карпаратыўнай зонай замест замены рэзалвера хоста і накіруйце яго на DNS-сервер, да якога новы маршрут ужо дасягае. З systemd-resolved на хосце:
resolvectl dns eth1 10.20.0.53
resolvectl domain eth1 '~corp.example.com'
На Windows запіс у табліцы палітыкі развязання імён робіць тое ж: Add-DnsClientNrptRule -Namespace ".corp.example.com" -NameServers 10.20.0.53. Калі госць запускае свой рэзалвер на host-only адрасе, выкарыстайце гэты адрас, але толькі пасля пацверджання, што ён адказвае на 192.168.56.2, а не на loopback.
Затым праверце MTU, перш чым вінаваціць DNS у павольных старонках. Інтэрфейс тунелю меншы за 1500-байтавы інтэрфейс хоста, таму хост, які адпраўляе сегменты поўнага памеру з усталяваным бітам DF, губляе іх дзесьці ўнутры госця. Класічны сімптом — працоўны ping і ўнутраная вэб-праграма, якая затынаецца пасля TLS-рукапаціску. Сцісніце MSS на шляху перасылкі ў госці:
sudo iptables -t mangle -A FORWARD -p tcp --tcp-flags SYN,RST SYN -j TCPMSS --clamp-mss-to-pmtu
Праверка 5: правярайце з абодвух бакоў
З хоста traceroute або tracert да ўнутранага адраса павінны паказваць 192.168.56.2 як першы хоп, а не фізічны шлюз. У госці назірайце, як тая ж спроба выходзіць: tcpdump -ni any host 10.20.30.40 паказвае перасланы запыт на host-only баку і трансляваны на тунелі. Запыт, які выходзіць, вяртаецца і ўсё ж пакідае хост маўклівым, паказвае на зваротны шлях.
Дзве памылкі ахопліваюць большасць такіх выпадкаў. Або тунель госця не нясе зваротнага маршруту для host-only прэфікса, бо няма правіла NAT, або маршрут хоста паказвае на адрас, якога госць ужо не мае пасля перазапуску. Перачытайце адрасы з ip -br addr і ip route get замест таго, каб давяраць нататкам з мінулай сесіі.
Праверка 6: зрабіце так, каб яно перажыло перазагрузку і абнаўленне гіпервізара
Замацуйце абодзве паловы: канфігурацыю маршрутаў netplan або NetworkManager на хосце, route add ... -p на Windows і net.ipv4.ip_forward=1 у /etc/sysctl.d/ плюс набор правіл фаеруола, які перазагружаецца ў госці. Зрабіце здымак госця, як толькі канфігурацыя пройдзе праверку, да таго як прыйдзе наступнае абнаўленне карпаратыўнага кліента.
Host-only сеткі перанумяроўваюцца, калі гіпервізар стварае свае адаптары нанова, і гэта маўкліва робіць несапраўднымі ўсе маршруты і правілы NAT, пабудаваныя на 192.168.56.0/24. Пасля абнаўлення паўтарыце першыя тры праверкі па чарзе; гэта займае хвіліну і ловіць выпадак, калі хост яшчэ мае свой маршрут, а госць перайшоў у новую падсетку.
IPv6 патрабуе асобнага праходу. Правілы ip6tables, запісы AAAA і другая сям'я маршрутаў хоста не ідуць за наладай IPv4, і карпаратыўны сэрвіс, дасяжны праз IPv6, будзе выглядаць пастаянна зламаным, пакуль IPv4 працуе.
Пройдзена ці не, па чарзе: хост можа пінгаваць host-only адрас госця; госць перасылае і робіць MASQUERADE у бок тунелю; ip route get вяртае госця як шлюз для ўнутранага прэфікса; карпаратыўныя імёны развязаюцца праз абмежаваны рэзалвер; traceroute паказвае госця першым; і тыя ж шэсць адказаў перажываюць перазагрузку.