Шесть проверок, выполненных по порядку, решают, может ли виртуальная машина быть VPN-шлюзом для своего собственного хоста. Гипервизор ничего этого не делает за вас: туннель принадлежит гостю, маршрут принадлежит хосту, а сеть между ними — обычная маршрутизация. Я держу этот список потому, что пропуск одного шага всегда даёт один и тот же симптом, тишину, когда хост весело пингует гостя и не достигает ничего внутреннего.

Начните с причины. Либо корпоративный клиент устанавливается только внутри гостя, либо политика держит его там, а вам всё равно нужен внутренний build-сервер с хоста. Если хосту разрешён собственный клиент, сделайте так: один туннель на хосте всегда лучше двух сетей плюс NAT.

Проверка 1: хосту нужна связь, которой он может назначить адрес

У хоста должен быть интерфейс в том же префиксе, что и второй адаптер гостя. Host-only в VirtualBox, host-only или пользовательский VMnet в VMware Workstation, внутренний мост или устройство tap в QEMU/KVM и коммутатор Internal в 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/ плюс набор правил брандмауэра, который перезагружается в госте. Сделайте snapshot гостя, как только конфигурация подтвердится, до прихода следующего обновления корпоративного клиента.

Сети host-only перенумеровываются, когда гипервизор заново создаёт свои адаптеры, и это тихо обнуляет каждый маршрут и правило NAT, построенные на 192.168.56.0/24. После обновления повторите первые три проверки по порядку; это занимает минуту и ловит случай, когда у хоста ещё есть его маршрут, а гость переехал в новую подсеть.

IPv6 требует отдельного прохода. Правила ip6tables, записи AAAA и второе семейство маршрутов хоста не следуют за настройкой IPv4, а корпоративный сервис, доступный по IPv6, будет выглядеть навсегда сломанным, пока IPv4 работает.

Пройдено или нет, по порядку: хост может пинговать адрес гостя в сети host-only; гость пересылает и делает MASQUERADE в сторону туннеля; ip route get возвращает гостя как шлюз для внутреннего префикса; корпоративные имена разрешаются через ограниченный резолвер; traceroute показывает гостя первым; и те же шесть ответов переживают перезагрузку.

Похожие статьи