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

20

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

Например, сетевой трафик при загрузке приложения должен всегда использовать интерфейс, wlan0тогда как все другие приложения на машине должны использовать eth0.

Возможно ли иметь такое правило в Linux?

Суреш
источник

Ответы:

22

Это можно сделать с помощью сетевых имен Linux.

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

Обновление: из ядра 3.14 использование групп управления еще проще, как описано в этой статье . Ты должен:

1) определить контрольную группу net_cls для аннотирования пакетов из данного процесса с помощью classid (или группы процессов, обратите внимание, что между ними не должно быть никаких отношений родитель-потомок)

2) использовать модуль iptables cgroup (добавлен в Linux 3.14), чтобы пометить пакеты

3) использовать политику маршрутизации (ip rule add fwmark ....) для создания новой таблицы маршрутизации для помеченных пакетов

Преимущество состоит в том, что нам не нужно заниматься связующим звеном, и все намного динамичнее благодаря cgroups.

chripell
источник
14

Я ооочень боролся с этим, так что вот ПОЛНОЕ решение. Он протестирован на Ubuntu 15 и 16. Вы можете особенно использовать его с OpenVPN для маршрутизации определенных приложений вне интерфейса VPN-туннеля.

Полное решение "cgroup"

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

  • Ядро Linux поместит приложение в контрольную группу . Сетевой трафик от приложений в этой группе будет идентифицирован по их идентификатору класса на уровне сетевого контроллера.
  • iptables отметит этот трафик и заставит его выйти с правильным IP
  • ip route будет обрабатывать помеченный трафик в другой таблице маршрутизации с маршрутом по умолчанию к любому IP-адресу шлюза, который вы хотите.

Автоматический скрипт

Я сделал скрипт novpn.sh для автоматизации установки и запуска зависимостей. Проверено на Ubuntu.

Сначала запустите свой VPN.

wget https://gist.githubusercontent.com/kriswebdev/a8d291936fe4299fb17d3744497b1170/raw/cf8b37fbe6c3f50a0be825eb77cafa3e0134946f/novpn.sh
# If you don't use eth0, edit the script setting.
sudo chmod +x novpn.sh
./novpn.sh traceroute www.google.com
./novpn.sh --help

Ручная инструкция

Сначала установите поддержку cgroup и инструменты:

sudo apt-get install cgroup-lite cgmanager cgroup-tools

Перезагрузка (может и не понадобиться).

Вам нужен iptables 1.6 .0+. Получите исходный код релиза iptables 1.6.0 , распакуйте его и запустите ( --disable-nftablesфлаг позволит избежать ошибок) из директории источника iptables:

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. Процессы в этой группе будут иметь класс 0x00110011(11:11).

sudo su
mkdir /sys/fs/cgroup/net_cls/novpn
cd /sys/fs/cgroup/net_cls/novpn
echo 0x00110011 > net_cls.classid

Теперь предположим, что интерфейс, который вы хотите использовать для конкретного приложения, имеет eth0IP-адрес шлюза 10.0.0.1. Замените их тем, что вы действительно хотите (получить информацию от ip route). Запустите еще как root:

# Add mark 11 on packets of classid 0x00110011
iptables -t mangle -A OUTPUT -m cgroup --cgroup 0x00110011 -j MARK --set-mark 11

# Force the packets to exit through eth0 with NAT
iptables -t nat -A POSTROUTING -m cgroup --cgroup 0x00110011 -o eth0 -j MASQUERADE

# Define a new "novpn" routing table
# DO THIS JUST ONCE !
echo 11 novpn >> /etc/iproute2/rt_tables

# Packets with mark 11 will use novpn
ip rule add fwmark 11 table novpn

# Novpn has a default gateway to the interface you want to use
ip route add default via 10.0.0.1 table novpn

# Unset reverse path filtering for all interfaces, or at least for "eth0" and "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
# Close all Firefox windows first
cgexec -g net_cls:novpn firefox

