Čo hovoríme bohu IPv6?

Správne, a bohu šifrovania dnes povieme to isté.
Tu bude reč o nešifrovanom IPv4 tuneli, ale nie o „teplom lampovom“, skôr o modernom „svetelnom“. A ešte sa tu mihnú surové sockety a prebieha práca s paketmi v priestore používateľa.
Existuje N protokolov tunelovania na akúkoľvek chuť a farbu:
- štýlový, módny, mladistvý
- multifunkčné, ako švajčiarske nože, OpenVPN a SSH
- starý a neprísny GRE
- maximálne jednoduchý, rýchly, úplne nešifrovaný IPIP
- aktívne sa vyvíjajúci
- množstvo ďalších.
Ale jažprogramátor, preto zvýšim N len o trošku, a vývoj skutočných protokolov nechám Ď-developerom.
V jednom ešte nenarodenom projektoch, ktorým sa teraz venujem, musím sa dostať k hostiteľom za NAT-om z vonku. Pri použití protokolov so serióznou kryptografiou som mal stále pocit, že je to ako strieľať na vrabce z dela. Keďže sa tunel používa väčšinou len na prechod cez NAT, vnútorný traffic je obvykle tiež šifrovaný, všade sa tlačí za HTTPS.
Pri skúmaní rôznych protokolov tunelovania sa pozornosť môjho vnútorného perfekcionistu neustále priťahoval IPIP kvôli jeho minimálnym nákladom. Ale má jedno a pol zásadného nedostatku pre moje úlohy:
- vyžaduje verejné IP na oboch stranách,
- a žiadnu autentifikáciu.
Preto sa perfekcionista zatvoril späť do tmavého rohu lebky, alebo kde tam sedí.
A tak raz, keď som čítal články o v Linuxe, narazil som na FOU (Foo-over-UDP), teda niečo, čo je zabalene v UDP. Zatiaľ sú podporované iba IPIP a GUE (Generic UDP Encapsulation).
„Tu je strieborná guľka! Mne stačí obyčajný IPIP.“ — myslel som si.
V skutočnosti guľka sa ukázala ako nie celkom strieborná. Inkapulácia v UDP rieši prvý problém — k klientom za NAT-om sa dá pripojiť zvonku pomocou vopred nastaveného spojenia, ale tu sa polovica ďalšieho nedostatku IPIP objavuje v novom svetle — za verejnými IP a portom klienta sa môže skrývať ktokoľvek z privátnej siete (v čistom IPIP táto problém nie je).
Na vyriešenie tejto polovičnej problému vznikla utilita V nej je implementovaný vlastný mechanizmus autorizácie vzdialeného hostiteľa, pričom neruší činnosť jadrového FOU, ktorý rýchlo a efektívne spracováva pakety v jadrovom priestore.
Tvoj skript nie je potrebný!
Dobré, ak poznáš verejný port a IP adresu klienta (napríklad nemôže ísť všetko, kam sa mu zachce, NAT sa snaží mapovať porty 1:1), môžeš vytvoriť IPIP-over-FOU tunel nasledujúcimi príkazmi, bez akýchkoľvek skriptov.
na serveri:
# Подгрузить модуль ядра 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 klientovi:
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 nemusia byť podporované staršími jadrami, môžu sa vynechať.
# peer a peer_port sa používajú na vytvorenie spojenia okamžite pri vytvorení FOU listener-a.
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ázov miestneho tunelového sieťového rozhrania203.0.113.1— verejná IP adresa servera198.51.100.2— verejná IP adresa klienta192.168.0.2— IP adresa klienta, priradená rozhraniu eth010001— miestny port klienta pre FOU20001— verejný port klienta pre FOU10000— verejný port servera pre FOUencap-csum— možnosť na pridanie kontrolného súčtu UDP do enkapsulovaných UDP paketov; možno nahradiťnoencap-csum, aby sa nekontroloval, integrita sa stále kontroluje vonkajšou vrstvou enkapsulácie (kým je paket v tuneli)eth0— miestne rozhranie, ku ktorému bude pripojený ipip tunel172.28.0.1— IP adresa tunelového rozhrania klienta (súkromná)172.28.0.0— IP adresa tunelového rozhrania servera (súkromná)
Pokiaľ je UDP spojenie aktívne, tunel bude v prevádzke, a keď sa preruší, bude to, ako sa to podarí — ak IP: port klienta zostanú rovnaké — bude fungovať, zmenia sa — preruší sa.
Najjednoduchšie je všetko vrátiť späť vypnutím jadrových modulov: modprobe -r fou ipip
Aj keď autentifikácia nie je potrebná, verejné IP a port klienta nie sú vždy známe a často sú nepravidelné alebo sa menia (v závislosti od typu NAT). Ak sa vynechá encap-dport na strane servera, tunel nebude fungovať, nie je taký inteligentný, aby bral vzdialený port spojenia. V tomto prípade môže tiež pomôcť ipipou, alebo WireGuard a jemu podobní.
Ako to funguje?
Klient (čo je zvyčajne za NAT-om) vytvára tunel (ako v príklade vyššie) a posiela paket s autentifikáciou na server, aby ho nastavili zo svojej strany. V závislosti od nastavení to môže byť prázdny paket (len aby server videl verejné IP: port pripojenia), alebo s údajmi, podľa ktorých server dokáže identifikovať klienta. Údaje môžu byť jednoduchou heslovou frázou v otvorenom texte (prichádza mi na um analógia s HTTP Basic Auth) alebo podpísané súkromným kľúčom špeciálne formátované údaje (podobne ako HTTP Digest Auth, len silnejšie, pozri funkciu client_auth v kóde).
Na serveri (strana s verejným IP) pri spustení ipipou vytvára obslužný program pre frontu nfqueue a nastavuje netfilter tak, aby potrebné pakety smerovali kam treba: pakety iniciujúce pripojenie do fronty nfqueue, a [takmer] všetky ostatné priamo do listenera FOU.
Pre tých, ktorí nie sú v obraze, nfqueue (alebo NetfilterQueue) je špeciálna funkcia pre laikov, ktorí nevedia vyvíjať jadrové moduly, ktorá pomocou netfilter (nftables/iptables) umožňuje presmerovať sieťové pakety do užívateľského priestoru a spracovať ich tam primitívnymi prostriedkami: modifikovať (voliteľne) a vrátiť späť jadru alebo ich zahodiť.
Pre niektoré programovacie jazyky existujú bindiny na prácu s nfqueue, pre bash sa nenašla (heh, nie prekvapujúco), musel som použiť python: ipipou využíva .
Ak nie je výkonnosť kritická, pomocou tejto funkcie je možné relatívne rýchlo a jednoducho vytvárať vlastnú logiku práce s paketmi na dostatočne nízkej úrovni, napríklad vypracovávať experimentálne protokoly prenosu dát, alebo trolliť lokálne a vzdialené služby netradičným správaním.
Ruka v ruke s nfqueue pracujú surové sokety (raw sockets), napríklad keď je tunel už nastavený a FOU počúva na požadovanom porte, bežne zaslať paket z tohto istého portu nebude možné — je obsadené, ale môžete vziať a poslať náhodne vygenerovaný paket priamo do sieťového rozhrania pomocou surového soketu, hoci nad generovaním takého paketu bude treba trochu dlhšie zapracovať. Tak sa v ipipou vytvárajú pakety s autentifikáciou.
Keďže ipipou spracováva iba prvé pakety z pripojenia (a tiež tie, ktoré sa stihli dostať do fronty pred vytvorením pripojenia), výkonnosť takmer netrpí.
Akonáhle ipipou server prijme balík, ktorý prešiel autentifikáciou, tunel sa vytvorí a všetky nasledujúce pakety v pripojení sa už spracovávajú jadrom mimo nfqueue. Ak pripojenie vypršalo, prvý paket nasledujúceho bude nasmerovaný do fronty nfqueue, v závislosti od nastavení, pokiaľ to nie je paket s autentifikáciou, ale z poslednej zapamätanej IP a portu klienta, môže byť buď povolený na ďalšie spracovanie, alebo odmietnutý. Ak autentifikovaný paket príde z nových IP a portu, tunel sa prekonfiguruje na ich použitie.
Obvyklé IPIP-over-FOU má ešte jednu nevýhodu pri práci s NAT — nemožno vytvoriť dva IPIP tunely zapuzdrené v UDP s rovnakými IP, pretože moduly FOU a IPIP sú dosť izolované od seba. T.j. pár klientov za jednou verejnou IP sa nemôže súčasne pripojiť k jednemu serveru týmto spôsobom. V budúcnosti, , to vyriešia na úrovni jadra, ale to nie je isté. Zatiaľ sa problémy s NAT môžu vyriešiť NAT-om — ak sa stane, že pár IP adries je už obsadených iným tunelom, ipipou vykoná NAT z verejného na alternatívny súkromný IP, voilà! — môžu sa vytvárať tunely, kým sa nevyprázdnia porty.
Keďže nie všetky pakety v pripojení sú podpísané, takáto jednoduchá ochrana je zraniteľná voči MITM, takže ak na ceste medzi klientom a serverom číha zlomyseľník, ktorý môže odpočúvať a ovládať provoz, môže presmerovať pakety s autentifikáciou cez inú adresu a vytvoriť tunel z nedôveryhodného hostiteľa.
Ak má niekto nápady, ako to opraviť a ponechať väčšinu prevádzky v jadre, neváhajte — vyjadrite sa.
Mimochodom, zapuzdrenie v UDP sa veľmi dobre osvedčilo. V porovnaní so zapuzdrením nad IP je oveľa stabilnejšie a častejšie rýchlejšie, aj napriek dodatočným nákladom na hlavičku UDP. Je to spôsobené tým, že na internete väčšina hostiteľov slušne funguje iba s tromi najpopulárnejšími protokolmi: TCP, UDP, ICMP. Značná časť môže dokonca úplne ignorovať všetko ostatné, alebo spracovávať pomalšie, pretože je optimalizovaná iba pre tieto tri.
Napríklad, preto sa QUICK, na ktorom bol postavený HTTP/3, vyvíjal práve nad UDP, a nie nad IP.
Nuž, dosť slov, poďme si pozrieť, ako to funguje v „reálnom svete“.
Bitka
Na simuláciu reálneho sveta sa používa iperf3. Po okamžikovej podobnosti s realitou je to približne ako simulácia reálneho sveta v Minecrafte, ale zatiaľ to stačí.
V súťaži sa zúčastňujú:
- referenčný hlavný kanál
- hrdina tohto článku ipipou
- OpenVPN s autentifikáciou, ale bez šifrovania
- OpenVPN v režime „všetko zahrnuté“
- WireGuard bez PresharedKey, s MTU=1440 (pretože len IPv4)
Technické údaje pre geekov
Metriky sa snímajú takýmito príkazmi
na klientovi:
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 priepustnosť hlavného kanála delená počtom tokov "-P", aby sa neopakovali zbytočné pakety a nezhoršila sa výkonosť.
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 latencia
ping -c 10 SERVER_IP | tail -1
na serveri (spúšťa sa súčasne s klientom):
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"
Nastavenie tunelov
ipipou
server
/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
sa dostal do backendu.
/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 šifrovania, s autentifikáciou)
server
openvpn --genkey --secret ovpn.key # Potom treba poslať 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
sa 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 (so šifrovaním, autentifikáciou, cez UDP, všetko ako má byť)
Nastavené pomocou
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
sa 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
Surové škaredé tabuľky
Vytíženosť CPU servera nie je veľmi represívna, pretože tam beží veľa iných služieb, niekedy spotrebúvajú zdroje:
proto šírka pásma[Mbps] CPU_idle_client[%] CPU_idle_server[%]
# 20 Mbps kanál z mikropočítača (4 jadra) do VPS (1 jadro) cez Atlantik
# čistý
UDP 20.4 99.80 93.34
TCP 19.2 99.67 96.68
ICMP latencia 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 latencia min/avg/max/mdev = 199.562/208.919/220.222/7.905 ms
# openvpn0 (len autentifikácia, žiadne šifrovanie)
UDP 19.3 99.89 72.90
TCP 16.1 95.95 88.46
ICMP latencia min/avg/max/mdev = 191.631/193.538/198.724/2.520 ms
# openvpn (úplné šifrovanie, autentifikácia, atď)
UDP 19.6 99.75 72.35
TCP 17.0 94.47 87.99
ICMP latencia 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 latencia min/avg/max/mdev = 217.925/223.601/230.696/3.266 ms
## cca-1Gbps kanál medzi VPS Európy a USA (1 jadro)
# čistý
UDP 729 73.40 39.93
TCP 363 96.95 90.40
ICMP latencia 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 latencia min/avg/max/mdev = 107.444/107.523/107.648/0.058 ms
# openvpn0 (len autentifikácia, žiadne šifrovanie)
UDP 193 17.51 1.62
TCP 12 95.45 92.80
ICMP latencia 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 latencia min/avg/max/mdev = 107.616/107.788/108.038/0.128 ms
kanál na 20 Mbps


kanál na 1 optimistický Gbps


Vo všetkých prípadoch je ipipou dosť blízko ukazovateľom základného kanála, a to je skvelé!
Nešifrovaný tunel openvpn sa správal dosť zvláštne v oboch prípadoch.
Ak sa niekto chystá testovať, bude zaujímavé počuť názory.
Nech je s nami IPv6 a NetPrickle!
Zdroj: habr.com
