Две конфигурации Windows выглядят в «Параметрах» одинаково и ведут себя совершенно по-разному. Одна — скопированный профиль VPN с триггером приложения, поэтому запуск одного исполняемого файла поднимает туннель. Другая — профиль с раздельным туннелированием, чей список маршрутов случайно покрывает то, с чем общается это приложение. Первая отвечает на вопрос, когда туннель существует. Вторая отвечает, какие пакеты в него входят, и только вторая оставляет остальную машину на физическом канале, пока приложение остаётся подключённым.

Триггер — правило жизненного цикла, а не правило маршрутизации

Add-VpnConnectionTriggerApplication связывает путь к исполняемому файлу с именем профиля. Когда этот процесс запускается, диспетчер подключений удалённого доступа набирает профиль, и когда условие триггера заканчивается, соединение может упасть. Ничто в этом обмене не проверяет сокеты. Командлету нужна повышенная оболочка, полный путь к бинарнику и -Force когда вы заменяете существующую запись. Убедитесь, что связь сохранилась, с помощью Get-VpnConnectionTrigger вместо того чтобы доверять приглашению; справочник Microsoft по Add-VpnConnectionTriggerApplication перечисляет параметры и примеры.

Две границы объясняют большинство сообщений «триггер ничего не делает». Триггеры строятся вокруг профилей для всех пользователей, поэтому область профиля — первое, что нужно уладить, а путь приложения должен совпадать с реально запускаемым бинарником, а не с ярлыком или загрузчиком, создающим второй процесс. Вторая граница намеренная: в сети, которую Windows классифицирует как доверенную, триггер остаётся бездействующим, потому что профиль рассчитан на работу вне офиса.

Add-VpnConnectionTriggerApplication -Name "APP_VPN" -ApplicationID "C:\Program Files\Vendor\app.exe" -Force
Get-VpnConnectionTrigger -Name "APP_VPN" | Format-List *
Get-VpnConnection -Name "APP_VPN" | Format-List Name,ConnectionStatus,SplitTunneling,AllUserConnection

Раздельное туннелирование решает, что пересекает туннель

Когда раздельное туннелирование выключено, Windows устанавливает на интерфейс VPN классовый маршрут по умолчанию с низкой метрикой. Ему следует каждый сокет, включая браузер и службу обновлений, поэтому триггер в такой конфигурации двигает всю машину, пока профиль подключён. Триггер по-прежнему лишь правило жизненного цикла; радиус поражения пришёл от маршрута.

Когда раздельное туннелирование включено, профиль несёт только префиксы, которые продвигает шлюз или которые вы добавляете на интерфейс VPN. Всё остальное продолжает использовать физический маршрут по умолчанию. Это та схема, которую обычно имеют в виду под «одно приложение через отдельный выход», и она от начала до конца является решением о маршрутизации.

Set-VpnConnection -Name "APP_VPN" -SplitTunneling $true
Get-VpnConnection -Name "APP_VPN" | Select-Object SplitTunneling
Get-NetRoute -InterfaceAlias "APP_VPN" | Sort-Object DestinationPrefix

Где маршрутизированное разделение перестаёт изолировать приложение

Обычный сбой — назначение, которое так и не появляется в списке маршрутов туннеля. Приложение, которое входит по одному адресу, а затем стримит с CDN или разрешает десяток сменяющихся конечных точек, часть соединений положит на интерфейс VPN, а остальные — на Wi-Fi. IPv6 — отдельная таблица, поэтому профиль, продвигающий только префиксы IPv4, может выглядеть правильным, пока трафик приложения по IPv6 остаётся локальным.

Два меньших эффекта значат не меньше. Побеждает самое длинное совпадение префикса, поэтому более конкретный on-link маршрут, /32, продвинутый для хоста управления, или подсеть второго адаптера могут обыграть туннель ровно для нужного вам адреса. Разрешение имён тоже происходит до маршрутизации: если DNS-серверы профиля или правило NRPT не покрывают имя, приложение может разрешить его через физический адаптер и затем набрать адрес, который никогда не был внутри туннелированных префиксов.

Три формы и что каждая даёт

Таблица — та часть, которую я бы приклеил на стену, потому что решение о радиусе поражения, а не о функциях. Если назначения приложения — стабильные префиксы, которые можно перечислить, маршрутизированное разделение даёт изоляцию с наименьшим следом. Если нет, профиль с маршрутом по умолчанию за виртуальной машиной или вторым устройством сохраняет разделение честным ценой перемещения более одного процесса.

ShapeWhat starts the tunnelWhat enters itPick it when
Trigger plus routed splitProcess startOnly pushed or added prefixesThe app's endpoints are stable prefixes and the host should stay direct
Trigger plus default routeProcess startEverything, machine-wideYou need one exit for all traffic and accept the wider scope
Separate VM or deviceGuest boot or loginEverything inside that guestThe app's destinations rotate, or the host must keep its own public address

Чего ни один из этих вариантов не даёт — привязки на уровне сокета на хосте. У классического клиента Windows VPN нет правила, что этот процесс обязан использовать тот адаптер; триггеры и фильтры маршрутов живут в разных слоях, а слой, выбирающий интерфейс, — это таблица маршрутизации. Если руководство обещает принуждение по приложениям только из скопированного профиля, спросите, какой маршрут или какой фильтр делает работу.

Проверьте пару за один проход

Проверяйте жизненный цикл и маршрутизацию по отдельности, в таком порядке. Закройте приложение, убедитесь, что профиль сообщает Disconnected, затем запустите приложение и проверьте, изменилось ли состояние. Только когда туннель поднят, стоит спрашивать, куда идёт конкретное назначение, и использовать нужно адрес, который приложение действительно набирает, а не догадку.

$app = Get-Process app | Select-Object -First 1
Get-VpnConnection -Name "APP_VPN" | Select-Object ConnectionStatus
Get-NetTCPConnection -OwningProcess $app.Id -State Established | Select-Object RemoteAddress,RemotePort
Find-NetRoute -RemoteIPAddress 203.0.113.10

Find-NetRoute называет интерфейс и следующий переход, который понёс бы это назначение. Физический псевдоним там означает, что туннель поднят и для этого потока неважен: проверьте продвинутые префиксы, затем более конкретные маршруты, затем IPv6. Если состояние вообще не меняется, триггер не сработал, и путь к исполняемому файлу, область профиля и операционный журнал клиента VPN — три места, куда смотреть.

Уберите всё аккуратно, чтобы следующий тест был честным

Удаляйте в обратном порядке сборки: сначала триггер приложения, затем профиль. Удаление профиля при оставшемся триггере оставляет висящую связь, которая запутывает следующую попытку, и Remove-VpnConnection -Force не всегда очищает запись телефонной книги, созданную вне командлетов.

Записи для отдельных пользователей лежат в rasphone.pbk пользователя в профиле Roaming; записи для всех пользователей лежат в ProgramData. Проверьте хранилище, соответствующее области профиля, снова подключите сохранённый профиль и убедитесь, что его маршруты и DNS ведут себя как раньше, чтобы более поздний тест измерял внесённое изменение, а не оставшееся состояние.

  • Туннель поднимается при запуске процесса, а не при входе в систему.
  • На интерфейсе VPN появляются только предназначенные префиксы.
  • Настоящий удалённый адрес приложения разрешается в псевдоним VPN.
  • После удаления профиля не остаётся висящего триггера.

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