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

Три решения в фиксированном порядке

Исходящий пакет принимает три отдельных решения. Во-первых, правило политики определяет, какая таблица маршрутизации применяется. Во-вторых, маршрут внутри этой таблицы определяет следующий хоп и исходящий интерфейс. В-третьих, хуки netfilter решают, выживет ли пакет, будет ли изменён или перенаправлен.

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

StageSelectorWhat it cannot decide
Policy ruleuid range, mark, incoming interfaceWhich route exists inside the table
Route lookupDestination prefix, longest matchWhether the packet is allowed out
Netfilter hookChain position, match conditionsWhich table was selected

Метки — это упакованное поле, а не ваша собственная этикетка

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

Поэтому на Android опасно записывать целиком значение метки командой iptables -j MARK --set-mark. Она не добавляет тег, а заменяет выбор сети, который система уже сделала. Пакет после этого соответствует другим правилам, и это может выглядеть так, будто VPN заработал, или так, будто постороннее приложение потеряло связь, в зависимости от того, какие биты были перезаписаны.

Если метки всё же нужно затронуть, сначала прочитайте текущее значение и используйте маску, чтобы изменялись только те биты, которые вы понимаете:

ip rule show
ip route show table all | head -40
ip route get 10.20.4.11

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

Кому принадлежат правила и таблицы

Сетевой сервис Android, netd, создаёт правила и таблицы для каждой сети. AOSP RouteController — это место, где эти правила собираются для VPN, физических сетей и диапазонов uid, и его жизненный цикл привязан к сетевым событиям, а не к файлу конфигурации.

Отсюда следуют два вывода. Во-первых, приоритеты и номера таблиц, которые вы находите на одном устройстве, — это внутренние детали сборки, а не интерфейс: одинаково выглядящие номера на другой версии Android могут означать совсем другое. Во-вторых, состояние перестраивается при смене сетей, поэтому правило, вставленное сегодня из root-оболочки, может исчезнуть после следующего перехода Wi-Fi.

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

У вопросов о порядке хуков нет универсального ответа

Вопрос, работает ли iptables до VPN-маршрутизации, не имеет ответа без указания пути пакета. Локально сгенерированный пакет проходит через хук output, где изменение метки запускает проверку повторной маршрутизации — это второй поиск, а не ретроактивная правка первого. Пакет, пришедший от клиента через tethering, проходит по пути prerouting и вместо этого пересылается дальше, и цепочки, которые его видят, другие.

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

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

Диагностируйте внутри системы или оставьте её в покое

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

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

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

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