Представьте: вы подключились к рабочему VPN – нужно зайти на корпоративный сервер или проверить доступность сервиса из другой юрисдикции. Потом, не выключая его, открыли приложение популярного маркетплейса – проверить, прибыл ли в пункт выдачи корм для почтовых воробьев. В этот момент приложение тихо просканировало localhost, нашло SOCKS5-порт вашего VPN-клиента, отправило через него запрос и узнало выходной IP вашего сервера. Завтра этот IP окажется в блэклисте. Сервер, за который вы или ваша компания платите $5 в месяц, вдруг внезапно деградировал. А вы даже не узнаете, кто вас сдал.

Эта статья о том, как я решил эту проблему. Не теоретически, а в виде работающего open-source приложения.
Anubis на GitHub – код, APK и инструкция по настройке. А ниже – как это устроено под капотом.
Предыстория
В апреле 2026 года Минцифры разослало крупнейшим российским площадкам методичку по обнаружению VPN-трафика. Компании получили конкретные инструкции: как выявлять VPN, как ограничивать доступ пользователям, и как передавать обнаруженные IP-адреса VPN-серверов в РКН для последующей блокировки.
Фактически каждое крупное российское приложение теперь потенциально содержит модуль, который:
определяет наличие VPN через
ConnectivityManagerпроверяет доступность заблокированных ресурсов
передаёт IP-адреса VPN-серверов для блокировки
Это не теория - статья Российский мессенджер MAX замечен в обращении к иностранным сервисам определения IP и серверам конкурентов описывает то, как обнаружили подобное поведение, статья “Месседжер MAX следит за пользователями VPN? Реверс инжиниринг говорит - да” показала конкретные обращения к серверам Telegram и WhatsApp для определения обхода блокировок.
Параллельно была обнаружена критическая уязвимость во всех популярных VLESS-клиентах: они поднимают локальный SOCKS5 прокси без авторизации, через который любое приложение на устройстве может узнать выходной IP VPN-сервера. Другой автор на Хабре, @Wendor, предложил решение на стороне VPN-клиента – свой клиент TeapodStream с рандомным портом и авторизацией SOCKS5. Шпион больше не может воспользоваться прокси. Но сам факт наличия VPN (tun0, маршруты) от его взгляда это не скрывает – как выяснилось в комментариях к той статье, шпион может биндиться напрямую к tun0 через SO_BINDTODEVICE и всё равно узнать выходной IP. Так что это закрывает один конкретный вектор, но не все.
На фоне всего этого на Хабре появилась статья с предложением использовать Island/Insular для изоляции приложений. В комментариях развернулась дискуссия о том, насколько это реально защищает. Позже тот же автор опубликовал продолжение – красивое серверное решение в виде трёхкаскадного VPN. Ключевой трюк: точка входа внутри РФ скрыта (трафик к ней выглядит как обычный межсервисный), а выходной узел и вовсе находится вне юрисдикции блокировок. Если шпион и сдаст выходной IP – РКН его забанит, но это не сломает схему: между российским трафиком и выходом стоит ещё один заграничный узел, и бан никакой цепочки не разрывает. Схема работает дальше как ни в чём не бывало. Подход серверный и устойчивый.
В первой версии этой статьи я описал его схему как "ротационную" – мол, выходные узлы быстро заменяются после банов. @linux-over справедливо поправил в личке: ничего заменять не нужно, схема живёт дальше как была. Этот абзац переписан.
Я решил зайти с другой стороны – со стороны клиента: вообще не дать шпиону ничего узнать, отключив его до включения VPN.
Песочница: что она реально даёт, а что нет
Идея простая: помещаем приложения в рабочий профиль Android, и они не видят VPN. Insular (форк Island) - это приложение-песочница, создающее рабочий профиль.
Как работает рабочий профиль под капотом
Рабочий профиль - это отдельный пользователь Android (например, user 10), привязанный к основному (user 0). Приложения не клонируются: APK один, но у каждого профиля своя директория данных (/data/user/0/ vs /data/user/10/). Изолированы: файлы, контакты, аккаунты, буфер обмена, хранилище ключей. Не изолирована: сеть.
Что песочница действительно скрывает
Автор статьи про Island утверждает, что Т-Банк после помещения в песочницу “перестал жаловаться на VPN”. Проверка показала, что это правда - и вот почему:
ConnectivityManager в Android фильтрует сети по userId. VPN, созданный в user 0, не виден через ConnectivityManager.getAllNetworks() из user 10 (рабочего профиля). Это framework-level фильтр в ConnectivityService - не ядерная изоляция, а программная. Но для приложений, которые проверяют VPN простейшим способом (а таких большинство), этого достаточно:
// Этот код из рабочего профиля НЕ увидит VPN основного профиля val cm = getSystemService<ConnectivityManager>() val vpnActive = cm.allNetworks.any { cm.getNetworkCapabilities(it) ?.hasTransport(NetworkCapabilities.TRANSPORT_VPN) == true } // vpnActive == false, хотя VPN включён
Что такое ConnectivityManager
ConnectivityManager - системный сервис Android для информации о сетевых подключениях. Любое приложение с разрешением ACCESS_NETWORK_STATE (есть практически у всех, не требует подтверждения) может спросить систему: "есть ли VPN?". В рамках одного профиля система ответит честно. Но между профилями - фильтрует. Это задокументированное поведение Android, не баг.
Так что песочница - не бесполезна. Она закрывает самый простой и распространённый вектор детектирования.
Что песочница НЕ скрывает
Проблема в том, что сетевой стек Android - один на всё ядро. Рабочий профиль не использует Linux network namespaces (хотя ядро их поддерживает - на этом построены Docker и LXC). Это значит, что из рабочего профиля доступны три канала утечки:
Что видит приложение из рабочего профиля |
Как проверяет |
Нужны права? |
|---|---|---|
Интерфейс |
|
Нет |
Маршрут через |
|
Нет |
SOCKS5 прокси на localhost |
Подключение к |
Нет |
Все три проверки работают без каких-либо разрешений. SOCKS5 на localhost - самая опасная: приложение в рабочем профиле может не просто обнаружить VPN, но и воспользоваться им, узнав выходной IP-адрес сервера.
Утилиты YourVPNDead и RKNHardering проверяют все каналы, а не только ConnectivityManager - поэтому они успешно детектят VPN из любого рабочего профиля: Island, Insular, Knox, Shelter, второе пространство Xiaomi.
А методичка Минцифры явно описывает проверку характерных портов прокси: SOCKS (1080, 9000, 5555), HTTP (3128, 8080), Tor (9050). Именно те проверки, от которых рабочий профиль не защищает.
Возможна ли полноценная сетевая изоляция на Android?
Может, Google просто доделает изоляцию? На настольных ОС виртуализация (VirtualBox, QEMU, Hyper-V) создаёт гостевую систему с собственным сетевым стеком. Гостевая ОС не видит VPN хоста – это настоящая изоляция. Linux-ядро, на котором построен Android, тоже так умеет – через network namespaces.
Но Android не пользуется network namespaces для профилей. VpnService, ConnectivityManager и весь сетевой фреймворк не рассчитаны на per-profile сетевую изоляцию. Чтобы песочница реально изолировала сеть, Google пришлось бы переработать сетевую подсистему. Этого нет, и в обозримом будущем не предвидится.
А что на других платформах?
**На ПК** проблема решается тривиально: помещаем приложения, которым не доверяем, в виртуальную машину (VirtualBox, QEMU). Даже если VPN на хосте работает в TUN-режиме и перехватывает весь трафик -- гостевая ОС в режиме NAT этого не видит. Трафик гостя пойдёт через VPN хоста, но гость видит только свою виртуальную сетевую карту. У него нет доступа к интерфейсам хоста (tun0, wg0 и т.д.), к его таблице маршрутизации, к списку адаптеров. Факт наличия VPN для него невидим. Это полноценная изоляция. **На iOS** ситуация хуже, чем на Android: нет даже рабочих профилей, нет per-app VPN для произвольных приложений. Единственный вариант -- второй телефон. **На Android** полноценной виртуализации нет, но есть другой механизм -- полное отключение приложения на уровне системы. Об этом ниже.
Проблема глубже: фоновая активность
Но допустим, чудо произошло и Google добавил настоящую сетевую изоляцию для профилей. Спасло бы это нас? Нет.
Android архитектурно позволяет приложениям вести активность без явного действия пользователя. BroadcastReceiver, JobScheduler, WorkManager, push-уведомления через FCM – всё это запускает код приложения в фоне. Приложение, которое вы запустили два дня назад и давно свернули, продолжает жить: получает события, обрабатывает данные, отправляет запросы.
Это не баг, а “by design”. Android построен вокруг модели, где приложения реагируют на системные события. Но эта же модель означает, что приложение в любой момент может:
проверить состояние VPN
просканировать открытые порты на localhost
отправить HTTP-запрос к произвольному серверу
передать собранную информацию
Агрессивное энергосбережение (Doze mode, App Standby, OEM-оптимизации) может замедлить эту активность, но не гарантирует её полного отсутствия. Системные приложения и приложения, которым вы разрешили работу в фоне, вообще не подпадают под ограничения. А банковские приложения, маркетплейсы, мессенджеры – чаще других просят разрешить работу в фоне, потому что иначе пользователи жалуются на задержку уведомлений.
Песочница от фоновой активности не защищает – приложение в рабочем профиле работает точно так же, как в основном. Единственный способ гарантированно закрыть все векторы утечки – сделать так, чтобы приложение не существовало в системе в момент, когда VPN активен.
Итого по песочнице
Рабочий профиль – не бесполезен, но недостаточен:
Скрывает VPN от
ConnectivityManager– работает против простых проверок (банковские приложения, Т-Банк)Не скрывает
tun0, маршруты и SOCKS5 – не работает против продвинутых проверок (методичка Минцифры, YourVPNDead)Не блокирует фоновую активность – приложение продолжает сканировать сеть, даже если вы его не открывали
Имеет встроенную заморозку отдельных приложений и целого профиля (“Pause work apps”) – но это всё ещё ручное действие
Полноценная сетевая изоляция на Android невозможна архитектурно – и ждать её от Google не приходится
Единственный гарантированный способ запретить приложению любую активность – полностью его отключить. Отключённое приложение не может проверить VPN, просканировать порты или отправить запрос – его просто не существует в системе. В Island, кстати, тоже есть кнопка «заморозить» – и замороженное приложение точно так же мертво и, следовательно, безопасно. Но в Island вы делаете это вручную. Забыли заморозить перед включением VPN – всё, данные утекли.
Нам нужно не просто отключать приложения – нам нужно делать это автоматически, по состоянию VPN. Но сначала разберёмся, как вообще отключить произвольное приложение на Android.
Заморозка вместо изоляции
Кнопка «Отключить» – она уже существует
Android уже умеет полностью отключать приложения – но прячет эту возможность. Если вы зайдёте в Настройки → Приложения и откроете какое-нибудь предустановленное системное приложение (например, Google Фото или YouTube), вы увидите кнопку “Отключить”. Нажатие на неё полностью останавливает приложение: оно больше не запускается, не работает в фоне, не получает уведомления, его иконка пропадает из лаунчера.
Это именно то, что нам нужно. Отключённое приложение не может ничего детектить - оно мертво.
Но есть подвох: для приложений, установленных пользователем (а не предустановленных), этой кнопки нет. Для них Android предлагает только “Удалить”. Это ограничение интерфейса, не системы - под капотом механизм отключения работает для любых приложений. Просто Android не даёт к нему доступ через UI.
pm disable-user: та самая кнопка, но для всех
Системная команда pm disable-user делает то же самое, что кнопка “Отключить”, но для любого приложения:
pm disable-user --user 0 com.example.app
pm - это Package Manager, встроенный в каждый Android. disable-user отключает приложение для пользователя. --user 0 - основной профиль. com.example.app - имя пакета (например, ru.sberbankmobile для Сбера).
После этой команды приложение:
не имеет процесса в системе
не может запустить Service, BroadcastReceiver, ContentProvider
не получает Intent’ы и push-уведомления
не может обратиться ни к какому API, включая ConnectivityManager
не может просканировать localhost порты и отправить HTTP-запрос
иконка пропадает из лаунчера
Это не изоляция, а анабиоз. Приложение мертво на уровне PackageManager. Обратная операция – pm enable <package> – оживляет его мгновенно. Дальше в статье я буду называть это «заморозкой» – отключение, заморозка, «приложение мертво» означают одно и то же: pm disable-user.
Проблема доступа: ADB и его ограничения
Команда pm disable-user требует повышенных привилегий - уровня shell (UID 2000). На обычном Android приложения работают в своей “песочнице” и такие команды выполнять не могут.
Стандартный способ получить shell-доступ - ADB (Android Debug Bridge). Вы подключаете телефон к компьютеру по USB, устанавливаете Android SDK и выполняете:
adb shell pm disable-user --user 0 com.example.app
Это работает, но неудобно: нужен компьютер, USB-кабель, и каждый раз вводить команды вручную. Автоматизировать заморозку при включении VPN таким способом невозможно.
Если хочется попробовать заморозку без Anubis и Shizuku
Для тех, кто хочет просто поиграться с `pm disable-user` без командной строки, есть [ADB AppControl](https://adbappcontrol.com/) -- десктопный GUI для ADB (Windows, есть портативная версия). Подключаете телефон по USB, получаете список всех приложений и отключаете/включаете в один клик. Самый дружелюбный способ познакомиться с возможностями ADB. Но ограничения те же: всё привязано к ПК, USB-кабелю и ручному действию -- автоматически по состоянию VPN замораживать нельзя.
Shizuku: ADB без компьютера
Shizuku решает эту проблему. Это приложение, которое один раз запускается с правами shell (через ADB или Wireless Debugging на Android 11+), а потом предоставляет эти права другим приложениям - прямо на телефоне, без компьютера.
После настройки Shizuku любое приложение с его разрешением может выполнять shell-команды: pm disable-user, pm enable и другие - всё, что доступно в adb shell. Какие именно команды и зачем - станет понятно дальше.
Критически важно: Shizuku - не root. Он не ломает Knox, не теряет гарантию, не вызывает проблем с банковскими приложениями и проверками SafetyNet/Play Integrity. Shell-доступ - привилегии ADB, а не суперпользователя. Shizuku нужно перезапускать после перезагрузки телефона (или настроить автозапуск). Его используют десятки приложений - это зрелый инструмент с открытым исходным кодом.
⚠️ Нюанс с китайскими приложениями. В комментарии к этой статье читатель сообщил, что после установки Shizuku у него безвозвратно заблокировали аккаунт WeChat. Сам Shizuku ничего не инжектит в чужие процессы, но некоторые китайские приложения (WeChat, Alipay, UnionPay и родственные) агрессивно сканируют список установленных пакетов и могут расценить наличие ADB-инструмента как “модифицированное устройство”. Если такие приложения вам нужны – лучше держать их на отдельном устройстве без Shizuku.
Бонус: не только безопасность
Инструменты для заморозки давно существуют: Hail, IceBox. Замороженные приложения не расходуют заряд батареи, не занимают RAM, не создают фоновый трафик, не шлют уведомления – пользователь получает бонус к автономности и производительности. Но в этих инструментах триггером был “приложение мне редко нужно”. Теперь триггер другой: состояние VPN-подключения.
По степени защиты pm disable-user уступает только одному варианту - второму телефону, где потенциально опасные приложения физически находятся на другом устройстве. Но второй телефон - это неудобство, расходы и необходимость носить два устройства. Заморозка даёт 99% той же защиты на одном устройстве, без побочных эффектов.
Так появился Anubis - менеджер приложений, который автоматически связывает заморозку с состоянием VPN.
Архитектура Anubis
Три группы приложений
Вместо бинарного “заморозить / не заморозить” - три группы с разной сетевой политикой:
Группа |
Состояние приложения по умолчанию |
При запуске из Anubis |
|---|---|---|
Без VPN |
Заморожено |
Выключает VPN → размораживает → запускает |
Только VPN |
Заморожено |
Включает VPN → размораживает → запускает |
Запуск с VPN |
Активно |
Включает VPN → запускает |
“Без VPN” и “Только VPN” – всегда заморожены по умолчанию. Размораживаются только при явном запуске из Anubis или через ярлык. При смене состояния VPN – замораживаются обратно: включили VPN – заморозились приложения “Без VPN”, выключили – заморозились “Только VPN”.
“Запуск с VPN” – для приложений, которые морозить нет смысла (браузер, Telegram, YouTube), но которым для стабильной работы требуется VPN-подключение. Они живут как обычные приложения, получают пуши, но при запуске из Anubis автоматически поднимается VPN.
Таким образом, приложения “Без VPN” и “Только VPN” живут в постоянном анабиозе и оживают только по вашему явному запросу.

По сути, инверсия привычной модели Android: вместо “приложения работают всегда, если пользователь не вмешался” – “приложения мертвы всегда, если пользователь не запросил иное”.
Осознанный trade-off: замороженное приложение не получает push-уведомления. Если банк в группе “Без VPN” заморожен, пуш о переводе не придёт, пока вы не запустите его через Anubis. Такова цена за безопасность: либо приложение молчит и не шпионит, либо живёт и потенциально сливает данные. Anubis выбирает первое - а уведомления вы увидите, когда осознанно откроете приложение. Да и многие ли приложения шлют вам ВАЖНЫЕ пуши? Да и нейроресурс тоже стоит беречь.
Shizuku: shell-доступ без root
Чтобы вся эта оркестрация с заморозкой работала автоматически, нужен надёжный способ дёргать pm disable-user прямо из приложения. Anubis использует Shizuku (о котором мы говорили выше) – конкретно AIDL UserService паттерн из API 13.
// IUserService.aidl - выполняется в процессе Shizuku с правами shell interface IUserService { void destroy() = 16777114; int execCommand(in String[] command) = 1; String execCommandWithOutput(in String[] command) = 2; }
Почему AIDL, а не Shizuku.newProcess()
В Shizuku v13 метод `newProcess()` стал приватным. Вместо него используется паттерн UserService: мы определяем AIDL-интерфейс, реализуем его в классе `UserService`, который запускается в процессе Shizuku с правами shell. Связь через `Shizuku.bindUserService()`. UserService выполняет команды через `Runtime.getRuntime().exec()` - те же команды, что вы набираете в `adb shell`.
UserService инициализируется один раз в Application.onCreate() и живёт, пока работает приложение. Все компоненты (Activity, TileService, ShortcutActivity) используют один и тот же экземпляр. Это критично для отзывчивости - никаких задержек на подключение к Shizuku при каждом действии.
Управление VPN-клиентами
Anubis умеет запускать VPN-клиенты через shell-команды:
Клиент |
Метод |
Команда |
|---|---|---|
v2rayNG |
Toggle (widget broadcast) |
|
NekoBox |
Start/Stop (exported Activity) |
|
Happ |
Toggle (widget broadcast) |
|
v2rayTun |
Toggle (widget broadcast) |
|
V2Box |
Toggle (widget broadcast) |
|
Любой другой |
Ручной |
Открывает приложение |
Toggle - та же команда, что отрабатывает при нажатии на виджет клиента на рабочем столе: если VPN выключен - включить, если включён - выключить. NekoBox - исключение: у него отдельные Activity для включения и выключения.
Что такое am broadcast и am start
`am` - Activity Manager, системная утилита Android. `am broadcast` отправляет broadcast Intent - сообщение, на которое может отреагировать любое зарегистрированное приложение. Так работают виджеты на рабочем столе: при нажатии на виджет VPN-клиента, система отправляет broadcast, а клиент его получает и включает/выключает VPN. Мы делаем то же самое, но из командной строки через Shizuku. `am start` запускает Activity - экран приложения. У NekoBox есть специальные Activity для включения и выключения VPN, которые не показывают UI, а просто выполняют действие и закрываются. Обе команды доступны через `adb shell` или через Shizuku с правами shell.
Пользователь также может выбрать любое установленное приложение в качестве VPN-клиента - оно будет работать в ручном режиме (Anubis открывает его для включения, а для выключения использует механизмы, описанные ниже).
Определение активного VPN-клиента
Пользователь может включить VPN не только через Anubis, но и напрямую из клиента – открыть v2rayNG и нажать кнопку. Чтобы интерфейс Anubis честно показывал, какой именно клиент сейчас держит VPN (а не только тот, что выбран в настройках), нужен способ спросить об этом у системы. Плюс эта же информация помогает в крайнем случае – когда dummy VPN не сработал и приходится делать am force-stop конкретного процесса.
Система знает, какое приложение владеет VPN-сетью. Мы извлекаем это через Shizuku:
dumpsys connectivity | grep -A 30 'type: VPN\[' | grep -oE 'OwnerUid: [0-9]+'
Что такое dumpsys и UID
`dumpsys` - диагностическая утилита Android, которая выводит внутреннее состояние системных сервисов. `dumpsys connectivity` показывает все сетевые подключения, включая VPN. Для каждого подключения система хранит UID (User ID) - числовой идентификатор приложения, которое его создало. Зная UID, через `pm list packages --uid` получаем имя пакета. Это та же информация, которую Android показывает в шторке уведомлений: "Подключено через Happ" - просто мы извлекаем её программно.
Получаем UID владельца VPN-сети, резолвим в package name. Это работает для любого клиента - известного, неизвестного, кастомного. Даже если пользователь установил VPN-клиент, которого нет в нашем списке, мы покажем его package name в интерфейсе и сможем корректно его остановить.
Путь к работающему решению: три неудачные попытки
**Попытка 1: reflection на NetworkCapabilities.mOwnerUid.** На Android 11 поле попало в hidden API blocklist - getDeclaredField() бросает NoSuchFieldException. На Android 10 поле вообще не существует в публичном API. Отброшено. **Попытка 2: dumpsys connectivity | grep -i vpn.** Ловило строку NOT_VPN из WiFi-сети! Каждая WiFi-запись содержит NOT_VPN в capabilities. В результате возвращался UID 1000 (system) и package com.android.dynsystem. Полностью мимо. **Попытка 3: pidof для каждого известного клиента.** Находило все запущенные VPN-клиенты, а не тот, который реально держит VPN. v2rayNG мог висеть в фоне, пока Happ реально обеспечивал VPN. В итоге мы пытались остановить не тот клиент. **Работающее решение:** grep -A 30 'type: VPN\[' - паттерн, уникальный для VPN-сети. Не совпадает с NOT_VPN. Тестировано на Pixel 5, Android 11.
Изящный хак: как отключить любой VPN-клиент без API и без root
Итак, мы умеем запускать VPN и определять, кто его держит. Осталась обратная задача: как выключить VPN-клиент?
Почему обычные способы не работают
Для NekoBox это тривиально – у него есть отдельная Activity для отключения. Но для toggle-клиентов (v2rayNG, Happ и др.) всё сложнее: toggle-команда ненадёжна для остановки. При тестировании Happ обнаружилось: мы отправляем toggle, VPN на мгновение выключается, Anubis начинает размораживать приложения – а Happ уже переподключился. Приложения оказываются разморожены при активном VPN.
am force-stop тоже не панацея – не всегда срабатывает мгновенно. А для произвольного клиента, о котором мы ничего не знаем, API остановки нет вообще.
Dummy VPN: перехват через архитектуру Android
Я перепробовал всё что мог – и решение пришло из самой архитектуры Android: система разрешает только один VPN одновременно. Когда приложение вызывает VpnService.establish(), система автоматически отзывает предыдущий VPN.
Как работает VPN на Android
На Android VPN реализован через системный API VpnService. Приложение создаёт виртуальный сетевой интерфейс (tun0), через который система направляет весь (или часть) трафика. Но система разрешает только один такой интерфейс одновременно. Если второе приложение создаёт свой VPN - первый автоматически отключается. Это как розетка, в которую можно воткнуть только одну вилку. Мы используем это: создаём "пустой" VPN на долю секунды - система отзывает чужой -- мы тут же закрываем свой. Результат: ни одного VPN. При первом использовании Android покажет системный диалог "Разрешить VPN?" - это одноразовое действие.
Мы создали StealthVpnService - минимальный VPN-сервис, который делает одну вещь:
class StealthVpnService : VpnService() { private fun doDisconnect() { // Устанавливаем свой VPN - система отзывает чужой val fd = Builder() .addAddress("10.255.255.1", 32) .setSession("stealth-disconnect") .establish() // Немедленно закрываем - VPN нет вообще fd?.close() stopSelf() } }
Результат: любой VPN-клиент отключён, и нам даже не нужно знать его package name. Требуется VPN permission (одноразовый системный диалог при первом использовании).
Поэтому toggle используется только для включения (когда VPN точно выключен). Для выключения – эскалация:
API stop - только для клиентов с явной командой (NekoBox:
QuickDisableShortcut)Dummy VPN - перехватываем VPN, закрываем свой → ни одного VPN нет
am force-stop– останавливаем процесс обнаруженного клиента
Приложения не размораживаются, пока VPN реально не отключился. Состояние проверяется каждые 200мс через ConnectivityManager. Если после всех трёх шагов VPN всё ещё активен - остаёмся в защитном режиме и показываем ошибку.
Нюанс: если в системных настройках Android включена “Постоянная VPN” (Always-on VPN) для клиента, система будет автоматически перезапускать его после нашего перехвата. В этом случае Always-on нужно выключить.
Обнаружение API закрытых VPN-клиентов через jadx
Изначально Anubis поддерживал автоматический запуск только для v2rayNG и NekoBox – у них open-source, и API легко находится прямо в коде. Остальные клиенты работали в ручном режиме: Anubis открывал приложение, а пользователь сам нажимал “Подключить”. Выключение делалось через dummy VPN – для него реверс не нужен.
Но переключение контекста (открыл шторку → нажал на ярлык → подождал → переключился в чужое приложение → нажал там кнопку → вернулся в исходное) убивало весь смысл оркестрации. Хотелось одного нажатия. Так появилась задача – реверсить closed-source клиенты, чтобы и для них работала автоматика.
Целевые клиенты – Happ, v2rayTun, V2Box. Все три closed source, исходный код недоступен, документации по внешним API нет. Как был найден broadcast action для управления ими?
Ключевое наблюдение
Ресурсы Android (строки, XML-разметка, манифест) не обфусцируются. Обфускатор R8/ProGuard работает только с Java/Kotlin кодом: переименовывает классы, методы, переменные. Но strings.xml, AndroidManifest.xml, XML-описания виджетов остаются нетронутыми.
Это даёт нам точку входа: если у приложения есть виджет на рабочий стол (а у всех VPN-клиентов с поддержкой toggle он есть), мы можем найти его через ресурсы.
Пошаговая методика
Декомпилируем APK через jadx
Ищем виджет в ресурсах: в
res/values/strings.xmlнаходимapp_widget_name– имя виджета (“Switch”, “Toggle”). Ресурсы не обфусцированы.Находим receiver в манифесте: в
AndroidManifest.xmlищем<receiver>с<meta-data android:name="android.appwidget.provider">– это классAppWidgetProvider.
Важно: не перепутать с shortcuts
В APK может быть несколько компонентов с похожими именами. Например, в V2Box есть и `ScSwitchActivity` (в `shortcuts.xml`), и `WidgetProvider` (receiver в манифесте). `shortcuts.xml` -- это ярлыки для лаунчера, а нам нужен именно **receiver виджета рабочего стола**. Отличить легко: у receiver'а есть ``, а в `shortcuts.xml` перечислены `` с `` на Activity. Почему receiver, а не activity? Потому что `am broadcast` можно отправить в фоне без UI, а `am start` на Activity может показать экран. Виджет по определению работает через broadcast -- нажатие на виджет отправляет PendingIntent с broadcast, receiver его ловит и дёргает toggle.
Извлекаем broadcast action из кода: в Java-коде receiver’а ищем
setAction("...")– эта строка тоже не обфусцирована, потому что broadcast action’ы являются runtime-константами.Проверяем логику: в
onReceive()ищем паттерн toggle:
// Декомпилированный Happ (jadx output) // Классы и методы обфусцированы (kd5, r25), но строка action и структура видны intent.setAction("com.happproxy.action.widget.click"); // ... if (kd5.a.getIsRunning()) { r25.L(context); // stop } else { r25.J(context); // start }
Проверяем exported: в манифесте смотрим
android:exported="true"у receiver’а – если да, broadcast можно отправить из любого приложения. У всех проверенных клиентов WidgetProvider имеетexported=true(системе нужно отправлять ему APPWIDGET_UPDATE). Но даже если быexported=false– через Shizuku shell (UID 2000) broadcast доставляется в любой компонент, потому что shell обходит эту проверку.
Паттерн v2ray/xray форков
Все четыре проверенных форка (v2rayNG, Happ, v2rayTun, V2Box) используют одинаковую структуру:
Action: <package>.action.widget.click Receiver: <package>.receiver.WidgetProvider (или WidgetProvider1x1 у v2rayTun)
Зная package name нового форка, можно предсказать broadcast action без декомпиляции.
Shell-команда для toggle:
am broadcast -a <package>.action.widget.click -n <package>/.receiver.WidgetProvider
Это стандартный Android IPC - broadcast action’ы являются публичными интерфейсами по определению. Обнаружение API для целей совместимости защищено законодательством (EU Software Directive 2009/24/EC, ст. 1280 ГК РФ).
Важно: toggle используется только для включения VPN. Почему для выключения он ненадёжен и что используется вместо – описано выше в секции про dummy VPN.
Ярлыки на рабочий стол
Техническая часть позади. Под капотом Anubis умеет: замораживать/размораживать приложения, запускать и останавливать VPN, определять активного клиента. Осталось сделать это удобным – чтобы пользователь просто нажимал на иконку приложения, а вся оркестрация происходила за кадром.

Для каждого приложения из любой группы можно создать pinned shortcut через ShortcutManager. Ярлык выглядит как обычная иконка приложения и ведёт себя как обычный запуск. Но под капотом:
Запускается
ShortcutActivity- прозрачная Activity без UIОна определяет группу приложения (Без VPN / Только VPN / Запуск с VPN)
Замораживает/размораживает нужные группы
Включает/выключает VPN через соответствующий клиент
Дожидается подтверждения состояния (VPN включился/выключился)
Размораживает целевое приложение
Запускает его
Закрывается
Пользователь видит: нажал ярлык → приложение открылось. 200мс задержки, если Shizuku уже подключён. Вся оркестрация за кадром.
Дополнительные детали
Grayscale для замороженных приложений
На домашнем экране иконки замороженных приложений отображаются в grayscale:
private val grayscaleFilter = ColorFilter.colorMatrix( ColorMatrix().apply { setToSaturation(0f) } )
Визуально видно, что приложение отключено. При размораживании иконка мгновенно становится цветной – для этого используется реактивный счётчик frozenVersion, который инкрементируется при каждой операции заморозки или разморозки.
Автозаморозка при запуске
Если при запуске Anubis обнаруживает активный VPN, он автоматически замораживает приложения группы “Без VPN”. Не нужно ничего нажимать - приложения защищены с первой секунды.
Проверка сети
Встроенная карточка “Сеть” показывает ping (время ответа ipinfo.io), страну и город. IP и провайдер скрыты за спойлером - это приватная информация, если пользователь работает через личный сервер. Проверка автоматически запускается при каждом изменении состояния VPN - видно сразу: VPN включился → страна изменилась.
Quick Settings Tile
Плитка в системной шторке определяет состояние из реальности (через ConnectivityManager), а не из внутренней переменной. Это важно: состояние могло измениться из ShortcutActivity или другого компонента, и плитка должна это отражать.
Фоновый мониторинг VPN (опционально)
Без фонового мониторинга есть один зазор: пользователь включает VPN-клиент напрямую (не через Anubis), а приложения группы “Без VPN” в этот момент разморожены. Они могут увидеть VPN.
Для закрытия этого зазора в настройках есть опция “Фоновый мониторинг VPN”. При включении запускается Foreground Service (сервис с постоянной нотификацией, который Android гарантированно не убивает) с подписчиком на изменения сети NetworkCallback. Он мгновенно реагирует на изменение VPN-состояния:
VPN включился → замораживает группу “Без VPN”
VPN выключился → замораживает группу “Только VPN”
Цена - постоянная нотификация в шторке. Поэтому это осознанно вынесено в настройку: если вы управляете VPN только через Anubis (или через ярлыки), фоновый мониторинг не нужен - оркестратор и так всё контролирует.
А что если просто firewall?
Казалось бы, можно просто заблокировать доступ приложений к SOCKS5 порту через iptables. Но:
iptables требует root. Shizuku даёт UID 2000 (shell), а для модификации firewall-правил нужен UID 0. AFWall+ и аналоги - только с root.
Даже root-firewall обходится. Статья про уязвимость VLESS-клиентов показала, что приложение может обратиться напрямую к tun0 через
setsockopt(SO_BINDTODEVICE), обходя per-app правила VpnService. Firewall iptables этот вызов тоже не блокирует.Отключённому приложению firewall не нужен. Если приложение отключено через
pm disable-user, у него нет процесса - некому подключаться к SOCKS5, некому обращаться к tun0, некому вообще что-либо делать.
Более того, наш подход даёт двойную защиту даже в момент, когда приложение разморожено. Вспомним порядок действий при запуске приложения из группы “Без VPN”:
Выключаем VPN → процесс VPN-клиента завершается → SOCKS5 порт закрывается → tun0 интерфейс исчезает
Проверяем что VPN действительно выключен (поллинг ConnectivityManager каждые 200мс)
Только после подтверждения размораживаем приложение
То есть к моменту, когда приложение оживает, прокси-порт уже закрыт и VPN-интерфейс уничтожен. Приложению просто нечего сканировать – ни открытого порта, ни tun0, ни активного VPN в ConnectivityManager.
Если собрать все подходы вместе – песочницу, firewall, заморозку – картина выглядит так:
Сравнение подходов (итого)
Island/Insular/Shelter |
Firewall (root) |
Anubis |
|
|---|---|---|---|
Метод |
Рабочий профиль |
iptables |
|
Приложение работает? |
Да |
Да |
Нет (мертво) |
ConnectivityManager видит VPN? |
Нет (фильтр по userId) |
Зависит от правил |
Невозможно |
Видит tun0? |
Да (ядро общее) |
Да ( |
Невозможно |
Видит SOCKS5? |
Да (loopback общий) |
Зависит от правил |
Невозможно |
Видит маршруты? |
Да (/proc/net/route) |
Да |
Невозможно |
Фоновая активность? |
Да |
Да |
Невозможно |
Защита от простых проверок |
Да |
Зависит |
Да |
Защита от методички Минцифры |
Нет |
Частично |
Да |
Управление VPN |
Нет |
Нет |
Да (5 клиентов + любой) |
Root нужен? |
Нет |
Да |
Нет (Shizuku) |
Удобство |
Ручная заморозка |
Настройка правил |
Один тап по ярлыку |
Стек
Kotlin + Jetpack Compose (Material 3, dynamic colors)
Shizuku API 13.1.5 - AIDL UserService для shell-команд без root
Room с TypeConverters - хранение групп приложений
ConnectivityManager NetworkCallback - мониторинг VPN в реальном времени
ShortcutManager - pinned shortcuts с оркестрацией freeze/VPN/launch
Что дальше
Self-hosted
app_processdaemon - для работы без ShizukuЭкспорт/импорт конфигурации групп
Поддержка дополнительных VPN-клиентов по мере обнаружения их API
Быстрый старт
⚠️ Прочтите перед тем, как добавлять приложения в группы.
Anubis замораживает приложения через системный
pm disable-user. Для Android это выглядит как отключение приложения, и большинство лаунчеров убирают ярлыки таких приложений с рабочего стола – иногда полностью из меню приложений. Виджеты тоже исчезают. Папки на рабочем столе, в которых лежали эти приложения, могут распасться.Это не удаление. Приложения, их настройки и учётные записи остаются в системе в состоянии
disabled. Но после разморозки ярлыки не возвращаются автоматически на прежние позиции – их придётся расставить заново. Это поведение лаунчеров, не Anubis.Поэтому:
Не жмите “Авто-выбор” вслепую. Сначала посмотрите, что именно Anubis предлагает – там могут оказаться приложения, чьи ярлыки вам нужны на рабочем столе (Яндекс.Клавиатура, Mir Pay и подобное).
Начните с 2-3 приложений (например, Сбер и Ozon). Убедитесь, что всё работает, потом расширяйте список.
Если ярлыки уже пропали – приложения не потеряны. Откройте Anubis → зажмите приложение → “Разморозить” → “Убрать из группы”. Оно вернётся в системный список приложений и появится в поиске. Ярлыки на рабочий стол перетаскивать руками.
Массовое восстановление удобнее делать через Hail: отсортировать замороженные, отметить галками, разморозить пачкой.
Установите Shizuku (на Android 11+ – через Wireless Debugging прямо с телефона, без компьютера, за 1 минуту)
Установите Anubis
Дайте разрешения (Shizuku + VPN)
Поместите приложения, для которых VPN нежелателен (банки, маркетплейсы), в группу “Без VPN”
Всё. Теперь при включении VPN они замораживаются автоматически
Никогда не пользовались режимом разработчика и Shizuku? Держите пошаговый гайд на русском – от “где вообще эта кнопка разработчика” до первого замороженного приложения.
Как помочь проекту
Anubis - полностью open-source (MIT). Проект на ранней стадии, и ему нужна помощь:
Звезда на GitHub - лучшая мотивация развивать проект
Какого VPN-клиента не хватает? Пишите в комментариях или в Issues. Добавить поддержку нового v2ray-форка - это 5 строк кода, а инструкцию по реверсу через jadx я оставил выше
Нашли баг? Issues на GitHub открыты
Хотите контрибьютить? PR приветствуются. Ближайшие задачи: self-hosted daemon без Shizuku, экспорт/импорт конфигурации
Ссылки
Проект:
Anubis на GitHub – исходники, APK, issues
Пошаговый гайд по установке – от “где кнопка разработчика” до готовой настройки
Инструменты, использованные в Anubis:
Контекст проблемы:
Методичка Минцифры (новость) – триггер всей истории с детектом VPN
Анализ MAX – подробное описание обнаруженного нежелательного функционала от @runetfreedom
Уязвимость VLESS-клиентов – SOCKS5 на localhost как вектор утечки выходного IP от @runetfreedom
Смежные решения (рекомендую):
Статья про Island – отправная точка обсуждения песочниц для изоляции шпионов от @linux-over
Трёхкаскадный VPN, устойчивый к spyware – серверный подход от @linux-over. Вместе с Anubis покрывают обе стороны проблемы
TeapodStream: критическая уязвимость VLESS-клиентов – модификация VPN-клиента от @Wendor с закрытым SOCKS5
Благодарности
Отдельное спасибо @linux-over – за его серию статей про Island и трёхкаскадный VPN, которые задали контекст для этой работы, и за инвайт, без которого вы бы это не читали. Наши подходы хорошо комбинируются: его схема обеспечивает устойчивость VPN-инфраструктуры на стороне сервера (точка входа из РФ остаётся в тени, бан выходного узла не ломает связность), Anubis устраняет источник проблемы на клиенте. Вместе получается дешевле и спокойнее, чем по отдельности.
Также спасибо @Wendor – его TeapodStream закрывает утечку SOCKS5 на уровне VPN-клиента. Если Anubis – это страховка “шпион не должен запуститься”, то TeapodStream – “даже если запустился, SOCKS5 ему не поможет”. В связке получается многослойная защита: VPN-клиент не светит прокси, Anubis не пускает шпиона до момента, когда VPN активен. Также спасибо @Wendor – его TeapodStream закрывает утечку SOCKS5 на уровне VPN-клиента. Если Anubis – это страховка “шпион не должен запуститься”, то TeapodStream – “даже если запустился, SOCKS5 ему не поможет”. В связке получается многослойная защита: VPN-клиент не светит прокси, Anubis не пускает шпиона до момента, когда VPN активен.
На этом технические решения проблемы, пожалуй, исчерпаны. А нетехнические… Как известно, или Internet Explorer, или падишах.
Anubis – MIT License. Приложение не предоставляет VPN-сервис, не содержит средств обхода блокировок и не предназначено для нарушения законодательства. Оно управляет жизненным циклом установленных приложений через стандартные механизмы Android (pm disable-user, VpnService API) и может использоваться для любых задач, связанных с приватностью и контролем фоновой активности приложений. Автор не призывает к нарушению действующего законодательства.
Комментарии (341)

Byaka8kaka
14.04.2026 13:02Установите Shizuku (на Android 11+ - через Wireless Debugging прямо с телефона, без компьютера, за 1 минуту)
Было бы супер, если бы была прям инструкция для не технических специалистов)
Примерно так:
1. Запустите настройку устройства и нажмите на символ поиска.
2. Наберите build и нажмите Номер сборки в списке ниже.
3. Нажмите Номер сборки 7 раз
4. Установите приложение
И т.д..
Иначе приложение дальше просто не уедет, а чем меньше людей себе его поставит - тем оно менее эффективно.
sogonov Автор
14.04.2026 13:02Согласен, абсолютно валидное замечание — запуск Shizuku это реальный порог входа для нетехнической аудитории. Сделал отдельный подробный гайд на русском: https://github.com/sogonov/anubis/blob/main/docs/SETUP.md - от “где вообще эта кнопка разработчика” до готовой настройки, с разделением на Android 11+ (без компьютера) и Android 10 (через ADB AppControl). Ссылку на гайд добавил в “Быстрый старт” в статье. Если есть замечания по гайду - буду рад улучшить, присылайте правки в Issues или прямо в комментариях.
В самой Shizuku сделан достаточно удобный гайд


Zachelovek
14.04.2026 13:02Сделал отдельный подробный гайд на русском
Спасибо!
Прочитал, один вопрос по итогам: минимальная версия андроид в гайде - 10. Верно ли я понял, что на более старых всё обсуждаемое тут неприменимо?

sogonov Автор
14.04.2026 13:02На более старых Android Shizuku формально должен работать(minSdk у него 24, это a7), но Anubis рассчитан на API 29+ (а10), и я не тестировал на более старых версиях. Попробую найти для теста устройство или на крайняк эмулятор, по идее, можно тоже понизить minSdk. Но метод с беспроводной отладкой это точно а11+, на всем, что ниже придется выдавать нужные права через adb shell по usb

Arjgsh
14.04.2026 13:02К сожалению эта вонючая шизука никак не хочет работать

sogonov Автор
14.04.2026 13:02А что именно не получается? Каким способом пытаетесь её включить? Я выложил чуть более подробный гайд на русском: https://github.com/sogonov/anubis/blob/main/docs/SETUP.md

Skipy
14.04.2026 13:02Производитель вашего устройства ограничил права adb, приложения, использующие Shizuku, будут работать некорректно
Обычно эти ограничения можно снять в настройках для разработчиков
А дальше предлагается почитать справку на сайте shizuku, который с телефона вообще не открывается
Всё, тупик. Чтобы на Xiaomi включить Shizuku, нужно включить отладку по USB (настройки безопасности). А для этого требуется войти в Mi Account. Которого не существует.

sogonov Автор
14.04.2026 13:02когда-то в очень далеком прошлом я тоже впервые пробовал, не получилось разобраться, а поскольку ноутбук с ADB чаще всего под рукой, я выдавал себе нужные разрешения через adb shell. Но сейчас на всех моих пикселях работает, быстро и удобно... А что у вас за операционная система?
У вас получается, вот такой выданный системой код не срабатывает?

Если не получится разобраться с беспроводом, моя рекомендация - установить ADB App Control, это пожалуй самый приятный способ взаимодействия с ADB, даже для меня, хоть и 90% действий я делаю в консоли Far Manager. Через adb shell скорее всего запустится с первого раза
p.s. пока писал вам ответ, ваш комментарий уже изменился)

Arjgsh
14.04.2026 13:02После сопряжения шизука не запускается, просто ожидает и все. И да, ограничение на adb, так же как и писали выше

Snooper
14.04.2026 13:02Попробуйте пункт «Отключить контроль разрешений» в настройках разработчика.

Arjgsh
14.04.2026 13:02Да, спасибо, видел в инструкции к шизуке, просто сейчас нет времени водится с телефоном. Когда разберусь звезду поставлю, а то лазить во второе пространство это неудобно. Сразу вопрос, что придумать для приложений, кидающих флаг ВПН, но для которых я хочу чтобы открывались все приложения (byedpi например), типо игнорировать от него состояние.
А, и ещё - всю эту порнографию не придется случаем проделывать после каждой перезагрузки устройства?
Ну а вообще это все полумеры. Тут уже была статья про то, что надо пролить прокси на локалхосте (почему это не делается изкаропки?) и вышла приложение даже, но, пока что, там нет роуминга, что очень и очень нужно

sogonov Автор
14.04.2026 13:021) если byedpi работает по аналогии с тем же adguard - то есть прописывается в системный VPN, хоть и не является им по своей сути, то да, он будет на общих основаниях триггерить Anubis. Но ему, по идее, не страшны и описанные методы из методички минцифры, нет IP которые можно испортить. Так что, если задача просто скрыть системный флаг "VPN сейчас активен" - в рабочий профиль всех, кому нужен byedpi, и там же его самого запускать, или наоборот, в зависимости от того, как проще организовать.
2) Придется после каждой перезагрузки, если устройство без root доступа(более того, пока получение прав через root, а не через shizuku приложение и не поддерживает). Но нужно будет всего лишь активировать shizuku. Это одна команда в adb shell или при а11+ способ через беспроводную отладку. Все группы приложений, а так же их состояние(заморожено/разморожено) сохранятся. Только право размораживать/замораживать после перезагрузки потеряется, пока не восстановить shizuku в правах
neit_kas
14.04.2026 13:02У себя на Samsung в разделе для разработчиков нашёл пункт: “Выбрать приложение для отладки”. Помню даже использовал его с Brevent. Не знаете, какие права у такого приложения? Это случаем не self-hosted ADB со всеми вытекающими?
И, кстати, на счёт “однокнопочных” универсальных решений. Я не Android разработчик, но как понимаю, реально определить, активен VPN или нет. А значит по идее можно не долбаться с API VPN клиентов: мониторим в фоне VPN. Если активируется - переключаемся. Или это будет не надёжно?

