Маршрутизация одной учётной записи Linux через OpenVPN правилом UID
Правило uidrange помещает IPv4-сокеты одной учётной записи в существующий туннель без namespace. Решите отдельно про DNS, IPv6 и резервный путь, затем проверьте.
Маршрутизация по учётной записи подходит, когда каждый IPv4-сокет одного пользователя Linux должен выходить через существующий туннель, и не подходит, когда нужна изоляция на уровне программы. Она выбирает по UID, поэтому всё, что работает под этой учётной записью, попадает в охват, включая забытое пакетное задание. Решите этот вопрос, прежде чем трогать хотя бы одно ip rule.
Пример ниже предполагает отдельную учётную запись браузера с UID 1500, туннельное устройство tun-office с локальным адресом 10.80.0.11 и VPN, разрешающий указанные назначения. Сам демон работает вне этого UID.
Три условия, которые выбирают механизм
Выбирайте правило UID, когда идентичность, выполняющая работу, это учётная запись, когда перенос всего её трафика приемлем и когда namespace был бы тяжелее, чем заслуживает задача. Выбирайте сетевой namespace, когда рабочей нагрузке нужны собственные интерфейсы, резолвер и таблица маршрутизации. Выбирайте прокси или привязку на процесс когда переместить нужно ровно одно приложение, а остальная часть сеанса остаётся на локальном пути. Запись этих трёх пунктов предотвращает правило, которое тихо охватывает больше задуманного.
Ошибка, которой стоит избегать, это предположение, что запускатель определяет владельца. Браузер, которому URL передал сеанс другого пользователя, не создал сокетов под UID 1500, и ни одно правило не переместит создаваемый им трафик.
Таблица, правило и предохранитель
После проверки существующих правил и выбора неиспользуемых номеров таблицы и приоритета схема коротка: маршрут по умолчанию в отдельной таблице с адресом источника туннеля, правило, отправляющее запросы учётной записи в эту таблицу, и завершающее правило, блокирующее резерв. В записанном виде это идемпотентная замена маршрута, ip -4 route replace default dev tun-office src 10.80.0.11 table 51820, за которой следует ip -4 rule add priority 12100 uidrange 1500-1500 lookup 51820.
Предохранитель это ip -4 rule add priority 12101 uidrange 1500-1500 unreachable, и он важнее, чем подсказывает его длина. Без него отсутствующий маршрут в таблице 51820 проваливается в обычный аплинк, и учётная запись тихо выпускает трафик, который политика должна была перехватить. С ним тот же сбой становится тайм-аутом, то есть блокировкой, а не резервом.
Держите обычное правило локального адреса перед этими, и осознанно решите, должны ли исключения для LAN или управления идти перед выбранной таблицей. Найденный там маршрут по умолчанию позже не обращается к main за более конкретным маршрутом LAN, что удивляет тех, кто ожидает применения совпадения самого длинного префикса между таблицами. Запишите предполагаемый список исключений в заметку об изменении, пока обоснование ещё свежо.
Что оставляет за рамками маршрутизация по UID: DNS
Демон резолвера открывает свои восходящие сокеты под собственным UID, поэтому выбор 1500 не переносит эти запросы в таблицу 51820. Интеграция DNS это отдельное решение: направьте учётную запись на резолвер, доступный через туннель, или примите, что разрешение имён идёт путём хоста, а трафик нет.
Запрос через loopback к локальному stub не доказывает, что восходящий запрос использовал маршрут браузера, как и успешная загрузка страницы из кеша.
IPv6 нужен собственный пункт в проекте
Правила выше охватывают только IPv4. Если требование это туннель IPv4 без прямого IPv6 из этой учётной записи, добавьте проверенное завершающее правило, например ip -6 rule add priority 12101 uidrange 1500-1500 unreachable, затем проверьте более ранние правила IPv6 и исключения loopback, которые хотите сохранить.
Блокировка прямого IPv6 это не двойной стек туннелирования, а граница. Если назвать это туннелированием, следующий читатель политики запутается, и путаница всплывёт как заявка в поддержку о сломанном сайте IPv6.
Проверьте на реальной учётной записи, а затем владейте жизненным циклом
Сравните запросы: ip -4 route get 198.51.100.25 uid 1500 к тому же назначению с обычным UID. Затем выполните разрешённый запрос под отдельной учётной записью и проверьте адрес источника, который видит удалённая сторона. Предпочитаемый адрес источника это не source NAT, и он не переопределит приложение, привязанное к чему-то другому. Если оба запроса возвращают один и тот же путь, правило делает не то, что вы думаете.
Держите таблицу, правила и время жизни туннельного маршрута у одного владельца, проверьте переподключение и потерю туннеля, а при выводе политики удаляйте только её точные записи. Namespace по-прежнему доступен, если отдельные интерфейсы и отдельное состояние это то, что вам действительно нужно.