Powiąż program unix z określonym interfejsem sieciowym

40

Pytanie: Jak uruchomić program, upewniając się, że jego dostęp do sieci jest ograniczony przez określony interfejs sieciowy?

Przypadek: Chcę uzyskać dostęp do dwóch różnych komputerów o tym samym adresie IP (192.168.1.1), ale dostępnych za pośrednictwem dwóch różnych interfejsów sieciowych (eth1 i eth2).

Przykład:

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

Powyższe jest przybliżeniem tego, co chciałbym, zainspirowane wiązaniem sprzętowym wykonanym za pomocą primusrun i optirun .

Wyzwanie: Jak sugerowano w powiązanym wątku , używane interfejsy nie są wybierane przez program, lecz przez jądro (stąd powyższa składnia wstępnego wiązania).

Znalazłem kilka powiązanych rozwiązań, które są niezadowalające. Opierają się na powiązaniu interfejsów sieciowych za pośrednictwem czarnej listy sieci specyficznej dla użytkownika; tj. uruchomienie procesu jako użytkownik, który może uzyskać dostęp tylko do jednego określonego interfejsu sieciowego.

Skeen
źródło
Czy sugerujesz, że twoje urządzenie jest podłączone do dwóch różnych sieci, obie 192.168.1.0? Jak wygląda twoja tabela routingu? Jeśli chcesz ograniczyć interfejsy widoczne z procesu, najlżejszym rozwiązaniem byłyby grupy, cięższe pojemniki.
lgeorget
Tak, dwie różne sieci, obie w tym samym zakresie IP. Nie jestem pewien, czy nie chcę ograniczać widocznych interfejsów, po prostu dyktować, który z nich ma być domyślny? :)
Skeen
3
To, o co pytasz, jest trudne z jednego dobrego powodu: połączenie dwóch sieci za pomocą tej samej domeny IP jest jak posiadanie windy w budynku z dwoma piętrami o tym samym numerze. Zakres adresów IP określa domenę, a nie interfejs wyjściowy. Niemniej jednak musi istnieć sposób obejścia wadliwego projektu sieci za pomocą iptables.
lgeorget
Łączę mój system z dwiema różnymi infrastrukturami lokalnymi, ponieważ takie infrastruktury nigdy nie zostały zaprojektowane do współdziałania, a zatem projekt sieci jest wadliwy pod tym względem.
Skeen
1
Mój argument przeciwko NAT był taki, że całe przestrzenie adresowe są zwykle ukryte za NATem, a kiedy łączę dwie infrastruktury NAT'owane, dochodzi do kolizji. - Nie jestem w stanie modyfikować infrastruktury. - Próbowałem użyć sieciowych nazw z parami wirtualnych interfejsów sieciowych (jedna w przestrzeni nazw, druga w głównej przestrzeni nazw), łącząc główną przestrzeń nazw z interfejsem fizycznym i uruchamiając programy w sieciowej przestrzeni nazw. - Wygląda na to, że działa, ale nie uzyskuję dostępu poza główną przestrzenią nazw (tj. Brak dostępu poza samą maszyną).
Skeen

Odpowiedzi:

35

W przypadku systemu Linux odpowiedź ta została już udzielona w Superuser - jak używać różnych interfejsów sieciowych dla różnych procesów? .