clientikshow
14.04.2026 13:02Сделайте пометку в статье, у меня была ситуация когда я поставил шизуку и мне заблок ровали WeChat аккаунт без возможности восстановления. Актуально может для тех кто пользуется приложениями из поднебесной

cjmaxik
14.04.2026 13:02У меня вичат работает без проблем, шизуку не трогал. Совпадение?

clientikshow
14.04.2026 13:02Возможно совпадение, но в моем кейсе только шизуку ставил и сразу бан словил.

sogonov Автор
14.04.2026 13:02я в статье пометку сделал, но впервые слышу о таком

GBQ3
14.04.2026 13:02Спасибо за труд. Но вопрос такой. Толе имею 3 приложения из китая.если их закинуть в песочницу увидят ли они работу шизуки? Или же такой вариант я закинуть их в Песочницу , заморозить . Если нужны , то отключить шизуку и после только запускать. Есть ли в этом смысл, ваше мнение ?

sogonov Автор
14.04.2026 13:02они могут видеть список пакетов установленных в системе, и даже замороженная shizuku им может в теории не понравиться. Тем не менее, в рабочем профиле они их скорее всего не увидят, там свое пространство. Установите в рабочее пространство anubis (даже без shizuku) и посмотрите, например в меню ручного выбора VPN, какие приложения он там видит? вот столько же приложений увидит и китайское.. Если только из рабочего профиля - то с вероятностью 80% они ничего не узнаю о том, что происходит в основном профиле

