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

Двумя вопросами владеют две подсистемы

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

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

Что на самом деле меняет исключение по приложению

Конструктор VpnService может назвать пакеты, остающиеся вне туннеля, с помощью addDisallowedApplication, или назвать единственные разрешённые внутри пакеты с помощью addAllowedApplication. Эти приложения тогда открывают сокеты в нижележащей сети, а VPN продолжает владеть маршрутом по умолчанию для всего остального.

Область действия точна: собственные сокеты пакета, на этом устройстве, пока туннель поднят. Она ничего не говорит о пересылаемом трафике, ничего о втором устройстве и ничего о пакетах, которые система отправляет от имени тетеринга.

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

Как пересылаемый пакет выглядит для телефона

Пакет клиента приходит на интерфейс хотспота с частным адресом источника, назначенным телефоном, скажем 192.168.43.20, и публичным назначением. Чтобы переслать его, телефону нужен маршрут к вышестоящему каналу и правило трансляции, чтобы ответы нашли обратный путь, ведь частный адрес клиента в сотовой сети ничего не значит.

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

Какая политика действительно нужна исключению для хотспота

Прежде чем трогать правило, запишите решение как источник, назначение и предполагаемый путь. Минимальная форма для одного одобренного назначения выглядит так:

SourceDestinationIntended path
One authorized hotspot clientOne approved public service addressOrdinary cellular uplink
The same clientAll other covered destinationsShared VPN
The phone's own appsTheir existing destinationsUnchanged phone policy

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

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

Один перехваченный адрес — не назначение

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

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

Проверьте со стороны нижележащего сегмента

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

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

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