Маршрут, доданий до таблиці 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, яку ви підтримуєте, і підтримуйте її життєвий цикл через компонент, якому вона належить. Очищення ланцюжків платформи або вставлення правила з високим пріоритетом перетворює діагностику на другого менеджера мережі, і телефон поводитиметься відповідно.

Схожі статті