Привязать Unix-программу к определенному сетевому интерфейсу

40

Вопрос: Как запустить программу, обеспечив при этом доступ к сети через определенный сетевой интерфейс?

Случай: я хочу получить доступ к двум различным машинам с одинаковым IP (192.168.1.1), но доступным через два разных сетевых интерфейса (eth1 и eth2).

Пример:

net-bind -D eth1 -exec {Program 192.168.1.1}
net-bind -D eth2 -exec {Program 192.168.1.1}

Вышеприведенное является приблизительным примером того, что я хотел бы, основываясь на аппаратной привязке, выполняемой через primusrun и optirun .

Задача: Как предлагается в связанном потоке , используемые интерфейсы выбираются не программой, а ядром (отсюда и синтаксис предварительной привязки в приведенном выше примере).

Я нашел некоторые связанные решения, которые являются неудовлетворительными. Они основаны на связывании сетевых интерфейсов посредством внесения в черный список пользовательских сетей; то есть запуск процесса от имени пользователя, который может получить доступ только к одному конкретному сетевому интерфейсу.

Skeen
источник
Вы подразумеваете, что ваша машина подключена к двум разным сетям, обе 192.168.1.0? Как выглядит ваша таблица маршрутизации? Если вы хотите ограничить интерфейсы, видимые из процесса, самое легкое решение - cgroups, более тяжелые контейнеры.
lgeorget
Да, две разные сети, обе в одном диапазоне IP. Я не уверен, что не хочу ограничивать видимые интерфейсы, просто диктую, какой использовать по умолчанию? :)
Скин
3
То, что вы спрашиваете, трудно по одной веской причине: объединение двух сетей с использованием одного и того же IP-домена похоже на наличие лифта в двухэтажном здании с одинаковым номером. Диапазон IP-адресов определяет домен, а не интерфейс вывода. Тем не менее, должен быть способ обойти ваш дефектный дизайн сети с помощью iptables.
lgeorget
Я подключаю свою систему к двум различным локальным инфраструктурам, так как такие инфраструктуры никогда не были предназначены для взаимодействия, и, следовательно, дизайн сети в этом отношении несовершенен.
Скин
1
Мой аргумент в пользу NAT состоял в том, что целые адресные пространства обычно скрыты за NAT, и когда я подключаю две NAT-инфраструктуры, происходит коллизия. - Я не в состоянии изменить инфраструктуру. - Я пытался использовать пространства имен сети с парами виртуальных сетевых интерфейсов (одно в пространстве имен, другое в корневом пространстве имен), соединяя корневое пространство имен одно с физическим интерфейсом, и запускать программы в пространстве имен сети. - Кажется, это работает, но я не получаю доступ за пределами корневого пространства имен (т.е. нет доступа вне самой машины).
Скин

Ответы:

35

Для Linux на Superuser уже ответили - как использовать разные сетевые интерфейсы для разных процессов? ,

Самый популярный ответ использует LD_PRELOADхитрость, чтобы изменить сетевую привязку для программы, но современные ядра поддерживают гораздо более гибкую функцию, называемую «пространства имен сети», которая предоставляется через ipпрограмму. Этот ответ показывает, как использовать это. Из моих собственных экспериментов я сделал следующее (как root):

# Add a new namespace called test_ns
ip netns add test_ns

# Set test to use eth0, after this point eth0 is not usable by programs
# outside the namespace
ip link set eth0 netns test_ns

# Bring up eth0 inside test_ns
ip netns exec test_ns ip link set eth0 up

# Use dhcp to get an ipv4 address for eth0
ip netns exec test_ns dhclient eth0

# Ping google from inside the namespace
ip netns exec test_ns ping www.google.co.uk

Также можно управлять сетевыми пространствами имен в какой - то степени с unshareи nsenterкоманд. Это позволяет вам также создавать отдельные пространства для PID, пользователей и точек монтирования. Для получения дополнительной информации см .:

Graeme
источник
«после этой точки eth0 не может использоваться программами за пределами пространства имен». Итак, я пытаюсь решить эту проблему?
Скин
1
@Skeen, да, так что, вероятно, вы бы добавили интерфейс, который никакие другие программы не используют в пространство имен, и использовали бы ваш основной как обычно.
Грэм,
1
@Graerne; Оба интерфейса активно используются; Я не могу позволить себе убрать интерфейсы.
Скин
а что со шлюзом по умолчанию? wvdialнапример, кажется, не устанавливает его вообще ... поэтому он должен быть определен в самом пространстве имен
Flash Thunder
Не могли бы вы включить инструкции о том, как отменить это? Вы просто ip netns remove test_nsхотите вернуться к нормальной жизни? Или ты должен сделать что-то особенное?
Multihunter
17

Я принимаю ответ Грэма; это просто продолжение, чтобы объяснить изменения, которые я внес в его предложение, чтобы решить мою проблему.

Вместо того чтобы связывать физический интерфейс внутри пространства имен, я создал пару виртуальных сетевых интерфейсов с одним концом в сетевом пространстве имен и одним концом в корне. Пакеты затем направляются через эту виртуальную сеть из пространства имен в корневое пространство имен и затем в физический интерфейс. - Таким образом, я могу запускать все свои обычные передачи данных и, кроме того, запускать процессы, которые могут получить доступ только к определенному интерфейсу.

# Create the eth0 network namespace
ip netns add eth0_ns

# Create the virtual network pair
ip link add v_eth0a type veth peer name v_eth0b

