Always-on VPN или kill switch: что вы на самом деле включили?
Always-on VPN переподключает туннель; kill switch решает, что может выйти без него. Пять проверок, прежде чем верить надписи.
Always-on и kill switch стоят в двух строках друг от друга на одном экране настроек, поэтому люди читают их как два названия одной функции. Это не так. Always-on — это политика переподключения: запускать туннель при загрузке, возвращать его после сбоя или смены сети и продолжать попытки, пока он не поднимется. Kill switch — это политика трафика: он называет пакеты, которым всё ещё разрешено покидать машину, пока туннель лежит. Первое можно включить без второго, и на большинстве платформ результат по умолчанию всё равно выпускает трафик в этот промежуток.
Проверка 1: блокировка — это отдельный переключатель?
На Android 10 и новее сохранённый профиль VPN открывает за значком шестерёнки два независимых переключателя: Always-on VPN и Block connections without VPN. Только второй и есть kill switch. При одном always-on туннель действительно возвращается после обрыва, а любое приложение посреди запроса может выйти в сеть через Wi-Fi или мобильные данные, пока это не произойдёт.
Управляемые устройства сохраняют то же разделение в API политик. setAlwaysOnVpnPackage() принимает имя пакета и флаг lockdownEnabled; администратор, который задал пакет и оставил флаг false, построил постоянный туннель, а не закрытое устройство. Формулировки в консоли редко делают эту разницу заметной.
Читайте состояние с устройства, а не из консоли: adb shell settings get global always_on_vpn_app и adb shell settings get global always_on_vpn_lockdown. Если первая возвращает null, на уровне платформы не навязан ни один пакет; если вторая возвращает 0, платформа ничего не блокирует. Руководство по VPN для Android описывает это как отдельные возможности, а не один режим.
Проверка 2: какой слой владеет блокировкой?
Надписи живут в клиенте, а блокировки обычно в межсетевом экране, поэтому одно и то же слово на каждой платформе значит разное. Строки ниже стоит подтвердить, прежде чем доверять любой из них.
| Where you see the label | What the label promises | What actually blocks |
|---|---|---|
| Android VPN profile | Always-on VPN | Block connections without VPN |
| Android device policy | Always-on package | lockdownEnabled flag |
| Windows built-in VPN | Always On tunnel | Outbound firewall rules |
| WireGuard for Windows | Tunnel service | Block untunneled traffic option |
| wg-quick on Linux | Route via AllowedIPs | Your own nftables or iptables rules |
Windows — самый ясный пример надписи, которая не блокирует. Там Always On описывает устойчивость туннеля: туннель устройства для аутентификации машины и пользовательский туннель для вошедшей учётной записи, настроенные через XML профиля или Add-VpnConnection. Ничто в этом профиле не останавливает исходящий пакет, когда туннеля нет, а исходящая фильтрация по умолчанию не включена, поэтому ноутбук в Wi-Fi продолжает работать, пока VPN лежит.
WireGuard делится так же, но по клиенту. WireGuard for Windows имеет параметр Block untunneled traffic для каждого туннеля, который ставит правила фильтра; в инструментах Linux такого переключателя нет. wg-quick добавляет маршрут для каждой записи AllowedIPs и правило fwmark, а wg-quick down удаляет и то и другое, поэтому физический маршрут по умолчанию снова берёт работу на себя, не потеряв ни одного пакета.
На платформах Apple always-on приходит как функция профиля управления для наблюдаемых устройств и выражается правилами on-demand, а не флажком. Вопрос, на который нужно ответить по полезной нагрузке: отказывает ли несостоявшийся туннель в трафике или только просит другое соединение. Название пункта меню об этом не скажет.
Проверка 3: измеряйте промежуток, а не значок
Важны четыре перехода, и они ломаются по-разному: загрузка до того, как кто-то войдёт, сон и пробуждение, переход с Wi-Fi на мобильные данные и сбой клиента, который оставляет интерфейс туннеля наполовину настроенным. Чистое переподключение на одном из них ничего не доказывает про остальные три.
Самая дешёвая проверка намеренно останавливает туннель и затем пытается выйти. Когда туннель лежит, curl -m 5 -sS -o /dev/null -w '%{http_code}' https://example.com, возвращающий 200, означает, что политика fail-open; тайм-аут или отказ в соединении означают, что что-то всё ещё блокирует. ip route get 1.1.1.1 называет интерфейс, который понёс бы пакет, и это обычно информативнее значка в трее, а systemctl status wg-quick@wg0 показывает, был ли интерфейс аккуратно удалён.
Запустите ту же проверку во втором окне, пока сеть меняется, а не только после того, как она устоялась. Интервал между обрывом и повторной попыткой — это и есть главное, а разрешение имён — самый быстрый способ заметить, что трафик ушёл: если локальный резолвер отвечает, пока туннель лежит, блокировка неполная.
Проверка 4: определите исключения до того, как запрёте
Два исключения структурные. Клиент должен дойти до самого сервера VPN, поэтому набор правил, который отбрасывает всё, мешает и переподключению, которое вернуло бы защиту. Captive portal тоже недоступен через туннель, который не поднят, поэтому заблокированному устройству в гостиничном Wi-Fi нужен задокументированный способ открыть портал, а не импровизированный.
Минимальная форма: конечная точка разрешена, всё остальное отброшено:
table inet vpnlock {
chain output {
type filter hook output priority 0; policy drop;
oifname "lo" accept
ip daddr 203.0.113.10 udp dport 51820 accept
oifname "wg0" accept
}
}
Относитесь к этой строке конечной точки как к переменной, а не константе. Провайдеры меняют адреса, и устаревшее исключение — обычная причина, по которой работающий kill switch превращается в устройство, которое не может переподключиться. Локальные принтеры, общие ресурсы NAS и сервисы разработки входят в тот же записанный список, иначе они обнаруживаются по одному обращению в поддержку.
Проверка 5: запишите, что вы на самом деле доказали
Держите таблицу с четырьмя столбцами и заполняйте её тестами: состояние, ожидаемое поведение, наблюдённое поведение, доказательство. Строки — это переходы из проверки 3 плюс один намеренный сбой. Строка, которую нельзя заполнить выводом команды, — это непроверенная строка, а устройство, которое проходит строку переподключения и падает на строке загрузки, встречается достаточно часто, чтобы оправдать лишние десять минут.
Прежде чем считать готовым:
- Убедитесь, что настройка блокировки отделена от настройки переподключения, и прочитайте её значение на устройстве.
- Знайте, какой слой применяет блокировку - параметр клиента, политика устройства или межсетевой экран - и где этот слой настраивается.
- Сохраните одну проверочную команду, доказывающую блокировку, и запускайте её во время перехода, а не после.
- Запишите список исключений, включая конечную точку, и отметьте, кто его обновляет.
- На управляемом оборудовании не трогайте навязанную политику; удаление блокировки меняет требование, а не чинит туннель.