Raspberry Pi, которому нужно защищать только собственный исходящий трафик, имеет два реалистичных решения: позволить сетевому менеджеру владеть туннелем или держать скрипт, который им владеет. Оба могут переносить трафик. Они отказывают в разных местах, и сбой, который вы можете диагностировать удалённо в два часа ночи, — тот, который стоит выбрать. Сравните их по владению, по тому, что означает полный туннель, когда в дело вступают IPv6 и DNS, и по тому, что происходит в момент падения туннеля.

Два владельца одного туннеля

Решение A — это профиль внутри сетевого менеджера системы: импортированный профиль OpenVPN или нативное подключение WireGuard, активируемое при загрузке той же службой, которая поднимает Ethernet и Wi-Fi. Решение B — ваша собственная единица, которая запускает клиент напрямую, правит конфигурацию резолвера и устанавливает свои маршруты и правила брандмауэра. Оба законны; они различаются тем, кому разрешено менять таблицу маршрутизации.

Отказы различаются, потому что владельцы разные. При A профиль, который не активируется, оставляет интерфейс поднятым, а туннель опущенным, и журналы менеджера говорят почему. При B скрипт, который удался наполовину, оставляет маршруты, переживающие породивший их процесс. Запускать оба — худший исход: два процесса пишут маршрут по умолчанию, две правки резолвера соревнуются при загрузке, и два набора секретов нужно ротировать.

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

Что создаёт импорт, а что нет

В Raspberry Pi OS Bookworm и новее стандартный инструмент настройки сети — NetworkManager, поэтому профиль является естественным домом для клиентского туннеля. Импорту нужен установленный соответствующий плагин; без него импорт завершается сообщением о неподдерживаемом типе подключения, что и есть честный сигнал остановиться и установить плагин.

nmcli connection import type openvpn file ./provider.ovpn
nmcli connection show
nmcli --ask connection up id provider-name

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

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

Полный туннель в сравнении обоих решений

Полный туннель — утверждение о маршрутах, а не о намерении, и два решения выражают его по-разному. Подход с профилем просит менеджер установить маршрут по умолчанию и свои настройки резолвера; подход со скриптом делает то, что говорит скрипт, включая ничего. Ни одно решение не покрывает IPv6, если ему не сказано, и нетронутый маршрут IPv6 по умолчанию охотно понесёт трафик вне туннеля, пока IPv4 выглядит безупречно.

ip -4 route get 198.51.100.23
ip -6 route show default
resolvectl query example.org

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

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

Открытый отказ против закрытого

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

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

sudo nft add table inet vpnkill
sudo nft 'add chain inet vpnkill out { type filter hook output priority 0; policy accept; }'
sudo nft add rule inet vpnkill out oifname != "tun0" ip daddr != 203.0.113.24 reject

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

Выбор для Pi без экрана

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

Переход между ними — в основном вопрос порядка: отключите старого владельца, убедитесь, что не осталось устаревшего маршрута или записи резолвера, затем включите новый и перезагрузитесь дважды. Одна перезагрузка может скрыть гонку, которую вскрывает вторая. Закончите проверкой Pi, а не туннеля: разрешите имя, получите что-нибудь по IPv4, получите по IPv6, если вы его сохранили, затем уроните туннель и убедитесь, что выбранное поведение действительно наступает. Интерфейс в ip link — начало проверки, а не конец.

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