Co mówimy Bogu IPv6?

Zgadza się, dzisiaj powiemy to samo bogu szyfrowania.
Tutaj będziemy mówić o niezaszyfrowanym tunelu IPv4, ale nie o tunelu z „ciepłą lampą”, ale o nowoczesnym tunelu „LED”. I tu też flashują surowe gniazda, i trwają prace z pakietami w przestrzeni użytkownika.
Istnieje N protokołów tunelowania dla każdego smaku i koloru:
- stylowy, modny, młodzieżowy
- wielofunkcyjne, takie jak noże szwajcarskie, OpenVPN i SSH
- stary i niezły GRE
- najprostszy, najszybszy, całkowicie niezaszyfrowany protokół IPIP
- aktywnie się rozwija
- wiele innych.
Ale jestem programistą, więc zwiększę N tylko o ułamek, a rozwój prawdziwych protokołów pozostawię programistom Kommersant.
W jednym nienarodzonym Teraz zajmuję się docieraniem z zewnątrz do hostów korzystających z NAT. Wykorzystując do tego protokoły z kryptografią dla dorosłych, nie mogłem oprzeć się wrażeniu, że to było jak strzelanie do wróbli z armaty. Ponieważ tunel jest używany w większości tylko do robienia dziur w NAT-e, ruch wewnętrzny jest zwykle również szyfrowany, ale nadal tonie w HTTPS.
Badając różne protokoły tunelowania, uwagę mojego wewnętrznego perfekcjonisty raz po raz zwracano na protokół IPIP ze względu na jego minimalny narzut. Ale ma półtora istotne wady dla moich zadań:
- wymaga publicznych adresów IP po obu stronach,
- i nie ma żadnego uwierzytelnienia dla Ciebie.
Dlatego perfekcjonista został zepchnięty z powrotem w ciemny kąt czaszki lub gdziekolwiek tam siedzi.
A potem pewnego dnia, czytając artykuły na temat w Linuksie natknąłem się na FOU (Foo-over-UDP), czyli tzw. cokolwiek, zapakowane w UDP. Jak dotąd obsługiwane są tylko protokoły IPIP i GUE (Generic UDP Encapsulation).
„Oto złoty środek! Mi wystarczy prosty IPIP.” - Myślałem.
W rzeczywistości kula okazała się nie całkowicie srebrna. Enkapsulacja w UDP rozwiązuje pierwszy problem - z klientami za NATem można się łączyć z zewnątrz za pomocą wcześniej ustalonego połączenia, ale tutaj połowa kolejnej wady IPIP kwitnie w nowym świetle - każdy z sieci prywatnej może ukryć się za widzialnym publiczny adres IP i port klienta (w czystym IPIP ten problem nie występuje).
Aby rozwiązać ten półtora problemu, narodziło się narzędzie . Implementuje domowy mechanizm uwierzytelniania zdalnego hosta, bez zakłócania pracy jądra FOU, który szybko i sprawnie będzie przetwarzał pakiety w przestrzeni jądra.
Nie potrzebujemy Twojego scenariusza!
Ok, jeśli znasz publiczny port i adres IP klienta (na przykład wszyscy za nim nigdzie nie idą, NAT próbuje mapować porty 1 w 1), możesz utworzyć tunel IPIP-over-FOU za pomocą następujące polecenia, bez żadnych skryptów.
na serwerze:
# Подгрузить модуль ядра FOU
modprobe fou
# Создать IPIP туннель с инкапсуляцией в FOU.
# Модуль ipip подгрузится автоматически.
ip link add name ipipou0 type ipip
remote 198.51.100.2 local 203.0.113.1
encap fou encap-sport 10000 encap-dport 20001
mode ipip dev eth0
# Добавить порт на котором будет слушать FOU для этого туннеля
ip fou add port 10000 ipproto 4 local 203.0.113.1 dev eth0
# Назначить IP адрес туннелю
ip address add 172.28.0.0 peer 172.28.0.1 dev ipipou0
# Поднять туннель
ip link set ipipou0 up
na kliencie:
modprobe fou
ip link add name ipipou1 type ipip
remote 203.0.113.1 local 192.168.0.2
encap fou encap-sport 10001 encap-dport 10000 encap-csum
mode ipip dev eth0
# Опции local, peer, peer_port, dev могут не поддерживаться старыми ядрами, можно их опустить.
# peer и peer_port используются для создания соединения сразу при создании FOU-listener-а.
ip fou add port 10001 ipproto 4 local 192.168.0.2 peer 203.0.113.1 peer_port 10000 dev eth0
ip address add 172.28.0.1 peer 172.28.0.0 dev ipipou1
ip link set ipipou1 up
gdzie
ipipou*— nazwa lokalnego interfejsu sieciowego tunelu203.0.113.1— publiczny serwer IP198.51.100.2— publiczny adres IP klienta192.168.0.2— adres IP klienta przypisany do interfejsu eth010001— lokalny port klienta dla FOU20001— publiczny port klienta dla FOU10000— publiczny port serwera dla FOUencap-csum— możliwość dodania sumy kontrolnej UDP do kapsułkowanych pakietów UDP; można zastąpićnoencap-csumnie wspominając, że integralność jest już kontrolowana przez zewnętrzną warstwę enkapsulacji (kiedy pakiet znajduje się wewnątrz tunelu)eth0— interfejs lokalny, z którym będzie powiązany tunel ipip172.28.0.1— IP interfejsu tunelu klienta (prywatny)172.28.0.0— Interfejs serwera tunelu IP (prywatny)
Dopóki połączenie UDP będzie aktywne, tunel będzie działał, ale jeśli się zepsuje, będziesz miał szczęście - jeśli adres IP klienta: port pozostanie taki sam - będzie działał, jeśli się zmienią - zepsuje się.
Najprostszym sposobem, aby wszystko odwrócić, jest wyładowanie modułów jądra: modprobe -r fou ipip
Nawet jeśli uwierzytelnianie nie jest wymagane, publiczny adres IP i port klienta nie zawsze są znane i często są nieprzewidywalne lub zmienne (w zależności od typu NAT). Jeśli pominiesz encap-dport po stronie serwera tunel nie będzie działał, nie jest wystarczająco inteligentny, aby zająć port połączenia zdalnego. W tym przypadku ipipou może również pomóc lub WireGuard i inne podobne mogą Ci pomóc.
Jak to działa?
Klient (zwykle znajdujący się za NATem) otwiera tunel (jak w powyższym przykładzie) i wysyła pakiet uwierzytelniający do serwera, aby ten skonfigurował tunel po swojej stronie. W zależności od ustawień może to być pusty pakiet (tylko po to, aby serwer mógł zobaczyć publiczny adres IP: port połączenia) lub z danymi, dzięki którym serwer może zidentyfikować klienta. Dane mogą mieć postać prostego hasła zapisanego w postaci zwykłego tekstu (przychodzi na myśl analogia z HTTP Basic Auth) lub specjalnie zaprojektowanych danych podpisanych kluczem prywatnym (podobnie jak HTTP Digest Auth tylko mocniej, patrz funkcja client_auth w kodzie).
Na serwerze (strona z publicznym adresem IP) po uruchomieniu ipipou tworzy procedurę obsługi kolejki nfqueue i konfiguruje netfilter tak, aby niezbędne pakiety były wysyłane tam, gdzie powinny być: pakiety inicjujące połączenie z kolejką nfqueue i [prawie] cała reszta trafia bezpośrednio do FOU słuchacza.
Dla niewtajemniczonych, nfqueue (lub NetfilterQueue) to specjalna rzecz dla amatorów, którzy nie wiedzą, jak tworzyć moduły jądra, które za pomocą netfilter (nftables/iptables) pozwalają przekierowywać pakiety sieciowe do przestrzeni użytkownika i tam je przetwarzać za pomocą prymitywne środki pod ręką: zmodyfikuj (opcjonalnie) i oddaj je jądru lub odrzuć.
Dla niektórych języków programowania istnieją powiązania do pracy z nfqueue, dla basha nie było żadnych (heh, nic dziwnego), musiałem użyć Pythona: ipipou używa .
Jeśli wydajność nie jest krytyczna, za pomocą tej rzeczy możesz stosunkowo szybko i łatwo wymyślić własną logikę pracy z pakietami na dość niskim poziomie, na przykład stworzyć eksperymentalne protokoły przesyłania danych lub trollować lokalne i zdalne usługi za pomocą niestandardowego zachowania.
Surowe gniazda współpracują z nfqueue, np. gdy tunel jest już skonfigurowany i FOU nasłuchuje na żądanym porcie, nie będziesz mógł w zwykły sposób wysłać pakietu z tego samego portu - jest zajęty, ale możesz pobrać i wysłać losowo wygenerowany pakiet bezpośrednio do interfejsu sieciowego za pomocą surowego gniazda, chociaż wygenerowanie takiego pakietu będzie wymagało nieco więcej majsterkowania. Tak powstają pakiety z uwierzytelnianiem w ipipou.
Ponieważ ipipou przetwarza tylko pierwsze pakiety z połączenia (oraz te, którym udało się przedostać do kolejki przed nawiązaniem połączenia), wydajność prawie nie spada.
Gdy tylko serwer ipipou odbierze uwierzytelniony pakiet, tworzony jest tunel i wszystkie kolejne pakiety w połączeniu są już przetwarzane przez jądro z pominięciem nfqueue. Jeżeli połączenie się nie powiedzie, to do kolejki nfqueue zostanie wysłany pierwszy pakiet następnego, w zależności od ustawień, jeśli nie jest to pakiet z uwierzytelnianiem, ale z ostatniego zapamiętanego adresu IP i portu klienta, można go albo przekazać włączone lub wyrzucone. Jeśli uwierzytelniony pakiet pochodzi z nowego adresu IP i nowego portu, tunel jest ponownie konfigurowany tak, aby z nich korzystał.
Zwykły IPIP-over-FOU ma jeszcze jeden problem podczas pracy z NAT - nie da się utworzyć dwóch tuneli IPIP enkapsulowanych w UDP z tym samym IP, ponieważ moduły FOU i IPIP są od siebie dość odizolowane. Te. para klientów korzystających z tego samego publicznego adresu IP nie będzie mogła w ten sposób jednocześnie połączyć się z tym samym serwerem. W przyszłości, , zostanie to rozwiązane na poziomie jądra, ale nie jest to pewne. W międzyczasie problemy z NAT można rozwiązać za pomocą NAT - jeśli zdarzy się, że para adresów IP jest już zajęta przez inny tunel, ipipou wykona NAT z publicznego na alternatywny prywatny adres IP, voila! - możesz tworzyć tunele aż do wyczerpania się portów.
Ponieważ Nie wszystkie pakiety w połączeniu są podpisane, wówczas ta prosta ochrona jest podatna na MITM, więc jeśli na ścieżce między klientem a serwerem czai się złoczyńca, który może podsłuchiwać ruch i nim manipulować, może przekierować uwierzytelnione pakiety przez inny adres i utwórz tunel z niezaufanego hosta.
Jeśli ktoś ma pomysł, jak rozwiązać ten problem, pozostawiając większość ruchu w rdzeniu, nie wahaj się zabrać głosu.
Nawiasem mówiąc, enkapsulacja w UDP sprawdziła się bardzo dobrze. W porównaniu z enkapsulacją przez IP jest ona znacznie stabilniejsza i często szybsza pomimo dodatkowego obciążenia nagłówka UDP. Wynika to z faktu, że większość hostów w Internecie działa dobrze tylko z trzema najpopularniejszymi protokołami: TCP, UDP, ICMP. Część materialna może całkowicie odrzucić wszystko inne lub przetwarzać ją wolniej, ponieważ jest zoptymalizowana tylko pod kątem tych trzech.
Na przykład dlatego QUICK, na którym opiera się HTTP/3, został stworzony na bazie UDP, a nie na IP.
No cóż, dość słów, czas zobaczyć, jak to działa w „realu”.
Bitwa
Używany do emulacji prawdziwego świata iperf3. Pod względem stopnia zbliżenia do rzeczywistości jest to mniej więcej tyle samo, co emulowanie prawdziwego świata w Minecrafcie, ale na razie wystarczy.
Uczestnicy konkursu:
- referencyjny główny kanał
- bohaterem tego artykułu jest ipipou
- OpenVPN z uwierzytelnianiem, ale bez szyfrowania
- OpenVPN w trybie all-inclusive
- WireGuard bez PresharedKey, z MTU = 1440 (tylko dla IPv4)
Dane techniczne dla maniaków
Metryki są pobierane za pomocą następujących poleceń:
na kliencie:
UDP
CPULOG=NAME.udp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -c SERVER_IP -4 -t 60 -f m -i 10 -B LOCAL_IP -P 2 -u -b 12M; tail -1 "$CPULOG"
# Где "-b 12M" это пропускная способность основного канала, делённая на число потоков "-P", чтобы лишние пакеты не плодить и не портить производительность.
TCP
CPULOG=NAME.tcp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -c SERVER_IP -4 -t 60 -f m -i 10 -B LOCAL_IP -P 2; tail -1 "$CPULOG"
Opóźnienie ICMP
ping -c 10 SERVER_IP | tail -1
na serwerze (działa jednocześnie z klientem):
UDP
CPULOG=NAME.udp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -s -i 10 -f m -1; tail -1 "$CPULOG"
TCP
CPULOG=NAME.tcp.cpu.log; sar 10 6 >"$CPULOG" & iperf3 -s -i 10 -f m -1; tail -1 "$CPULOG"
Konfiguracja tunelu
ipipou
Serwer
/etc/ipipou/server.conf:
server
number 0
fou-dev eth0
fou-local-port 10000
tunl-ip 172.28.0.0
auth-remote-pubkey-b64 eQYNhD/Xwl6Zaq+z3QXDzNI77x8CEKqY1n5kt9bKeEI=
auth-secret topsecret
auth-lifetime 3600
reply-on-auth-ok
verb 3
systemctl start ipipou@server
klient
/etc/ipipou/client.conf:
client
number 0
fou-local @eth0
fou-remote SERVER_IP:10000
tunl-ip 172.28.0.1
# pubkey of auth-key-b64: eQYNhD/Xwl6Zaq+z3QXDzNI77x8CEKqY1n5kt9bKeEI=
auth-key-b64 RuBZkT23na2Q4QH1xfmZCfRgSgPt5s362UPAFbecTso=
auth-secret topsecret
keepalive 27
verb 3
systemctl start ipipou@client
openvpn (bez szyfrowania, z uwierzytelnianiem)
Serwer
openvpn --genkey --secret ovpn.key # Затем надо передать ovpn.key клиенту
openvpn --dev tun1 --local SERVER_IP --port 2000 --ifconfig 172.16.17.1 172.16.17.2 --cipher none --auth SHA1 --ncp-disable --secret ovpn.key
klient
openvpn --dev tun1 --local LOCAL_IP --remote SERVER_IP --port 2000 --ifconfig 172.16.17.2 172.16.17.1 --cipher none --auth SHA1 --ncp-disable --secret ovpn.key
openvpn (z szyfrowaniem, uwierzytelnianiem, przez UDP, wszystko zgodnie z oczekiwaniami)
Skonfigurowany za pomocą
osłona drutu
Serwer
/etc/wireguard/server.conf:
[Interface]
Address=172.31.192.1/18
ListenPort=51820
PrivateKey=aMAG31yjt85zsVC5hn5jMskuFdF8C/LFSRYnhRGSKUQ=
MTU=1440
[Peer]
PublicKey=LyhhEIjVQPVmr/sJNdSRqTjxibsfDZ15sDuhvAQ3hVM=
AllowedIPs=172.31.192.2/32
systemctl start wg-quick@server
klient
/etc/wireguard/client.conf:
[Interface]
Address=172.31.192.2/18
PrivateKey=uCluH7q2Hip5lLRSsVHc38nGKUGpZIUwGO/7k+6Ye3I=
MTU=1440
[Peer]
PublicKey=DjJRmGvhl6DWuSf1fldxNRBvqa701c0Sc7OpRr4gPXk=
AllowedIPs=172.31.192.1/32
Endpoint=SERVER_IP:51820
systemctl start wg-quick@client
wyniki
Wilgotny, brzydki znak
Obciążenie procesora serwera nie jest zbyt orientacyjne, ponieważ... Działa tam wiele innych usług, czasami pochłaniają zasoby:
proto bandwidth[Mbps] CPU_idle_client[%] CPU_idle_server[%]
# 20 Mbps канал с микрокомпьютера (4 core) до VPS (1 core) через Атлантику
# pure
UDP 20.4 99.80 93.34
TCP 19.2 99.67 96.68
ICMP latency min/avg/max/mdev = 198.838/198.997/199.360/0.372 ms
# ipipou
UDP 19.8 98.45 99.47
TCP 18.8 99.56 96.75
ICMP latency min/avg/max/mdev = 199.562/208.919/220.222/7.905 ms
# openvpn0 (auth only, no encryption)
UDP 19.3 99.89 72.90
TCP 16.1 95.95 88.46
ICMP latency min/avg/max/mdev = 191.631/193.538/198.724/2.520 ms
# openvpn (full encryption, auth, etc)
UDP 19.6 99.75 72.35
TCP 17.0 94.47 87.99
ICMP latency min/avg/max/mdev = 202.168/202.377/202.900/0.451 ms
# wireguard
UDP 19.3 91.60 94.78
TCP 17.2 96.76 92.87
ICMP latency min/avg/max/mdev = 217.925/223.601/230.696/3.266 ms
## около-1Gbps канал между VPS Европы и США (1 core)
# pure
UDP 729 73.40 39.93
TCP 363 96.95 90.40
ICMP latency min/avg/max/mdev = 106.867/106.994/107.126/0.066 ms
# ipipou
UDP 714 63.10 23.53
TCP 431 95.65 64.56
ICMP latency min/avg/max/mdev = 107.444/107.523/107.648/0.058 ms
# openvpn0 (auth only, no encryption)
UDP 193 17.51 1.62
TCP 12 95.45 92.80
ICMP latency min/avg/max/mdev = 107.191/107.334/107.559/0.116 ms
# wireguard
UDP 629 22.26 2.62
TCP 198 77.40 55.98
ICMP latency min/avg/max/mdev = 107.616/107.788/108.038/0.128 ms
Kanał 20Mbps


kanał na 1 optymistyczny Gbps


We wszystkich przypadkach ipipou ma wydajność zbliżoną do kanału bazowego, co jest świetne!
Nieszyfrowany tunel openvpn zachowywał się dość dziwnie w obu przypadkach.
Jeśli ktoś będzie to testował, ciekawe będzie poznanie opinii.
Niech IPv6 i NetPrickle będą z nami!
Źródło: www.habr.com
