- Вопрос или проблема
- Полное решение “cgroup”
- Как это работает?
- Автоматический скрипт
- Руководство вручную
- Ответ или решение
- Как маршрутизировать трафик конкретного процесса через определенный интерфейс в Linux
- Почему это важно?
- Решение с использованием cgroups
- Как это работает?
- Автоматизация через скрипт
- Ручная настройка
- Альтернативные методы
- Заключение
Вопрос или проблема
Можно ли направить трафик, используемый процессом, через определённый интерфейс?
Например, сетевой трафик загрузочного приложения всегда должен использовать интерфейс wlan0
, тогда как все остальные приложения на компьютере должны использовать eth0
.
Можно ли создать подобное правило в Linux?
Я так долго мучился с этой проблемой, поэтому вот ПОЛНОЕ решение. Проверено на Ubuntu 15 до 19.10. Вы можете использовать его, например, с OpenVPN, чтобы направить определенные приложения за пределы VPN-туннеля.
Полное решение “cgroup”
Как это работает?
- Ядро Linux помещает приложение в контрольную группу. Сетевой трафик из приложений в этой группе будет идентифицироваться по своему class ID на уровне сетевого контроллера.
- iptables помечает этот трафик и заставляет его выходить с соответствующим IP
- ip route обрабатывает помеченный трафик в другой таблице маршрутизации, с маршрутом по умолчанию к любому IP-шлюзу, который вы хотите.
Автоматический скрипт
Я сделал скрипт novpn.sh для автоматической установки зависимостей и запуска. Проверено на Ubuntu 15 до 19.10.
Сначала запустите ваш VPN.
wget https://gist.githubusercontent.com/kriswebdev/a8d291936fe4299fb17d3744497b1170/raw/novpn.sh
# Если вы не используете eth0, отредактируйте настройки скрипта.
sudo chmod +x novpn.sh
./novpn.sh traceroute www.google.com
./novpn.sh --help
Руководство вручную
Сначала установите поддержку cgroup и инструменты:
sudo apt-get install cgroup-lite cgroup-tools
Вам нужна версия iptables 1.6.0+. Получите источник выпуска iptables 1.6.0, извлеките его, а затем выполните следующее (--disable-nftables
флаг изберёт ошибки) из каталога исходников iptables:
iptables --version
sudo apt-get install dh-autoreconf bison flex
./configure --prefix=/usr \
--sbindir=/sbin \
--disable-nftables \
--enable-libipq \
--with-xtlibdir=/lib/xtables
make
sudo make install
iptables --version
Теперь, на самом деле настроим конфигурацию. Определите группу управления с именем novpn
. Процессы в этой группе будут иметь classid 0x00110011
(11:11).
sudo su
mkdir /sys/fs/cgroup/net_cls/novpn
cd /sys/fs/cgroup/net_cls/novpn
echo 0x00110011 > net_cls.classid
Теперь предположим, что реальный интерфейс, который вы хотите использовать для конкретного приложения, это eth0
с IP шлюза 10.0.0.1
. ЗАМЕНИТЕ их тем, что вам действительно нужно (узнайте информацию с помощью ip route
), особенно в новых версиях Ubuntu, где интерфейсы имеют странные имена. Выполните команду под root:
# Добавьте метку 11 для пакетов classid 0x00110011
iptables -t mangle -A OUTPUT -m cgroup --cgroup 0x00110011 -j MARK --set-mark 11
# Осуществите выход пакетов через eth0 с использованием NAT
iptables -t nat -A POSTROUTING -m cgroup --cgroup 0x00110011 -o eth0 -j MASQUERADE
# Определите новую таблицу маршрутизации "novpn"
# СДЕЛАЙТЕ ЭТО ТОЛЬКО ОДИН РАЗ!
echo 11 novpn >> /etc/iproute2/rt_tables
# Пакеты с меткой 11 будут использовать novpn
ip rule add fwmark 11 table novpn
# Novpn имеет шлюз по умолчанию к интерфейсу, который вы хотите использовать
ip route add default via 10.0.0.1 table novpn
# Отключите обратную проверку путей для всех интерфейсов, или по крайней мере для "eth0" и "all"
for i in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > $i; done
Наконец, запустите ваше приложение на конкретном интерфейсе:
exit
sudo cgcreate -t $USER:$USER -a $USER:$USER -g net_cls:novpn
cgexec -g net_cls:novpn traceroute www.google.com
# Закройте все окна Firefox сначала
killall firefox; cgexec -g net_cls:novpn firefox
Или если вы хотите переместить уже запущенный процесс в группу, то… вы не можете! Это связано с функцией NAT (маскарад): iptables -nvL -t nat
не совпадает при переключении группы, но iptables -nvL -t mangle
согласуется.
# Получите PID процесса (мы предположим, что это 1234)
pidof firefox
# Добавить в группу управления - ЭТО НЕ РАБОТАЕТ! Бесшумно не удается достичь финального результата.
sudo echo 1234 > /sys/fs/cgroup/net_cls/novpn/tasks
# Удалить - но это работает...
sudo echo 1234 > /sys/fs/cgroup/net_cls
Благодарности: Ни один ответ не работал так, как ожидалось, но смесь их помогла: ответ chripell, статья evolware Маршрутизация процессов средствами cgroups, iptables и политикой маршрутизации, Как заставить определенный процесс не проходить через OpenVPN-соединение?, Килл-свитч для OpenVPN на базе iptables
Связанный вопрос: iptables и cgroups v2 (netfilter’s xt_cgroup)
Это можно сделать, используя сетевые пространства имен Linux.
Вот статья, которая объясняет как. Основная идея состоит в том, чтобы создать сетевое пространство имен с другим маршрутом по умолчанию и запустить процессы, которым это необходимо, там. Вы подключаете вновь созданное сетевое пространство имен к физическому адаптеру через мост (но возможны также и другие решения).
Обновление: с ядра 3.14 это стало ещё проще благодаря контрольным группам, как описано в этой статье. Вы должны:
1) определить контрольную группу net_cls, чтобы аннотировать пакеты от заданного процесса с помощью classid (или группу процессов, отметим, что между ними не обязательно должна быть какая-либо родительско-дочерняя связь)
2) использовать модуль iptables cgroup (добавлен в Linux 3.14) для изменения меток пакетов
3) использовать маршрутизацию политики (ip rule add fwmark ….), чтобы создать новую таблицу маршрутизации для помеченных пакетов
Преимущество в том, что мы не должны выполнять мостирование, и всё намного более динамично, благодаря cgroups.
Объединив отличные ответы mariusmatutiae и KrisWebDev, я создал существенно изменённую версию отличного скрипта novpn.sh
от KrisWebDev. В то время как скрипт KrisWebDev предназначен для решения более конкретной проблемы (запуск и перемещение процессов внутри/вне VPN), моя версия позволяет вам запускать в принципе любую команду в сетевой среде, которую вы задаете. Вы можете задать интерфейс для связывания, маршрут по умолчанию, указать свои собственные правила iptables, статические маршруты, задать “тест”, чтобы подтвердить, что всё работает, как вам нужно, перед запуском команды… и так далее. Он позволяет использовать несколько файлов конфигурации, чтобы вы могли определить любое количество специфических сетевых сред, внутри которых вы можете запускать команды/процессы.
Я разместил его как gist здесь:
https://gist.github.com/level323/54a921216f0baaa163127d960bfebbf0
Он даже может очистить после себя контрольные группы/таблицы маршрутизации/iptables!
Буду рад отзывам.
PS – Он разработан для Debian 8 (Jessie)
Несколько людей написали обертки, которые используют функцию LD_PRELOAD в Linux для достижения этой цели:
Ещё одна альтернатива, которая работает для меня
https://daniel-lange.com/archives/53-Binding-applications-to-a-specific-IP.html
BIND_ADDR="192.168.1.188" LD_PRELOAD=/usr/lib/bind.so google-chrome
где 192.168.1.188 — это IP нестандартного сетевого интерфейса
.
Ответ или решение
Как маршрутизировать трафик конкретного процесса через определенный интерфейс в Linux
Маршрутизация сетевого трафика конкретного приложения через заданный сетевой интерфейс в Linux — это задача, которая может быть решена несколькими способами. В этой статье мы предлагаем полное решение с использованием групп контроля (cgroups) и iptables. Этот метод полезен, например, для обеспечения маршрутизации трафика загрузочного приложения через интерфейс wlan0
, в то время как остальные приложения используют eth0
.
Почему это важно?
Контроль сетевого трафика через различные интерфейсы позволяет повысить безопасность и эффективность работы сети. Это особенно актуально для конфигураций с VPN, где важно исключить определенные приложения из туннелей VPN.
Решение с использованием cgroups
Как это работает?
- Использование cgroups: Система Linux поместит приложение в определённую группу контроля, что позволит маркировать сетевой трафик, исходящий от этого приложения.
- Маркировка трафика с помощью iptables: Затем с использованием iptables мы можем заставить этот трафик выходить через нужный IP-адрес.
- Обработка маршрутов с помощью таблицы маршрутизации: ip route будет обрабатывать помеченный трафик в другой таблице маршрутизации, где маршрут по умолчанию ведет к нужному IP-адресу шлюза.
Автоматизация через скрипт
Чтобы упростить процесс настройки, можно использовать автоматизированный скрипт. Пример подобного решения – novpn.sh.
wget https://gist.githubusercontent.com/kriswebdev/a8d291936fe4299fb17d3744497b1170/raw/novpn.sh
sudo chmod +x novpn.sh
./novpn.sh traceroute www.google.com
Ручная настройка
Если вы предпочитаете ручной подход, следуйте этим шагам:
-
Установка необходимых пакетов:
sudo apt-get install cgroup-lite cgroup-tools
-
Настройка группы контроля:
sudo su mkdir /sys/fs/cgroup/net_cls/novpn cd /sys/fs/cgroup/net_cls/novpn echo 0x00110011 > net_cls.classid
-
Настройка iptables и маршрутизации:
iptables -t mangle -A OUTPUT -m cgroup --cgroup 0x00110011 -j MARK --set-mark 11 iptables -t nat -A POSTROUTING -m cgroup --cgroup 0x00110011 -o eth0 -j MASQUERADE echo 11 novpn >> /etc/iproute2/rt_tables ip rule add fwmark 11 table novpn ip route add default via 10.0.0.1 table novpn for i in /proc/sys/net/ipv4/conf/*/rp_filter; do echo 0 > $i; done
-
Запуск приложения через cgroup:
exit sudo cgcreate -t $USER:$USER -a $USER:$USER -g net_cls:novpn cgexec -g net_cls:novpn <приложение>
Альтернативные методы
Можно также использовать сетевые пространства имен (network namespaces) или прокси типа LD_PRELOAD для более сложных конфигураций.
Заключение
Предложенное решение облегчит настройку маршрутизации трафика, исходящего от конкретных приложений, через заданный сетевой интерфейс. Эта техника открывает широкие возможности для более гибкого управления сетевыми потоками в Linux. Ваши отзывы и предложения всегда приветствуются, поскольку они помогают улучшить и адаптировать существующие методы под текущие нужды пользователей.