Najpopularniejsza odpowiedź wykorzystuje LD_PRELOADsztuczkę, aby zmienić powiązanie sieciowe dla programu, ale współczesne jądra obsługują znacznie bardziej elastyczną funkcję zwaną „sieciowymi przestrzeniami nazw”, która jest ujawniana przez ipprogram. Ta odpowiedź pokazuje, jak tego użyć. Z moich własnych eksperymentów zrobiłem następujące (jako 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

Możliwe jest również do pewnego stopnia zarządzanie sieciowymi przestrzeniami nazw za pomocą poleceń unsharei nsenter. Pozwala to również tworzyć osobne przestrzenie dla PID, użytkowników i punktów montowania. Aby uzyskać więcej informacji, zobacz:

Graeme
źródło
„po tym punkcie eth0 nie jest użyteczny przez programy spoza przestrzeni nazw” - Więc przerywam połączenie dla wszystkich innych problemów z tym związanych?
Skeen
1
@Skeen, tak, więc prawdopodobnie wcisnąłbyś interfejs, którego nie używają żadne inne programy, w przestrzeń nazw i normalnie używasz swojego głównego.
Graeme
1
@Graerne; Oba interfejsy są aktywnie wykorzystywane; Nie mogę sobie pozwolić na usunięcie interfejsów.
Skeen
a co z domyślną bramą? wvdialna przykład w ogóle go nie konfiguruje ... więc należy go zdefiniować w samej przestrzeni nazw
Flash Thunder
Czy możesz podać instrukcje, jak to cofnąć? Czy chcesz po prostu ip netns remove test_nswrócić do normy? A może musisz zrobić coś specjalnego?
Multihunter
17

Przyjmuję odpowiedź Graeme; jest to po prostu kontynuacja wyjaśniająca zmiany, które wprowadziłem w jego sugestii rozwiązania mojego problemu.

Zamiast wiązania fizycznego interfejsu w przestrzeni nazw, stworzyłem parę wirtualnych interfejsów sieciowych, z jednym końcem w przestrzeni nazw sieci i jednym w katalogu głównym. Paczki są następnie kierowane przez tę sieć wirtualną z przestrzeni nazw, do głównej przestrzeni nazw, a następnie do interfejsu fizycznego. - Jako taki jestem w stanie uruchomić wszystkie moje zwykłe transfery danych, a ponadto uruchomić procesy, które mają dostęp tylko do określonego interfejsu.

# 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}}

Po skonfigurowaniu interfejsów dla eth0 i eth1, z ich odpowiednimi przestrzeniami nazw eth0_ns i eth1_ns, programy mogą być uruchamiane na określonym interfejsie poprzez;

ip netns exec eth0_ns fish
ip netns exec eth1_ns fish
Skeen
źródło
4
Dobra robota! Myślę, że możesz także utworzyć urządzenie mostkowe i zmostkować domyślną przestrzeń nazw i wirtualną parę z jednym z fizycznych urządzeń. Wygląda to jednak równorzędnie.
Graeme,
1
Próbowałem zmostkować wirtualne i fizyczne urządzenie; Nie mogłem połączyć się z siecią zewnętrzną za pomocą tego rozwiązania.
Skeen
2
Tak, ale tylko z nowej przestrzeni nazw. Wydaje mi się, że problem, który miałem, był związany z menedżerem sieci, jednak tego nie rozgryzłem lub zaktualizowałbym odpowiedź.
Graeme
Mam ten sam problem, ale nie udało mi się użyć tego rozwiązania. Co dokładnie powinienem wpisać w {{ROUTE_SOURCE}} i {{ROUTE_TARGET}} w ostatnim kroku?
litov
@Graeme, przynajmniej na Ubuntu udało mi się uzyskać łączność z powrotem zarówno w przestrzeni nazw, jak i globalnej przestrzeni nazw wydając dhclient <bridge>za tutaj .
Chris Hunt
4

Rozwiązanie I: Wstępne ładowanie określonej biblioteki

  • App-Route-Jail : użyj ld_preload, aby wymusić bramę interfejsu (świetny pomysł, ale wymaga możliwości rootowania lub zaznaczania). Szczegółowe informacje na ten temat znajdują się poniżej.

  • Proxybound : użyj ld_preload, aby wymusić proxy dla określonej aplikacji (używa proxy zamiast interfejsu)

  • Force-Bind : ma wiele funkcji, ale wiązanie przecieka (nie jest wiarygodne)

  • Bind-Interface-IP : zbyt proste i nieszczelne połączenia (nie są niezawodne)

  • Bind-IP : zbyt proste i nieszczelne połączenia (nie są niezawodne)

Rozwiązanie II: Przestrzeń użytkownika systemu Linux

  • Klasyczna przestrzeń użytkownika Linux -a ip-netns : świetne rozwiązanie, ale wymaga rootowania, a interfejs może istnieć tylko na jednej przestrzeni użytkownika

  • Firejail : Firejail może zmusić aplikację do korzystania z określonej sieci, ale kompatybilność jest ograniczona (na przykład nie jest kompatybilna z interfejsami tun). Firejail nie wymaga rootowaniafirejail --dns=8.8.8.8 --noprofile --net=eth0 --ip=192.168.1.1 app-command

  • Firejail z netns : Firejail może zmusić aplikację do korzystania z określonej przestrzeni użytkownika, która została utworzona osobno, pozwala to nazwać przestrzenie bez katalogu głównegofirejail --dns=8.8.8.8 --noprofile --netns=nameOfyourNS app-command

  • Firejail z maskaradą i mostem : Firejail może zmusić aplikację do używania określonego interfejsu z maskaradą iptables , jest to świetne i nie wymaga rootowania, ale wymaga ip_forward i może sugerować wpływ na bezpieczeństwofirejail --net=br0 firefox

Rozwiązanie III: Linux iptables

Do tego celu można użyć Iptables, ale wymaga to ip_forward i może implikować wpływ na bezpieczeństwo, jeśli nie jest poprawnie skonfigurowany, przykład 1 , przykład 2 , przykład 3 , przykład 4

Uwagi dotyczące rozwiązań (I, II i III):

Wireguard

Jeśli korzystasz z VPN (zwłaszcza Wireguard) i chcesz zastosować to rozwiązanie do interfejsu Wireguard ( Wireguard z przestrzenią użytkownika ), możesz postępować zgodnie z instrukcjami, aby utworzyć przestrzeń użytkownika zawierającą interfejs wg (a zatem ograniczony do interfejsu VPN ) można to również połączyć z firejail --netns=containermożliwością korzystania z przestrzeni użytkownika bez uprawnień użytkownika root.

Jak znaleźć bramę interfejsu

Istnieje wiele rozwiązań, aby znaleźć bramę tutaj są niektóre polecenia, które pozwalają znaleźć używaną bramę

$ 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

Jak korzystać z App-Route-Jail

  • Zbuduj App-Route-Jail
git clone https://github.com/Intika-Linux-Network/App-Route-Jail.git
cd Approute-Utils
chown 755 make.sh
./make.sh
  • Dodaj trasę dla przyszłych oznaczonych pakietów (dla aplikacji uwięzionej) w tym przykładzie 192.168.1.1jest używana jako brama wymuszona, ta reguła trasy nie wpłynie na inne aplikacje, ta manipulacja musi być wykonana tylko raz przy rozruchu systemu, na przykład jeśli chcesz używaj tego rozwiązania codziennie
ip rule add fwmark 10 table 100
ip route add default via 192.168.1.1 table 100
  • Uruchom aplikację, którą chcesz więzić
MARK=10 LD_PRELOAD=./mark.so firefox
  • Testowanie adresu IP wan
MARK=10 LD_PRELOAD=./mark.so wget -qO- ifconfig.me
intika
źródło