# Move v_eth0a to the eth0_ns namespace, the virtual pair is now split
# between two network namespaces.
ip link set v_eth0a netns eth0_ns

# Configure the ends of the virtual network pairs
ip netns exec eth0_ns ifconfig v_eth0a up {{NAMESPACE_IP}} netmask {{NAMESPACE_NETMASK}}
ifconfig v_eth0b up {{ROOT_NS_IP}} netmask {{ROOT_NS_NETMASK}}

# Setup routing from namespace to root
ip netns exec eth0_ns route add default gw {{ROOT_NS_IP}} dev v_eth0a

# Setup IP forwarding
echo 1 > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -s {{ROUTE_SOURCE}}/24 -o {{NETWORK_INTERFACE}} -j SNAT --to-source {{ROUTE_TARGET}}

Как только интерфейсы настроены для eth0 и eth1 с соответствующими им пространствами имен eth0_ns и eth1_ns, программы могут быть выполнены на указанном интерфейсе через;

ip netns exec eth0_ns fish
ip netns exec eth1_ns fish
Skeen
источник
4
Отлично сработано! Я думаю, что вы также можете создать мостовое устройство и соединить пространство имен по умолчанию и виртуальную пару с одним из физических устройств. Это выглядит эквивалентно, хотя.
Грэм
1
Я попытался соединить виртуальное и физическое устройство; Я не смог связаться с внешней сетью, используя это решение.
Скин
2
Я сделал, но только из нового пространства имен. Я думаю, что проблема, с которой я столкнулся, была связана с сетевым менеджером, хотя я не понял ее, иначе я бы обновил свой ответ.
Грэм,
У меня та же проблема, но я не смог использовать это решение. Что именно я должен ввести в {{ROUTE_SOURCE}} и {{ROUTE_TARGET}} на последнем шаге?
Литов
@Graeme, по крайней мере , на Ubuntu я был в состоянии получить подключения обратно в обоих имен, а также глобальное пространство имен путем размещения dhclient <bridge>на здесь .
Крис Хант
4

Решение I: Предварительная загрузка конкретной библиотеки

  • App-Route-Jail : используйте ld_preload для принудительной настройки интерфейсного шлюза (отличная идея, но требуются возможности root или меток). Подробное описание приведено ниже.

  • Proxybound : используйте ld_preload для принудительной установки прокси в конкретном приложении (вместо интерфейса используется прокси)

  • Force-Bind : имеет много функций, но утечки привязки (не надежны)

  • Bind-Interface-IP : слишком простые и неплотные соединения (не надежно)

  • Bind-IP : слишком прост и утечка соединений (не надежно)

Решение II: пользовательское пространство Linux

  • Классическое пользовательское пространство linux ip-netns : отличное решение, но требуется root, и интерфейс может существовать только в одном пользовательском пространстве

  • Firejail : Firejail может заставить приложение использовать определенную сеть, но совместимость ограничена (например, она не совместима с интерфейсами tun). firejail не требует рутаfirejail --dns=8.8.8.8 --noprofile --net=eth0 --ip=192.168.1.1 app-command

  • Firejail с netns : Firejail может заставить приложение использовать определенное пространство пользователя, которое было создано отдельно, это позволяет нам использовать пространства имен без rootfirejail --dns=8.8.8.8 --noprofile --netns=nameOfyourNS app-command

  • Firejail с маскарадом и мостом : Firejail может заставить приложение использовать определенный интерфейс с маскарадом iptables , это здорово и не требует root, но это требует ip_forward и может означать влияние на безопасностьfirejail --net=br0 firefox

Решение III: Linux iptables

Iptables можно использовать для этой цели, но это требует ip_forward и может подразумевать влияние на безопасность, если оно настроено неправильно, пример 1 , пример 2 , пример 3 , пример 4

Решения (I, II и III) примечания:

Wireguard

Если вы используете VPN (особенно wireguard) и хотите применить это решение к интерфейсу wireguard ( wireguard с пользовательским пространством ), вы можете следовать инструкциям по ссылке, чтобы создать пространство пользователя, содержащее интерфейс wg (и, следовательно, ограниченное интерфейсом vpn). ) также это можно сочетать с firejail --netns=containerвозможностью использования пространства пользователя без рута.

Как найти интерфейсный шлюз

Существует множество решений для поиска шлюза, здесь приведены некоторые команды, позволяющие найти используемый шлюз

$ route
$ route -n
$ ip rule list
$ ip route show
$ netstat -rn
$ cat /etc/network/interfaces
$ cat /etc/sysconfig/network-scripts/ifcfg-eth0
$ traceroute www.google.com
$ ip route show 0.0.0.0/0 dev eth0

Как использовать App-Route-Jail

  • Построить App-Route-Jail
git clone https://github.com/Intika-Linux-Network/App-Route-Jail.git
cd Approute-Utils
chown 755 make.sh
./make.sh
  • Добавление маршрута для будущих помеченных пакетов (для заключенного в тюрьму приложения) в этом примере 192.168.1.1используется в качестве принудительного шлюза, это правило маршрута не повлияет на другие приложения, например, эту манипуляцию нужно выполнять только один раз при загрузке системы, если вы хотите используйте это решение ежедневно
ip rule add fwmark 10 table 100
ip route add default via 192.168.1.1 table 100
  • Запустите приложение, которое вы хотите заключить в тюрьму
MARK=10 LD_PRELOAD=./mark.so firefox
  • Тестирование wan IP-адреса
MARK=10 LD_PRELOAD=./mark.so wget -qO- ifconfig.me
intika
источник