przekierowanie portów do aplikacji w sieciowej przestrzeni nazw za pomocą VPN

13

Byłem w stanie skonfigurować sieciową przestrzeń nazw, założyć tunel z openvpn i uruchomić aplikację, która korzysta z tego tunelu w przestrzeni nazw. Do tej pory było dobrze, ale do tej aplikacji można uzyskać dostęp za pośrednictwem interfejsu sieciowego i nie mam pojęcia, jak kierować żądania do interfejsu internetowego w mojej sieci LAN.

Postępowałem zgodnie z instrukcjami z @schnouki wyjaśniającymi, jak skonfigurować sieć nazw i uruchomić w niej OpenVPN

ip netns add myvpn
ip netns exec myvpn ip addr add 127.0.0.1/8 dev lo
ip netns exec myvpn ip link set lo up
ip link add vpn0 type veth peer name vpn1
ip link set vpn0 up
ip link set vpn1 netns myvpn up
ip addr add 10.200.200.1/24 dev vpn0
ip netns exec myvpn ip addr add 10.200.200.2/24 dev vpn1
ip netns exec myvpn ip route add default via 10.200.200.1 dev vpn1
iptables -A INPUT \! -i vpn0 -s 10.200.200.0/24 -j DROP
iptables -t nat -A POSTROUTING -s 10.200.200.0/24 -o en+ -j MASQUERADE
sysctl -q net.ipv4.ip_forward=1
mkdir -p /etc/netns/myvpn
echo 'nameserver 8.8.8.8' > /etc/netns/myvpn/resolv.conf

Następnie mogę sprawdzić mój zewnętrzny adres IP i uzyskać różne wyniki wewnątrz i na zewnątrz przestrzeni nazw, zgodnie z przeznaczeniem:

curl -s ipv4.icanhazip.com
<my-isp-ip>
ip netns exec myvpn curl -s ipv4.icanhazip.com
<my-vpn-ip>

Aplikacja została uruchomiona, używam potopu w tym przykładzie. Wypróbowałem kilka aplikacji z interfejsem internetowym, aby upewnić się, że nie jest to problem specyficzny dla potopu.

ip netns exec myvpn sudo -u <my-user> /usr/bin/deluged
ip netns exec myvpn sudo -u <my-user> /usr/bin/deluge-web -f
ps $(ip netns pids myvpn)
 PID TTY      STAT   TIME COMMAND
1468 ?        Ss     0:13 openvpn --config /etc/openvpn/myvpn/myvpn.conf
9302 ?        Sl    10:10 /usr/bin/python /usr/bin/deluged
9707 ?        S      0:37 /usr/bin/python /usr/bin/deluge-web -f

Jestem w stanie uzyskać dostęp do interfejsu sieciowego na porcie 8112 z przestrzeni nazw i z zewnątrz, jeśli podam ip veth vpn1.

ip netns exec myvpn curl -Is localhost:8112 | head -1
HTTP/1.1 200 OK
ip netns exec myvpn curl -Is 10.200.200.2:8112 | head -1
HTTP/1.1 200 OK
curl -Is 10.200.200.2:8112 | head -1
HTTP/1.1 200 OK

Ale chcę przekierować port 8112 z mojego serwera do aplikacji w przestrzeni nazw. Celem jest otwarcie przeglądarki na komputerze w mojej sieci LAN i uzyskanie interfejsu sieciowego z adresem http: // my-server-ip: 8112 (my-server-ip jest statycznym ip serwera, który utworzył instancję interfejsu sieciowego)

EDYCJA: Usunąłem moje próby tworzenia reguł iptables. To, co próbuję zrobić, zostało wyjaśnione powyżej, a następujące polecenia powinny wypisać HTTP 200:

curl -I localhost:8112
curl: (7) Failed to connect to localhost port 8112: Connection refused
curl -I <my-server-ip>:8112
curl: (7) Failed to connect to <my-server-ip> port 8112: Connection refused

Wypróbowałem reguły DNAT i SNAT i rzuciłem MASQUERADE na dobrą miarę, ale ponieważ nie wiem, co robię, moje próby są daremne. Być może ktoś może mi pomóc zmontować ten konstrukt.

EDYCJA: Wyjście tcpdump z tcpdump -nn -q tcp port 8112. Nic dziwnego, że pierwsze polecenie zwraca HTTP 200, a drugie polecenie kończy się odrzuconym połączeniem.

curl -Is 10.200.200.2:8112 | head -1
listening on vpn0, link-type EN10MB (Ethernet), capture size 262144 bytes
IP 10.200.200.1.36208 > 10.200.200.2.8112: tcp 82
IP 10.200.200.2.8112 > 10.200.200.1.36208: tcp 145

curl -Is <my-server-ip>:8112 | head -1
listening on lo, link-type EN10MB (Ethernet), capture size 262144 bytes
IP <my-server-ip>.58228 > <my-server-ip>.8112: tcp 0
IP <my-server-ip>.8112 > <my-server-ip>.58228: tcp 0

EDYCJA: Sam @schnouki wskazał mi artykuł na temat administracji Debiana, wyjaśniający ogólne proxy TCP iptables . W przypadku danego problemu ich skrypt wyglądałby następująco:

