Вы не можете исключить программу из хоста WireGuard с полным туннелем, редактируя маршруты. Маршруты выбирают путь по назначению, а исключить вы хотите процесс, поэтому ядру не с чем сопоставлять. Рабочий подход — дать этому процессу собственный сетевой контекст: пространство имён со своим интерфейсом, своими адресами и своим маршрутом по умолчанию, соединённое с хостом парой veth. Я запускал это на Ubuntu 24.04 с wireguard-tools 1.0.20210914, и пространство имён ни разу не было проблемой — проблемой были политика пересылки хоста и правила маркировки туннеля.

Сначала выберите нужный тип контекста

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

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

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

Постройте второй контекст и подключите его к хосту

Иллюстративная схема: у хоста есть интерфейс WireGuard, несущий маршрут по умолчанию, и сетевое пространство имён с именем clearnet соединённое с хостом парой veth. Адреса ниже — примеры.

ip netns add clearnet
ip link add veth-clear-out type veth peer name veth-clear-in
ip addr add 192.168.100.1/24 dev veth-clear-out
ip link set veth-clear-out up
ip link set veth-clear-in netns clearnet
ip netns exec clearnet ip addr add 192.168.100.2/24 dev veth-clear-in
ip netns exec clearnet ip link set veth-clear-in up
ip netns exec clearnet ip route add default via 192.168.100.1

Это пространство имён теперь может достичь хоста и ничего больше. Хост должен пересылать трафик и переписывать адрес источника, потому что 192.168.100.0/24 — частная сеть, и у вышестоящего маршрутизатора нет маршрута обратно в неё:

sysctl -w net.ipv4.ip_forward=1
iptables -t nat -A POSTROUTING -o <wan-interface> -j MASQUERADE

Убедитесь в стороне пространства имён, прежде чем идти дальше.ip netns exec clearnet ip route должно показать маршрут veth и маршрут по умолчанию через 192.168.100.1, а ping на этот адрес должен ответить. Если ping на адрес хоста не проходит, адреса или состояние канала неверны, и никакое правило брандмауэра не поможет.

Когда имена разрешаются, но ничего не возвращается, прочитайте FORWARD

Классический сбой выглядит как ошибка маршрутизации: пространство имён разрешает имя, пакет уходит и ответ никогда не приходит. На хостах с политикой FORWARD DROP — так делают несколько дистрибутивов и большинство усиленных образов — пакет отбрасывается по пути, а ошибка, которую печатает приложение, ничего не говорит о фильтрации.

Прочитайте цепочку, прежде чем что-либо добавлять:

iptables -S FORWARD
nft list chain inet filter forward

Затем пропустите трафик в обе стороны, со счётчиками, чтобы знать, совпало ли правило когда-нибудь:

iptables -A FORWARD -i veth-clear-out -o <wan-interface> -j ACCEPT
iptables -A FORWARD -i <wan-interface> -o veth-clear-out -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
watch -n1 'iptables -L FORWARD -v -n'

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

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

Держите правила маркировки туннеля подальше от нового пути

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

Два дополнения разделяют пути. Вернитесь раньше в цепочке mangle для подсети пространства имён и добавьте правило на основе источника, которое помещает эту подсеть в основную таблицу:

iptables -t mangle -I PREROUTING -s 192.168.100.0/24 -j RETURN
ip rule add from 192.168.100.0/24 lookup main priority 100

Приоритет 100 упорядочивается перед правилами туннеля на моём хосте, поэтому для этого источника решает обычная таблица. Не копируйте число вслепую: приоритеты, которые wg-quick устанавливает, различаются между версиями и между настройками IPv4 и IPv6, поэтому выполните ip rule show и выберите приоритет, который на вашей машине окажется перед правилами туннеля.

Проверьте с помощью поиска, специфичного для источника а не доверяя списку правил:

ip route get 1.1.1.1 from 192.168.100.2
ip netns exec clearnet ip route get 1.1.1.1

Если первая команда сообщает интерфейс WireGuard, новое правило ещё не перед политикой туннеля. Если она сообщает интерфейс WAN, пока вторая всё ещё показывает маршрут по умолчанию veth, хост и пространство имён расходятся, и вам следует перечитать обе таблицы маршрутизации.

Запустите процесс, который открывает соединение

Запустить команду — одна строка, но запустите процесс, который действительно создаёт сокет.ip netns exec clearnet curl -s https://ifconfig.me— самый маленький честный тест: он показывает адрес, который пространство имён представляет миру, а не тот, который использовал бы хост.

Для службы подключите пространство имён по пути, чтобы процесс оставался в нём всю жизнь:

[Service]
NetworkNamespacePath=/run/netns/clearnet

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

readlink /proc/$(pgrep -f clearnet-profile | head -1)/ns/net
readlink /run/netns/clearnet

Два вывода должны совпадать. Та же проверка работает для любой долго работающей программы, и её стоит делать один раз на приложение, а не предполагать, что запускатель сделал то, что вы имели в виду.

Разрешение имён требует собственного решения. Создание пространства имён не даёт ему конфигурации резолвера; файлы для каждого пространства имён поддерживаются через /etc/netns/<name>/resolv.conf а без него вы наследуете поведение, которое легко прочитать неправильно. IPv6 требует такого же подхода: если у пространства имён нет маршрута по умолчанию v6, а приложение предпочитает v6, запросы могут застревать перед откатом, что выглядит как сломанный туннель.

Проверьте обрамление, а не только адрес выхода

Работающий публичный адрес доказывает маршрут, а не всё требование. Пройдите остальное в этом порядке:

  • ip netns exec clearnet ip route get 1.1.1.1 показывает маршрут по умолчанию veth, а не интерфейс WireGuard.
  • Счётчики FORWARD на обоих правилах растут, пока выполняется запрос.
  • Процесс приложения сообщает ожидаемый inode пространства имён.
  • После перезагрузки пространство имён существует до запуска службы; unit, который запускается раньше, терпит неудачу или, что хуже, работает вне пространства имён.

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

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