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

Почему исключение оставляет сеть открытой

VpnService.Builder принимает либо список разрешений, либо список запретов, но никогда оба. Только пакеты из списка разрешений идут через туннель. Список запретов переворачивает это: каждый пакет, кроме перечисленных, использует туннель, а перечисленные сохраняют физический путь. Пакет, не указанный в списке разрешений, тоже оказывается вне туннеля, поэтому исключение — обычное состояние для большинства приложений в этом режиме.

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

Случай Play Store — обычный намеренный пример. Исключение пакета магазина позволяет загрузкам использовать базовое соединение, когда выход VPN мешает передаче, и показывает, что исключение означает обход, а не блокировку.

Один профиль, один список

Конструктор выбрасывает исключение, если используются оба вызова, поэтому профиль перед вами — либо список разрешений, либо список запретов. Этот единственный факт определяет, как читать каждое последующее наблюдение. Проверьте код или управляемую конфигурацию до таблицы маршрутизации, потому что список определяет смысл остального вывода. Гибридный профиль — не то состояние, которое можно наблюдать.

Различие также предсказывает, что сделает недавно установленное приложение. В списке разрешений оно остаётся снаружи, пока кто-то не добавит его, а в списке запретов по умолчанию присоединяется к туннелю.

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

Следуйте правилу UID до таблицы туннеля

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

Вывод правил — это карта. Каждая строка называет таблицу поиска, и эта таблица хранит маршрут по умолчанию, который решает, попадают ли подходящие пакеты в туннель.

adb shell ip rule show
adb shell ip route show table all
adb shell cmd package list packages -U | grep <package>

Сначала выполните третью команду, чтобы получить UID, затем найдите правило, диапазон которого его содержит. Это правило указывает на номер таблицы, и ip route show table <n> с этим номером показывает, существует ли маршрут по умолчанию через устройство tun. Если в таблице нет маршрута по умолчанию, приложение выбрано, но пути у него нет, а это уже другая неисправность.

Эти команды требуют отлаживаемой сборки или устройства, где adb shell может читать состояние сети. На производственном телефоне менеджер пакетов всё ещё отвечает, но проверка маршрутизации может быть отклонена, поэтому запишите то, что можете, а остальное считайте неподтверждённым.

Маршрут требует префикс, а не приложение

Builder.addRoute требует префиксы назначения для туннеля. Профиль, который добавляет только 10.0.0.0/8 отправляет этот префикс через туннель и оставляет каждое другое назначение на физическом пути. Это обычное раздельное туннелирование, и оно не зависит от того, какие приложения выбрали правила.

Конфигурация, отправленная сервером, отражает ту же модель. Отдельные отправки маршрутов добавляют префиксы, а директива redirect-gateway заменяет маршрут по умолчанию и захватывает всё для приложений, которые покрывает туннель. Удаление этой директивы может сжать работающий туннель до одной подсети без каких-либо изменений на устройстве.

Отправленный маршрут с необычным шлюзом или метрическим уточнителем тоже может не установиться. Предпочитайте простую форму префикса и оставьте серверу пересылку и NAT.

Прочитайте пересечение, прежде чем менять настройку

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

VPN для каждого приложения может также оставить связанное приложение без связи. Когда on-demand выключен, а туннель не работает, приложение остаётся привязанным к VPN для отдельного приложения и не имеет запасного пути, что выглядит как сломанное приложение, а не как состояние политики. Включение on-demand или удаление связи через управление меняет это.

LayerWhat it selectsWhere to lookTypical mismatch
Package listProcessesBuilder calls or managed configurationApp excluded but expected to be blocked
UID policy ruleWhich table a UID usesip rule showTunnel icon on, app still on Wi-Fi
Routing tableDestinations for matched trafficip route show table <n>Covered app reaches only one subnet
Server pushPrefixes offered to the clientServer route configurationTunnel shrinks after a server edit

Диагностируйте по одной оси за раз. Сначала подтвердите разрешение или запрет, вторым делом прочитайте установленные правила UID и таблицы, а последним проверьте второе приложение на том же назначении. Второе приложение разделяет выбор процесса и выбор назначения в одном запросе.

Запишите результат как приложение, назначение и номер таблицы. Именно эту тройку должно сохранить следующее изменение.

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