Co říkáme bohu IPv6?

Správně, a bohu šifrování dnes řekneme totéž.
Bude tu řeč o nešifrovaném IPv4 tunelu, ale ne o "teplém lampovém", nýbrž o moderním "LED". A také se tu mihotají syrové sockety, a probíhá práce s pakety v uživatelském prostoru.
Existuje N protokolů tunelování pro každého dle chuti a barvy:
- stylový, módní, mladistvý
- multifunkční, jako švýcarské nože, OpenVPN a SSH
- stará a ne zlá GRE
- maximálně jednoduchý, rychlý, zcela nešifrovaný IPIP
- aktivně se rozvíjející
- mnoho dalších.
Ale já jsem programátor, proto zvýším N jen o kousek, a vývoj skutečných protokolů nechám Ď-developerům.
V jednom ještě nenarozeném , kterým se teď zabývám, potřebuji získat přístup k hostitelům za NATem zvenčí. Používajíc pro to protokoly se seriózní kryptografií, stále mě však neopouští pocit, že je to jako střílet z děla na vrabce. Jelikož se tunel používá většinou pouze k prorážení díry v NATu, vnitřní provoz je obvykle také zašifrovaný, všichni hrají na https.
Při zkoumání různých protokolů tunelování opakovaně přitahoval pozornost mého vnitřního perfekcionisty IPIP kvůli jeho minimálním nákladům. Ale má jeden a půl podstatných nedostatků pro mé úkoly:
- vyžaduje veřejné IP na obou stranách,
- a žádnou autentifikaci.
Proto se perfekcionista zase zavřel zpět do temného kouta své hlavy, nebo kde to sedí.
A tak jsem jednou při čtení článků o v Linuxu narazil na FOU (Foo-over-UDP), tj. něco, co se zabalí do UDP. Zatím jsou z toho, co se podporuje, pouze IPIP a GUE (generická UDP enkapsulace).
"Tady je stříbrná kulka! Mně stačí jednoduchý IPIP." – myslel jsem si.
Ve skutečnosti se kulka ukázala být nedokonale stříbrnou. Enkapsulace do UDP vyřešila první problém – ke klientům za NATem se dá připojit zvenčí použitím předem nastaveného spojení, ale tady se půlka dalšího nedostatku IPIP ukazuje v novém světle – za viditelnými veřejnými IP a portem klienta se může skrývat kdokoli z privátní sítě (v čistém IPIP tento problém není).
Pro řešení tohoto polo-problemu vznikla utilita V ní byl implementován domácí mechanismus autentizace vzdáleného hostitele, přičemž nedochází k narušení funkce jádra FOU, které bude rychle a efektivně zpracovávat pakety v prostorovém jádru.
Tvůj skript není potřeba!
Dobře, pokud jsou ti známy veřejný port a IP adresa klienta (například za ním všechny, kam popadá nechodí, NAT se snaží mapovat porty 1:1), můžeš vytvořit tunel IPIP-over-FOU následujícími příkazy, bez jakýchkoli skriptů.
na serveru:
# Подгрузить модуль ядра 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 klientu:
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
# Možnosti local, peer, peer_port, dev nemusí starší jádra podporovat, lze je opomenout.
# peer a peer_port se používají k okamžitému vytvoření spojení při vytvoření FOU listeneru.
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
kde
ipipou*— název místního tunelového síťového rozhraní203.0.113.1— veřejná IP adresa serveru198.51.100.2— veřejná IP adresa klienta192.168.0.2— IP adresa klienta, přidělená rozhraní eth010001— místní port klienta pro FOU20001— veřejný port klienta pro FOU10000— veřejný port serveru pro FOUencap-csum— volba pro přidání kontrolního součtu UDP do enkapsulovaných UDP paketů; lze nahraditnoencap-csum, aby se nepočítalo, integrita je tak kontrolována externí vrstvou enkapsulace (pokud packet zůstává uvnitř tunelu)eth0— místní rozhraní, k němuž bude připojen tunel IPIP172.28.0.1— IP adresa tunelového rozhraní klienta (privátní)172.28.0.0— IP adresa tunelového rozhraní serveru (privátní)
Dokud je UDP spojení aktivní, tunel bude funkční, a jakmile se přeruší, bude se to vyvíjet tak, jak to bude, — pokud zůstanou IP: port klienta stejné — bude trvat, změní-li se — dojde k přerušení.
Nejjednodušší je vzít vše zpět vyložením modulů jádra: modprobe -r fou ipip
I když autentizace není vyžadována, veřejné IP a port klienta nejsou vždy známy a často jsou nepředvídatelné nebo proměnné (v závislosti na typu NAT). Pokud vynecháš encap-dport na straně serveru, tunel nebude fungovat, není tak chytrý, aby převezmout vzdálený port spojení. V tomto případě ti může také pomoci ipipou nebo WireGuard a podobné nástroje.
Jak to funguje?
Klient (co obvykle za NAT-em) vytvoří tunel (jak je uvedeno v předchozím příkladu) a odešle balíček s autentizací na server, aby nastavil tunel na své straně. V závislosti na nastavení to může být prázdný balíček (jen aby server viděl veřejné IP: port připojení), nebo s daty, podle kterých server dokáže identifikovat klienta. Data mohou být jednoduchou heslovou frází v prostém textu (v hlavě mě napadá analogie s HTTP Basic Auth) nebo podepsaná soukromým klíčem speciálně zformátovaná data (podobně jako HTTP Digest Auth, ale silnější, viz funkce client_auth v kódu).
Na serveru (straně s veřejným IP) při spuštění ipipou vytvoří zpracovatel fronty nfqueue a nastaví netfilter tak, aby potřebné balíčky byly směrovány tam, kam mají: balíčky iniciující připojení do fronty nfqueue, a [téměř] všechny ostatní přímo do listeneru FOU.
Kdo neví, nfqueue (nebo NetfilterQueue) — to je speciální věc pro amatéry, kteří neumí vyvíjet jádrové moduly, která pomocí netfilter (nftables/iptables) umožňuje přesměrovávat síťové balíčky do uživatelského prostoru a tam je zpracovávat primitivními dostupnými prostředky: modifikovat (volitelně) a vrátit zpět jádru, nebo je zahodit.
Pro některé programovací jazyky existují vazby pro práci s nfqueue, ale pro bash se nic nenašlo (heh, nepřekvapuje), musel jsem použít python: ipipou používá .
Pokud není výkon kritický, pomocí této věci lze relativně rychle a jednoduše vyrobit vlastní logiku práce s balíčky na dost nízké úrovni, například vytvářet experimentální protokoly přenosu dat nebo trollit místní a vzdálené služby neobvyklým chováním.
Ruku v ruce s nfqueue pracují syrové sokety (raw sockets), například když je tunel již nastaven a FOU poslouchá na požadovaném portu, obvyklým způsobem nelze odeslat balíček z tohoto portu — je obsazen, ale můžete vzít a vygenerovaný balíček poslat přímo do síťového rozhraní pomocí syrového socketu, i když nad generováním takového balíčku bude třeba trochu více pracovat. Tak se vytvářejí v ipipou balíčky s autentizací.
Jelikož ipipou zpracovává pouze první pakety ze spojení (a také ty, které se dostaly do fronty před navázáním spojení), výkon téměř netrpí.
Jakmile ipipou server obdrží paket, který prošel autentizací, tunel se vytvoří a všechny následující pakety ve spojení jsou již zpracovány jádrem, obcházejíc nfqueue. Pokud spojení vyprší, první paket následujícího spojení bude směrován do fronty nfqueue, v závislosti na nastavení, pokud to není autentizační paket, ale má poslední zapamatovanou IP a port klienta, může být buď propuštěn dále, nebo odmítnut. Pokud autentizovaný paket přichází z nových IP a portu, tunel se přeprogramuje na jejich používání.
Obvyklé IPIP-over-FOU má další problém při práci s NAT — nelze vytvořit dva IPIP tunely encapsulované v UDP se stejnými IP, neboť moduly FOU a IPIP jsou dostatečně izolovány. Tedy pár klientů za jednou veřejnou IP se nebude moci současně připojit k jednomu serveru tímto způsobem. V budoucnu, , to vyřeší na úrovni jádra, ale to není jisté. Zatím lze problémy s NAT vyřešit pomocí NAT — pokud se stane, že pár IP adres již obsadil jiný tunel, ipipou provede NAT z veřejného na alternativní soukromou IP, voilà! — tunely lze vytvářet, dokud nezůstanou porty.
Jelikož nejsou všechny pakety ve spojení podepsány, taková jednoduchá ochrana je zranitelná vůči MITM, takže pokud se na cestě mezi klientem a serverem skrývá zloduch, který může naslouchat provozu a ovládat ho, může přesměrovat pakety s autentizací na jinou adresu a vytvořit tunel z nedůvěryhodného hostitele.
Pokud má někdo nápady, jak to opravit, zatímco většina provozu zůstává v jádře, neváhejte — ozvěte se.
Mimochodem, encapsulace v UDP se osvědčila velmi dobře. Ve srovnání s encapsulací nad IP je mnohem stabilnější a často rychlejší, ačkoliv má dodatečné náklady na hlavičku UDP. To je způsobeno tím, že na internetu většina hostitelů funguje rozumně jen s třemi nejpopulárnějšími protokoly: TCP, UDP, ICMP. Pozoruhodná část může dokonce ignorovat všechno ostatní, nebo to zpracovávat pomaleji, protože je optimalizována pouze pro tyto tři.
Například, proto byl QUICK, na jehož základě byl vytvořen HTTP/3, vytvořen právě nad UDP, nikoli nad IP.
Ale dost slov, pojďme se podívat, jak to funguje v „reálném světě“.
Bitva
Pro emulaci reálného světa se používá iperf3. Co se týče přiblížení k realitě, je to zhruba jako emulace reálného světa v Minecraftu, ale prozatím postačí.
V soutěži se účastní:
- standardní hlavní kanál
- hrdina tohoto článku ipipou
- OpenVPN s autentizací, ale bez šifrování
- OpenVPN v režimu „všechno zahrnuto“
- WireGuard bez PresharedKey, s MTU=1440 (protože IPv4-only)
Technické údaje pro geeky
Metriky se snímají těmito příkazy
na klientu:
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"
# Kde "-b 12M" je šířka pásma hlavního kanálu, dělená počtem vláken "-P", aby se nevytvářely přebytečné pakety a nezhoršovala se výkonnost.
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"
ICMP latence
ping -c 10 SERVER_IP | tail -1
na serveru (spouští se současně s 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"
Konfigurace tunelů
ipipou
server
/etc/ipipou/server.conf:
server
číslo 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
se dostal do backendu.
/etc/ipipou/client.conf:
client
číslo 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 šifrování, s autentizací)
server
openvpn --genkey --secret ovpn.key # Poté je třeba předat ovpn.key klientovi
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
se dostal do backendu.
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 (se šifrováním, autentizací, přes UDP, všechno tak, jak má být)
Nastavené pomocí
wireguard
server
/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
se dostal do backendu.
/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
Výsledky
Syrová, ošklivá tabulka
Zatížení CPU serveru není příliš ukazatel, protože tam běží mnoho dalších služeb, které občas spotřebovávají zdroje:
proto šířka pásma[Mbps] CPU_idle_client[%] CPU_idle_server[%]
# 20 Mbps kanál z mikropočítače (4 jádra) do VPS (1 jádro) přes Atlantik
# čistý
UDP 20.4 99.80 93.34
TCP 19.2 99.67 96.68
ICMP latence 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 latence min/avg/max/mdev = 199.562/208.919/220.222/7.905 ms
# openvpn0 (pouze ověřování, žádné šifrování)
UDP 19.3 99.89 72.90
TCP 16.1 95.95 88.46
ICMP latence min/avg/max/mdev = 191.631/193.538/198.724/2.520 ms
# openvpn (plné šifrování, ověřování atd.)
UDP 19.6 99.75 72.35
TCP 17.0 94.47 87.99
ICMP latence 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 latence min/avg/max/mdev = 217.925/223.601/230.696/3.266 ms
## přibližně 1Gbps kanál mezi VPS v Evropě a USA (1 jádro)
# čistý
UDP 729 73.40 39.93
TCP 363 96.95 90.40
ICMP latence 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 latence min/avg/max/mdev = 107.444/107.523/107.648/0.058 ms
# openvpn0 (pouze ověřování, žádné šifrování)
UDP 193 17.51 1.62
TCP 12 95.45 92.80
ICMP latence 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 latence min/avg/max/mdev = 107.616/107.788/108.038/0.128 ms
kanál na 20 Mbps


kanál na 1 optimistický Gbps


Ve všech případech je ipipou poměrně blízko základnímu kanálu a to je skvělé!
Nešifrovaný tunel openvpn se choval docela podivně v obou případech.
Pokud se někdo chystá testovat, budou zajímavé vaše názory.
Kéž by s námi bylo IPv6 a NetPrickle!
Zdroj: habr.com