YourIP=<my-server-ip>
YourPort=8112
TargetIP=10.200.200.2
TargetPort=8112

iptables -t nat -A PREROUTING --dst $YourIP -p tcp --dport $YourPort -j DNAT \
--to-destination $TargetIP:$TargetPort
iptables -t nat -A POSTROUTING -p tcp --dst $TargetIP --dport $TargetPort -j SNAT \
--to-source $YourIP
iptables -t nat -A OUTPUT --dst $YourIP -p tcp --dport $YourPort -j DNAT \
--to-destination $TargetIP:$TargetPort

Niestety ruch między interfejsami veth został przejęty i nic więcej się nie wydarzyło. Jednak @schnouki również zasugerowało użycie socatjako proxy TCP i działa to doskonale.

curl -Is <my-server-ip>:8112 | head -1
IP 10.200.200.1.43384 > 10.200.200.2.8112: tcp 913
IP 10.200.200.2.8112 > 10.200.200.1.43384: tcp 1495

Muszę jeszcze zrozumieć dziwne tasowanie portów podczas ruchu przez interfejsy veth, ale mój problem został rozwiązany.

pskiebe
źródło
Oświadczenie: W ogóle nie mam doświadczenia z vethurządzeniami (uważam to za bardzo interesujące ... ;-)). Czy tcpdumpsprawdziłeś, jak daleko docierają pakiety przychodzące? Jeśli tcpdump -i veth0nic nie pokazuje, tcpdumo -i lomoże być konieczne.
Hauke ​​Laging
Dodałem nieokreślony wynik tcpdump
pskiebe

Odpowiedzi:

9

Zawsze miałem problemy z przekierowaniami iptables (prawdopodobnie moja wina, jestem prawie pewien, że jest to wykonalne). Ale w przypadku takim jak twój, IMO łatwiej zrobić to w krainie użytkowników bez iptables.

Zasadniczo musisz mieć demona w „domyślnym” obszarze roboczym nasłuchującym na porcie TCP 8112 i przekierowującym cały ruch do portu 10.200.200.2 8112. Jest to więc prosty serwer proxy TCP.

Oto jak to zrobić za pomocą socat :

socat tcp-listen:8112,reuseaddr,fork tcp-connect:10.200.200.2:8112

( forkOpcja jest potrzebna, aby uniknąć socatzatrzymania po zamknięciu pierwszego połączenia proxy).

EDYCJA : dodano reuseaddrzgodnie z sugestią w komentarzach.

Jeśli absolutnie chcesz to zrobić za pomocą iptables, na stronie administracji Debiana znajduje się przewodnik . Ale nadal wolę socatbardziej zaawansowane rzeczy - takie jak proxy IPv4 do IPv6 lub usuwanie SSL, aby stare programy Java mogły łączyć się z bezpiecznymi usługami ...

Uważaj jednak, że wszystkie połączenia w Potopie będą pochodzić z adresu IP twojego serwera zamiast rzeczywistego adresu IP klienta. Jeśli chcesz tego uniknąć, musisz użyć prawdziwego zwrotnego proxy HTTP, który dodaje oryginalny adres IP klienta do żądania proxy w nagłówku HTTP.

Schnouki
źródło
1
Dzięki Tobie mój dzień jest lepszy! Nigdy nie spotkałem się z tym socati już od dłuższego czasu osiąga dokładnie to, co próbowałem zrobić z iptables. Przetestowałem kilka aplikacji i wszystkie one działają bezbłędnie, łącząc się ze światem zewnętrznym przez tun0, jednocześnie zapewniając dostęp do swojego interfejsu internetowego przez veth1.
pskiebe
1
Po kilku testach dodałem reuseaddrflagę. Zapobiega to port already in usebłędom podczas szybkiego uruchamiania i zatrzymywania socat:socat -4 TCP-LISTEN:8112,reuseaddr,fork TCP:10.200.200.2:8112
pskiebe
8

Łączenie sieciowej przestrzeni nazw z główną przestrzenią nazw zawsze mi przeszkadza. Powodem, dla którego zwykle tworzę przestrzeń nazw, jest to, że chcę ją odizolować. W zależności od tego, co próbujesz osiągnąć dzięki przestrzeniom nazw, tworzenie połączeń może pokonać ten cel.

Ale nawet odizolowany, wciąż dla wygody chcę przeszukać sieć.

To rozwiązanie pozwala zachować izolację i przekazać niektóre połączenia z nią. Nie musisz tworzyć całej tej sieci między dwoma sieciowymi przestrzeniami nazw, aby przekierować jeden port. Uruchom to w przestrzeni nazw, w której chcesz akceptować połączenia. Aby działał, należy go uruchomić jako root ip netns exec.

socat tcp-listen:8112,fork,reuseaddr \
  exec:'ip netns exec myvpn socat STDIO tcp-connect\:127.0.0.1\:8112',nofork

