Добавьте правило политики через ip rule, и оно работает, пока соединение не исчезнет; в этот момент его просто нет. Ничего не упало с шумом: состояние ядра изменилось, и ни один владелец конфигурации не знал, что правило должно существовать. В этом вся разница между правилом, которое выживает, и тем, которое нет. На хосте с systemd-networkd решение — дать правилу владельца, а не повторять команду после каждого переподключения.

Правило существует только тогда, когда у него есть владелец

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

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

У этого различия есть имя в networkd, и его стоит прочитать, прежде чем что-либо включать. Чужие правила по умолчанию удаляются в новых версиях, что удивляет тех, кто ожидал сохранения своих ручных записей.

Прочитайте версию, прежде чем доверять настройке

Поведение владения управляется настройкой в networkd.conf, и этой настройки нет в старых выпусках systemd. Проверьте установленную версию, прежде чем проектировать вокруг неё, потому что старый хост ведёт себя иначе, чем документация, которую вы читаете.

Важны два значения. Одно решает, удаляются ли правила, не объявленные в конфигурации networkd, а другое делает то же для маршрутов. Оба касаются владения, а не содержания политики, и оба по умолчанию выбирают более строгое поведение в текущих выпусках. Глобальное отключение сохраняет жизнь каждому чужому правилу, а это куда более широкое решение, чем объявить одну нужную политику VPN.

systemctl --version | head -1
networkctl --version | head -1
grep -R "ManageForeign" /etc/systemd/ /usr/lib/systemd/ 2>/dev/null

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

Объявите правило и таблицу, на которую оно указывает

Правило в файле .network называет таблицу, и это всё, что делает имя. Оно не создаёт маршруты внутри этой таблицы и не проверяет, имеют ли они смысл. Объявление правила без маршрутов даёт политику, которая сопоставляет трафик и затем отбрасывает его.

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

[RoutingPolicyRule]
Family=ipv4
IPProtocol=tcp
SourcePort=443
Table=100
Priority=1000

[Route]
Destination=10.80.0.0/24
Gateway=10.80.0.1
Table=100

Затем перезагрузите и прочитайте состояние ядра, а не файл. Конфигурация, разобранная чисто, всё равно может дать правило, которого вы не планировали, и оба представления совпадают только тогда, когда объявление было полным.

Выберите одного владельца для интерфейса

Два менеджера на одном туннеле создают борьбу, которая выглядит как ошибка в обоих. Импорт существующей настройки wg-quick в networkd — это миграция, а не дополнение, и запуск обоих оставляет интерфейс и его правила под двумя владельцами.

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

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

Отработайте события жизненного цикла

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

sudo networkctl reload
ip rule show
ip route show table 100
sudo systemctl restart systemd-networkd

Намеченный результат — та же политика с владельцем, созданная заново, и устаревшее состояние, выведенное из обращения, что прочнее, чем заново добавлять правило оболочки после каждого переподключения. Храните одну строку в журнале изменений, где названы файл, владеющий правилом, и версия, которая его поддерживает. Тогда следующий инженер сможет найти политику, не роясь в истории оболочки. Правило, которым никто не владеет, — это правило, которое снова будет потеряно.

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