Или если вы хотите перенести уже запущенный процесс в cgroup, ну ... вы не можете! Похоже, это связано с функцией NAT (маскарад): iptables -nvL -t natне совпадает, когда cgroup переключается, но iptables -nvL -t mangleсовпадает.

# Get PID of the process (we'll then suppose it's 1234)
pidof firefox
# Add to cgroup - THIS DOESN'T WORK! Silently fails to produce the final result.
sudo echo 1234 > /sys/fs/cgroup/net_cls/novpn/tasks
# Remove - but this works...
sudo echo 1234 > /sys/fs/cgroup/net_cls

Кредиты: Нет ответ не работал , как и ожидался, но смесь из них так: chripell ответить evolware статьи за процесс маршрутизации берут 2: с помощью контрольных групп, IPTables и политики маршрутизации , Как сделать процесс конкретного НЕ происходит через соединение OpenVPN? , Убить переключатель для OpenVPN на основе IPTables

KrisWebDev
источник
Спасибо за отличный ответ, как мне заставить его работать с apache? Я попытался cgexec -g net_cls:novpn apache2и дал мне весь список переменных неопределенных ошибок!
Раззак
2
Вы получите те же ошибки при запуске apache2прямо из терминала. Это потому, что apache2обычно запускается как служба, с systemctl start apache2. Однако это не сработает cgexec. apache2Вызываемая программа должна быть родителем процесса требуемого ( ), чтобы cgroup net_cls мог распространяться. Так что вам нужно найти скрипт запуска. В этом случае это так sudo cgexec -g net_cls:novpn /usr/sbin/apache2ctl start. Проверьте с ./novpn.sh --list.
KrisWebDev
Это больше не работает в Ubuntu 16.04!
Раззак
2
Я использую его на Ubuntu 16.04, и он работает нормально. Имена интерфейсов в Ubuntu 16 изменились, вы можете заменить необходимость заменить eth0на что-то вроде enp7s0. Получить информацию от ifconfigкоманды.
KrisWebDev
Спасибо. Но он не работает в Ubuntu 18.04 из-за удаления cpmanager из-за конфликта с systemd
skonsoft
3

Комбинируя превосходные ответы mariusmatutiae и KrisWebDev, я создал чрезвычайно измененную версию превосходного novpn.shсценария KrisWebDev . В то время как сценарий KrisWebDev разработан для устранения более специфического зуда (запуск и перемещение процессов внутри / вне VPN), моя версия позволяет вам выполнять практически любую команду в сетевой среде, которую вы укажете. Вы можете указать интерфейс для привязки, маршрут по умолчанию, указать свои собственные правила iptables, статические маршруты, указать «тест», чтобы подтвердить, что все работает, как вы хотите, перед запуском команды ... и т. Д.). Он позволяет вам использовать несколько конфигурационных файлов, чтобы вы могли определить любое количество конкретных сетевых сред, в которых вы можете запускать команды / процессы.

Я разместил это как суть здесь: https://gist.github.com/level323/54a921216f0baaa163127d960bfebbf0

Впоследствии он может даже очистить таблицы cgroup / iptables / routing!

Обратная связь приветствуется.

PS - Он предназначен для Debian 8 (Джесси)

все естественно
источник
Привет @allnatural, я хотел бы использовать ваш сценарий altnetworking.sh, но что я должен положить в файл конфигурации?
Cris70
0

Не за приложение, нет. Вы можете сделать это для каждого порта или для каждого IP-адреса и т. Д., Или само приложение может привязать (и использовать) определенную сетевую карту.

Вы не можете установить правило, чтобы сделать это, хотя.

Majenko
источник
У меня есть приложение Java, можно ли привязать это приложение к интерфейсу?
Суреш
Java-приложение, для которого у вас есть исходный код, и можете перепрограммировать внутренние компоненты?
Майенко
У меня есть исходный код Java-приложения, который использует библиотеку Apache http.
Суреш
Затем я отправляюсь на stackoverflow.com и спрашиваю там программистов, как изменить вашу программу. Я никогда не программировал на Java.
Majenko