wet-thought
14.04.2026 13:02А ярлыки как вынести обратно? Можно шорткат какой-то для этого запилить?

sogonov Автор
14.04.2026 13:02Да, ярлыки выносятся через долгое нажатие на иконку приложения в Anubis - в контекстном меню есть пункт “Создать ярлык на рабочем столе”. Создаётся pinned shortcut через ShortcutManager: иконка ложится на домашний экран, при нажатии оркеструет freeze/VPN/запуск в одно действие. Если не работает - киньте https://github.com/sogonov/anubis/issues с моделью телефона и версией Android, буду разбираться
Hidden text



Skipy
14.04.2026 13:02Установите Shizuku (на Android 11+ - через Wireless Debugging прямо с телефона, без компьютера, за 1 минуту)
А можно вот это поподробнее? А то всё найденное стопорится на запуске Android Studio и/или спаривании телефона и компьютера

sogonov Автор
14.04.2026 13:02Вам, скорее всего, запускать Android Studio не понадобится, я обхожусь ADB+VS Code для разработки под андроид. Вы хотите собрать приложение на своем компьютере из исходников?
А про Shizuku я подробнее уже написал. Если вы установите Anubis, он сам подскажет, откуда скачать shizukuHidden text

А когда вы установите Shizuku, подробный гайд есть уже внутри него
И вам остается лишь выбрать, что проще - найти компьютер с ADB и сделать все по проводу, или подключиться к Wi-fi и попробовать способ с беспроводной отладкой

