Kieruj ruchem przez określony interfejs dla procesu w systemie Linux

20

Czy możliwe jest kierowanie ruchu używanego przez proces przez określony interfejs?

Na przykład ruch sieciowy przez aplikację do pobierania powinien zawsze korzystać z interfejsu, wlan0podczas gdy wszystkie inne aplikacje na komputerze powinny korzystać eth0.

Czy w Linuksie można mieć tego rodzaju reguły?

Suresh
źródło

Odpowiedzi:

22

Można to zrobić za pomocą Linux Namespaces.

Oto artykuł, który wyjaśnia, jak to zrobić. Zasadniczo tworzysz przestrzeń nazw sieci z inną domyślną trasą i uruchamiasz tam procesy, które jej potrzebują. Połączysz nowo utworzoną przestrzeń nazw sieci z fizycznym adapterem za pomocą mostka (ale oczywiście możliwe są również inne rozwiązania).

Aktualizacja: z jądra 3.14 korzystanie z grup kontrolnych jest jeszcze łatwiejsze, jak opisano w tym artykule . Musisz:

1) zdefiniuj grupę kontrolną net_cls, aby opisać pakiety z danego procesu za pomocą classid (lub grupy procesów, zauważ, że nie musi istnieć żadna relacja rodzic-dziecko)

2) użyj modułu cgroup iptables (dodanego w Linuksie 3.14), aby zaznaczyć pakiety

3) użyj routingu zasad (reguła ip dodaj fwmark ....), aby utworzyć nową tabelę routingu dla zaznaczonych pakietów

Zaletą jest to, że nie musimy robić pomostów, a wszystko jest znacznie bardziej dynamiczne dzięki grupom.

Chripell
źródło
14

Tak bardzo się z tym zmagałem, więc oto ZUPEŁNE rozwiązanie. Jest testowany na Ubuntu 15 i 16. Możesz go szczególnie używać z OpenVPN do kierowania niektórymi aplikacjami poza interfejs tunelu VPN.

Kompletne rozwiązanie „cgroup”

Jak to działa

  • Jądro Linux umieści aplikację w grupie kontrolnej . Ruch sieciowy z aplikacji w tej grupie będzie identyfikowany na podstawie identyfikatora klasy na poziomie kontrolera sieci.
  • iptables oznaczy ten ruch i zmusi go do wyjścia z właściwym adresem IP
  • Trasa ip przetworzy zaznaczony ruch w innej tabeli routingu, z domyślną trasą do dowolnego adresu IP bramy.

Zautomatyzowany skrypt

Zrobiłem novpn.sh skrypt do automatyzacji zależności zainstalować i uruchomić. Testowane na Ubuntu.

Najpierw uruchom 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

Podręcznik HowTo

Najpierw zainstaluj obsługę i narzędzia cgroup:

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

Uruchom ponownie (może nie być konieczne).

Potrzebujesz iptables 1.6 .0+. Pobierz źródło wydania iptables 1.6.0 , rozpakuj je, a następnie uruchom to ( --disable-nftablesflaga pozwoli uniknąć błędów) ze źródła 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

Teraz prawdziwa konfiguracja. Zdefiniuj grupę kontrolną o nazwie novpn. Procesy w tej grupie będą miały klasę 0x00110011(11:11).

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

Załóżmy, że interfejs, którego chcesz używać dla konkretnej aplikacji, ma eth0adres IP bramy 10.0.0.1. Zastąp je tym, czego naprawdę chcesz (uzyskaj informacje ip route). Uruchom nadal jako 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

Na koniec uruchom aplikację na określonym interfejsie:

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

Lub jeśli chcesz przenieść już działający proces do grupy, cóż ... nie możesz! Wydaje się, że wynika to z funkcji NAT (maskarady): iptables -nvL -t natnie pasuje, gdy cgroup jest przełączana, ale iptables -nvL -t manglepasuje.

# 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

