Raising the marker makes the older app refuse a 2.2.0 package through its own update path, but a root-manager flash never consults it. That leaves one reachable combination in which a completed stop is displayed as a failure, so the operations guide names it and the remedy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
16 KiB
Эксплуатация Zapret2: поддержка, разрешения и восстановление
Этот документ дополняет основной README точными эксплуатационными границами APK и root-модуля. Он описывает контракт исходников. Подписанный релиз и конкретное устройство считаются проверенными только после прохождения release/device-матрицы.
Поддерживаемая конфигурация
| Компонент | Контракт |
|---|---|
| Android | API 24 (Android 7.0) или новее |
| Архитектура | ARM64 или ARM; x86/x86_64 не поставляются |
| Root-менеджер | Magisk 20.4+, KernelSU или APatch |
| Установка ZIP | Только boot mode: интерфейс менеджера либо magisk --install-module, ksud module install или apd module install из Zapret2 Control |
| Firewall | IPv4 iptables с NFQUEUE, --queue-bypass, multiport и mark; connbytes необязателен и при отсутствии включает исходящий KEEPALIVE-режим оригинального zapret2 |
| IPv6 | Требует того же набора в ip6tables; при его отсутствии IPv6 явно не перехватывается |
| Интерфейс | Jetpack Compose, Material 3 Expressive, светлая/тёмная тема и dynamic color на Android 12+ |
KernelSU 3.x требует metamodule только для содержимого system/: CLI-wrapper’ов и
hosts-оверлея. Основной сервис запускается модульным service.sh и не требует
монтирования /system. Другие root-менеджеры не входят в подтверждённую матрицу:
приложение не угадывает неизвестный installer backend.
Прошивка ZIP через TWRP/custom recovery не поддерживается. Installer получает
корректные MODPATH, архитектуру и manager environment только в boot mode. Поддерживаемый
root-менеджер сначала распаковывает кандидата в /data/adb/modules_update/zapret2,
а активный модуль остаётся неизменным до перезагрузки.
Зачем APK нужны разрешения
INTERNET— только для запроса метаданных релиза и скачивания выбранных APK/ZIP.ACCESS_NETWORK_STATE— для отображения типа текущего подключения.REQUEST_INSTALL_PACKAGES— для передачи уже проверенного APK системному установщику. Приложение не может незаметно завершить установку за пользователя.- Root выдаётся отдельно через активный менеджер/libsu. Он нужен для чтения защищённого состояния, изменения конфигурации, запуска/остановки сервиса и staging обновления через manager backend.
Приватный FileProvider не экспортируется и выдаёт временный read-доступ только к
проверенному APK внутри cache/updates/. Доступ ко всему cache или внешнему хранилищу
не предоставляется.
Что происходит при обновлении
Каждое обновление создаёт новую чистую генерацию из release ZIP в
/data/adb/modules_update/zapret2. Старое дерево не копируется и не объединяется с
новым: runtime-настройки, пользовательские пресеты, hostlist-файлы и Lua-изменения
начинаются с содержимого релиза. Активный модуль и запущенная служба не меняются до
перезагрузки. Downgrade через APK не поддерживается.
Нормальное восстановление
У пакетного обновления нет собственного lock/transaction/backup/recovery слоя. Незавершённый staging можно повторить через root-менеджер; активная генерация остаётся неизменной до перезагрузки. Runtime lifecycle и Full rollback имеют отдельные контракты и не участвуют в установке новой версии.
Безопасный порядок действий:
- Откройте Control и дождитесь завершения автоматической проверки состояния.
- Если доступно, повторите операцию или выполните обычную остановку/перезапуск.
- Для подтверждённо повреждённой установки используйте Full rollback в Control.
- Сохраните вывод Logs/Diagnostics; экспорт ограничен последними 64 КиБ и проходит редактирование приватных идентификаторов.
- Если приложение не может доказать безопасное состояние, перезагрузитесь и повторите проверку до любых ручных удалений.
Fail-closed сообщение не означает, что нужно стирать state-файлы. Оно означает, что автоматическая операция отказалась продолжать без достаточного доказательства.
Удаление и чистая переустановка
Для обычного удаления используйте интерфейс своего root-менеджера и затем перезагрузите устройство. Обычный uninstall удаляет runtime-состояние, но сохраняет защищённый tombstone как доказательство завершённого удаления.
Для полностью чистой переустановки есть отдельная необратимая операция:
- В APK откройте Control → «Восстановление» → «Удалить данные модуля полностью» и подтвердите удаление. APK останется установленным, а его внутреннее состояние будет сброшено вместе с модулем.
- Если интерфейс APK недоступен, нажмите Action у модуля в root-менеджере два раза в течение 120 секунд. Первое нажатие создаёт одноразовое подтверждение, второе выполняет удаление.
- Перезагрузите устройство до повторной установки модуля.
Обе кнопки вызывают один канонический lifecycle-сценарий. Он останавливает сервис, проверяет отсутствие принадлежащих Zapret2 процессов и firewall-правил, затем удаляет активный/ожидающий модуль, настройки, списки, журналы, state, install/update/recovery каталоги и устаревшие файлы. Сам установленный APK не удаляется. Операция отказывается продолжать при активной или неоднозначной транзакции и не обходит recovery-доказательства.
Uninstall сначала публикует защищённый tombstone, затем выполняет bounded stop и проверяет отсутствие принадлежащих Zapret2 процессов/firewall-правил. Неавторизованные или неоднозначные файлы намеренно сохраняются для диагностики вместо слепого удаления.
Диагностика
Базовые root-команды:
su -c zapret2-status
su -c zapret2-stop
su -c zapret2-start
su -c zapret2-restart
Проверьте в таком порядке:
- Root-менеджер действительно выдал APK root и модуль не отключён/не ожидает удаления.
- Control не показывает active update/recovery или partial package state.
- В статусе доказаны текущий owner, PID/starttime, generation и ruleset.
- Ядро поддерживает обязательные NFQUEUE/firewall-возможности.
- AdGuard, NetGuard, AFWall+ и другие владельцы firewall временно отключены для изолированной проверки.
- Для стратегии выбран совместимый preset/category и существующие hostlist-файлы.
Read-only device preflight и формат сохраняемых доказательств описаны в
tests/device/README.md. Изменяющие стадии допускаются
только на одноразовом устройстве с явными подтверждениями, указанными в harness.
Модуль не запускается и не останавливается
Если и zapret2-start, и zapret2-stop отвечают RECOVERY_BLOCKED
(в приложении — ошибка с доменом LIFECYCLE и стадией START_RECOVERY
или STOP_RECOVERY), значит в /data/adb/zapret2-state осталось состояние
прерванной операции. Снять его вправе только загрузочный проход
восстановления — перезагрузите устройство, после чего автостарт
отработает штатно. Это же указано в тексте самой ошибки.
Текст ошибки называет и само лекарство: перезагрузка помогает, когда состояние
классифицировано как unsafe. Если речь о незавершённом полном откате
(rollback-partial), сначала доведите откат до конца — перезагрузка сама по
себе такие улики не снимает, они durable по замыслу.
Если и это не помогло, каталог состояния можно удалить целиком. Сначала проверьте, нет ли в нём резервной копии вашего hosts-оверлея — во время незавершённого полного отката это может быть единственная копия:
su -c 'ls -l /data/adb/zapret2-state/hosts.rollback.backup'
# если файл есть — сохраните его, например:
su -c 'cp /data/adb/zapret2-state/hosts.rollback.backup /sdcard/zapret2-hosts.backup'
su -c 'rm -rf /data/adb/zapret2-state'
Пресеты, hostlist-файлы и runtime.ini лежат в каталоге модуля и при этом не
страдают.
Отказ STATE_UNAVAILABLE («insecure or unavailable zapret2 state directory»)
лечится тем же способом: каталог должен принадлежать root и иметь режим 0700.
Старт отказывает с «uninstall tombstone blocks start/restart»
Так бывает после ручного запуска uninstall.sh (без удаления модуля через
root-менеджер): скрипт намеренно оставляет метку сериализации, а снимает её
только полное удаление модуля менеджером. Если модуль остался установленным и
вы хотите им пользоваться, метку нужно убрать вручную:
su -c 'rm -f /data/adb/zapret2-state/uninstall.tombstone'
Штатное удаление через root-менеджер этой ситуации не создаёт: там удаляется весь приватный каталог целиком.
Сообщение «IPv6 не удалось перепроверить»
На части устройств ядро собрано без ip6table_mangle, поэтому ip6tables
установлен, но на запросы не отвечает. Модуль отличает такую ситуацию от занятой
блокировки xtables: он повторяет опрос несколько раз и только после этого
считает семейство недоступным на этом устройстве.
Доказать чистоту такого семейства невозможно, а отказывать навсегда нельзя — следующая загрузка отказала бы точно так же и заблокировала бы stop, uninstall и полное удаление. Поэтому семейство пропускается, а неопределённость доводится до вас вместо того, чтобы быть тихо списанной:
- остановка и удаление завершаются успешно, но не заявляют «проверено чисто»;
- полный откат сообщает
Z2_RB_STATUS=partialприZ2_RB_FIREWALL_CLEAN=0; - полное удаление отдаёт квитанцию
partialс той же оговоркой; - приложение показывает оговорку рядом с результатом, а не как ошибку.
Это не сбой и не требует вмешательства. Правила несут --queue-bypass, поэтому
трафик не блокируется даже если что-то осталось, а перезагрузка снимает все
правила netfilter независимо от того, удалось ли их прочитать. Если сообщение
появляется на каждой операции — это свойство ядра устройства, а не состояния
модуля.
Известные границы текущего дерева
- Material 3 Expressive закреплён на экспериментальном API; это не stable Material 3.
- Source-аудит не заменяет compile/lint/test, screenshot/TalkBack и rooted-device gates.
- x86/x86_64, неизвестные installer backend’ы и устройства без обязательного NFQUEUE-контракта не заявлены как поддержанные.
- До публикации следует сверить SHA-256 и подпись именно финальных APK/ZIP, а не только имена файлов или страницу релиза.
- Обновляйте APK и модуль вместе. В 2.2.0 остановка вправе не подтверждать набор правил, когда одно семейство прочитать не удалось; приложение 2.1.x такую форму выразить не умеет и покажет успешную остановку как отказ. Маркер контракта поднят до 8, поэтому обновление модуля из приложения старая версия отклонит сама, — но прошивка ZIP через рут-менеджер эту проверку обходит, и там пара «старый APK + новый модуль» достижима.