Я всегда пользовался шнуром, но сейчас снова попробовал способ с беспроводом - достаточно просто, понятно и нет зависимости от пк
p.s. Добавил в репозиторий гайд
https://github.com/sogonov/anubis/blob/main/docs/SETUP.md

Sneer1
14.04.2026 13:02Приблизительно о чем-то подобном и бродили мысли (логика работы). Интересная статья.

greenlittlefrog
14.04.2026 13:02Я себе сделал иначе: дома на Keenetic поднял wg клиент и подключил его, затем в маршрутизацию забил домены которые должны ходить только через wg. Таким образом дома всё маршрутизуется. Дополнительно на том же Keenetic поднял wg сервер, к которому вне дома подключается телефон и пользуется той же маршрутизацией. Дальше делаем на iOS автоматизацию, которая автоматически переключает VPN в зависимости от подключения к Wi-Fi.
На Linux аналогичный конфиг реализуется через dnsmasq и ip route.
Zloymopga
14.04.2026 13:02подумываю о такой же схеме но с vless. только вот вопрос - "шпионы" разве не будут видеть сам факт VPN при таком подходе?

greenlittlefrog
14.04.2026 13:02Некоторые жалуются потому что тумблер включен, но никакой блокировки или замедления нет.

Zloymopga
14.04.2026 13:02это значит, что они видят сам факт подключения. ну и потенциально могут сдетектить выходной ip - что уже угроза, что он попадет в блок-лист в будущем.