Kredyty: Żadna odpowiedź nie działała zgodnie z oczekiwaniami, ale ich kombinacja działała: artykuł chripell odpowiedz evolware Na routing procesu weź 2: używając grup dyskusyjnych, iptables i routingu polityki , Jak wykonać konkretny proces, NIE przechodząc przez połączenie OpenVPN? , Przełącznik Kill dla OpenVPN na podstawie iptables

KrisWebDev
źródło
Dzięki za świetną odpowiedź, jak sprawić, by działała z Apache? Próbowałem cgexec -g net_cls:novpn apache2i podałem całą listę zmiennych niezdefiniowanych błędów!
razzak
2
Te same błędy otrzymasz, uruchamiając apache2bezpośrednio z terminala. To dlatego, że apache2zwykle jest uruchamiany jako usługa, z systemctl start apache2. Jednak to nie zadziała cgexec. apache2Wywoływany program musi być rodzicem żądanego procesu ( ), aby grupa c_grupy net_cls mogła się rozprzestrzeniać. Musisz więc znaleźć skrypt uruchamiania. W tym przypadku tak jest sudo cgexec -g net_cls:novpn /usr/sbin/apache2ctl start. Sprawdź za pomocą ./novpn.sh --list.
KrisWebDev,
To już nie działa w Ubuntu 16.04!
razzak
2
Używam go na Ubuntu 16.04 i działa dobrze. Nazwy interfejsów zmieniły się w Ubuntu 16, być może trzeba wymienić eth0na coś podobnego enp7s0. Uzyskaj informacje z ifconfigpolecenia.
KrisWebDev
Dziękuję Ci. Ale to nie działa na Ubuntu 18.04, ponieważ cpmanager został usunięty z powodu konfliktu z systemd
skonsoft
3

Łącząc doskonałe odpowiedzi mariusmatutiae i KrisWebDev stworzyłem znacznie zmodyfikowaną wersję doskonałego novpn.shskryptu KrisWebDev . Podczas gdy skrypt KrisWebDev jest zaprojektowany do drapania bardziej specyficznego swędzenia (uruchamianie i przenoszenie procesów wewnątrz / na zewnątrz VPN), moja wersja pozwala na uruchomienie dowolnego polecenia w określonym przez ciebie środowisku sieciowym. Możesz określić interfejs, z którym chcesz się połączyć, domyślną trasę, określić własne reguły iptables, trasy statyczne, określić „test”, aby potwierdzić, że wszystko działa tak, jak chcesz przed uruchomieniem polecenia ... itd.). Pozwala na użycie wielu plików konfiguracyjnych, dzięki czemu można zdefiniować dowolną liczbę określonych środowisk sieciowych, w których można uruchamiać polecenia / procesy wewnątrz.

Opublikowałem to jako sedno tutaj: https://gist.github.com/level323/54a921216f0baaa163127d960bfebbf0

Może nawet później wyczyścić tabele cgroup / iptables / routing!

Witamy mile widziane.

PS - Jest przeznaczony dla Debian 8 (Jessie)

wszystko naturalne
źródło
Cześć @allnatural, Chciałbym użyć skryptu altnetworking.sh, ale co mam umieścić w pliku konfiguracyjnym?
Cris70
0

Nie na aplikację, nie. Możesz to zrobić dla każdego portu lub adresu IP itp., Lub sama aplikacja może powiązać (i użyć) określoną kartę sieciową.

Nie można jednak ustawić reguły, aby to zrobić.

Majenko
źródło
Mam aplikację Java, czy można powiązać tę aplikację z interfejsem?
Suresh
Aplikacja Java, dla której masz kod źródłowy i którą możesz przeprogramować elementy wewnętrzne?
Majenko,
Mam kod źródłowy aplikacji Java, który korzysta z biblioteki HTTP Apache.
Suresh
Następnie przejdę na stronę stackoverflow.com i zapytam programistów, jak zmienić twój program. Nigdy nie programowałem w Javie.
Majenko,