Nasłuchuje połączeń w jednej sieciowej przestrzeni nazw, w której go uruchomisz, na porcie 8112, a następnie podłączony klient execuruchomi się, ip netns exec myvpn ...aby wykonać resztę w myvpnsieciowej przestrzeni nazw, a następnie, gdy znajdzie się w myvpnsieciowej przestrzeni nazw, ponownie utworzy drugie połączenie z innym socat.

AnyDev
źródło
działa jak urok
przybliżeniu
Ponieważ nie mam zbyt dużego doświadczenia z administrowaniem linuksem i dowiedziałem się o tym trochę czasu: upewnij się, że nie wpisałeś obu :znaków w cudzysłowie, bo możesz napotkać błąd ... wrong number of parameters (2 instead of 1)(2 lub 3). W przeciwnym razie: działa świetnie! Ogromne dziękuję!
Igor
2

Dla potopu oto moje rozwiązanie. Nie ma potrzeby korzystania z iptables. Oto kroki:

  1. Uruchom tunel openvpn
  2. Utwórz przestrzeń nazw i przenieś tam swój tunel openvpn:
ip netns dodaj $ NS
# Poczekaj, aż pojawi się TUN
while [[$ (ip route | grep $ TUN | wc -l) == 0]]; śpij 1; gotowy
MY_IP = $ (adres ip pokaż $ TUN | grep inet | cut -d '' -f6 | cut -d '/' -f1)
# Sposób wyodrębnienia adresu IP bramy może być inny dla połączenia openvpn
GATEWAY_IP = $ MY_IP
# uwięź mój $ TUN (interfejs VPN) w przestrzeni nazw
zestaw linków ip $ TUN netns $ NS
# Uruchom interfejs z podsiecią (odpowiednik tego, który dostałem od serwera VPN)
ip netns exec $ NS ifconfig $ TUN $ MY_IP / 24 w górę
# Wywołaj pętlę zwrotną
ip netns exec $ NS ifconfig lo 127.0.0.1/8 w górę
# Skonfiguruj zdalną bramę (Twój punkt IP VPN punktu)
ip netns exec $ NS route dodaj domyślny gw $ GATEWAY_IP
  1. Nawiąż połączenie między domyślną przestrzenią nazw a utworzoną:
# Skonfiguruj interfejsy veth do komunikacji między przestrzeniami nazw
ip link dodaj veth0 wpisz veth peer name veth1
# Przenieś drugi veth do swojej przestrzeni nazw
zestaw linków ip veth1 netns $ NS
# podaj pierwszy adres IP z nieużywanego zakresu adresów IP
ifconfig veth0 10.1.1.1/24 w górę
# I drugi
ip netns exec $ NS ifconfig veth1 10.1.1.2/24 w górę
# DO ZROBIENIA: skonfiguruj pomost między veth1 a interfejsem eth, aby umożliwić komunikację z siecią LAN
# Skonfiguruj klienta DNS. ip netns będzie emulować /etc/resolv.conf przy użyciu tego pliku:
mkdir -p / etc / netns / $ NS
echo "nameserver 8.8.4.4"> /etc/netns/$NS/resolv.conf
  1. Uruchom swój wykopany w $ NS i swój sieć potopu w domyślnej przestrzeni nazw. Wskaż sieć-potop na adres IP 10.1.1.2 veth, gdzie opóźniony będzie nasłuchiwał jego połączenia.

Voila! Masz zabezpieczone za VPN, podczas gdy twoja sieć powodziowa jest swobodnie dostępna w sieci domowej

Vlad
źródło
2

Odpowiedź @ AndrDevEK jest przydatna. Aby to rozwinąć, możesz nie chcieć instalować socat. W takim przypadku możesz osiągnąć to samo przy nieco zawiłej konfiguracji przekierowania portów SSH. W szczególności przydatna jest tutaj funkcja przekierowywania portów do / z gniazda domeny unix, ponieważ gniazda domeny unix działają niezależnie od sieciowych nazw:

sudo ip netns exec myvpn su -c "ssh -N -L /tmp/myunixsock:localhost:8112 localhost" $USER &
ssh_pid1=$!
ssh -N -L localhost:8112:/tmp/myunixsock localhost &
ssh_pid2=$!

Sprzątać:

sudo kill $ssh_pid1
kill $ssh_pid2
rm /tmp/myunixsock

Pierwszy ssh -N -Ljest uruchamiany w przestrzeni nazw myvpn. To tworzy gniazdo domeny unix /tmp/myunixsocki nasłuchuje na nim. Połączenia przychodzące są przekazywane do localhost: 8112 (w przestrzeni nazw myvpn). Drugi ssh -N -Ljest uruchamiany w domyślnej przestrzeni nazw. Spowoduje to utworzenie nasłuchującego portu TCP i przekazywanie połączeń przychodzących do gniazda domeny unix.

Należy zauważyć, że aby to zadziałało, sshwewnątrz twojej sieciowej przestrzeni nazw będzie musiała działać, jeśli jeszcze nie jest (a operacja klucza publicznego bez hasła jest pomocna):

sudo ip netns exec myvpn ip link set up dev lo
sudo ip netns exec myvpn /usr/sbin/sshd -o PidFile=/run/sshd-myvpn.pid
ssh-copy-id localhost
Cyfrowa trauma
źródło