greenlittlefrog
14.04.2026 13:02Они просто дергают стандартный механизм iOS который позволяет им видеть что тумблер включен.
Дальше они могут посмотреть выходной IP - это будет русский IP, потому что через зарубежный VPN отправляются только определенные домены. Могут пингануть youtube.com - но он пингуется и без блокировки. Могут пустить traceroute - тут да, палево. В общем спалить можно, если сильно увлечься, тут вопрос заинтересованности. С точки зрения базового функционала у нас локация IP и гео совпадают.
SukharevAndrey
14.04.2026 13:02Им достаточно послать запрос на любой иностранный сервис определения айпишников, который отдаёт ответ в json. И сразу всё палится. Поэтому нужно делать triple-hop или иметь второй айпишник на выходной ноде или поднять там warp.

greenlittlefrog
14.04.2026 13:02У меня нет ни одного иностранного сервиса определения айпишников в белом списке, я так и не понял каким образом какое-то приложение должно узнать от условного ютуба адрес выходной ноды.

linux-over
14.04.2026 13:02белые списки ведь не круглосуточно работают
пока, во всяком случае

ilusha_b
14.04.2026 13:02Он имел в виду скорее всего свои белые списки.
Т.к. у него не "Всё, кроме этих доменов идет через VPN", а "Всё, кроме этих доменов не идет через VPN". Соответственно если у него указан домен ютуба и больше ничего - то всякие айпи чекеры будут показывать российский айпишник.

