Маршрутизируйте трафик через определенный интерфейс для процесса в Linux.

Вопрос или проблема

Можно ли направить трафик, используемый процессом, через определённый интерфейс?

Например, сетевой трафик загрузочного приложения всегда должен использовать интерфейс 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

Как это работает?

  1. Использование cgroups: Система Linux поместит приложение в определённую группу контроля, что позволит маркировать сетевой трафик, исходящий от этого приложения.
  2. Маркировка трафика с помощью iptables: Затем с использованием iptables мы можем заставить этот трафик выходить через нужный IP-адрес.
  3. Обработка маршрутов с помощью таблицы маршрутизации: 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

Ручная настройка

Если вы предпочитаете ручной подход, следуйте этим шагам:

  1. Установка необходимых пакетов:

    sudo apt-get install cgroup-lite cgroup-tools
  2. Настройка группы контроля:

    sudo su
    mkdir /sys/fs/cgroup/net_cls/novpn
    cd /sys/fs/cgroup/net_cls/novpn
    echo 0x00110011 > net_cls.classid
  3. Настройка 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
  4. Запуск приложения через cgroup:

    exit
    sudo cgcreate -t $USER:$USER -a $USER:$USER -g net_cls:novpn
    cgexec -g net_cls:novpn <приложение>

Альтернативные методы

Можно также использовать сетевые пространства имен (network namespaces) или прокси типа LD_PRELOAD для более сложных конфигураций.

Заключение

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

Оцените материал
Добавить комментарий

Капча загружается...