vikarti
14.04.2026 13:02иностранного сервиса определения айпишников в белом списке,
Известных вам сервисов.

Zalechi
14.04.2026 13:02уже тонны энергии сливаем ради ИИ для Вас лично, а вы стесняетесь им воспользоваться, чтобы спросить или не доверяете ему или не умеете формулировать вопросы?

spc
14.04.2026 13:02Сегодня приложение Дикси удивило - при включенном ВПН отказывается работать, хотя в настройках клиента указаны приложения, которым разрешен ВПН и Дикси там нет. Из этого я делаю вывод, что они сделали блокировку просто по факту включенного ВПН. Могу, конечно, ошибаться.

navion
14.04.2026 13:02Подтверждаю, Дикси не работает даже с App Tracking Protection в DuckDuckGo. В комментариях ещё писали про Газпромнефть с таким поведением.
Vabkab
Спасибо за проделанную работу! Было бы очень интересно, если бы вы добавили в сравнение подходов вариант от @Wendor. При нем, как я понимаю обнаружить наличие tun0 и не стандартной маршрутизации возможно, а подключиться к ней нет
sogonov Автор
Спасибо за идею! Добавил упоминание подхода @Wendor в статью (в “Предыстории” и “Благодарностях”). В сравнительную таблицу его вариант добавлять не стал - там у меня ось “что приложение видит” для песочницы/firewall/Anubis, а у Wendor’а другая плоскость: он чинит сам VPN-клиент. Получается не конкурирующий, а комплементарный подход - его TeapodStream закрывает SOCKS5, мой Anubis отключает шпиона целиком. В связке получается многослойная защита: клиент не светит прокси, Anubis не пускает шпиона до момента, когда VPN активен. Его решение также хорошо совместимо с Island и подобными приложениями - от того, что кто-то увидит наличие tun0 но не сможет им воспользоваться, выходной IP не пострадает. А при split per app маршрутизации, рабочем профиле с Island и его исправленном клиенте, не дающем лезть куда не следует, по идее, большинство приложений будут работать нормально с включенным VPN, и даже самые шаловливые из них не принесут вреда выходному серверу.