Hvad siger vi til IPv6-guden?

Korrekt, og vi siger det samme til krypteringsguden i dag.
Her vil der være om en ukrypteret IPv4-tunnel, men ikke om den "varme varme" type, men en moderne "LED" type. Og så optræder der rå sockets, og der arbejdes med pakker i brugerens rum.
Der er N tunneleringsprotokoller til enhver smag:
- stilig, moderigtig, ungdommelig
- multifunktionelle som schweiziske knive, OpenVPN og SSH
- den gamle og milde GRE
- maksimalt enkel, hurtig, slet ikke krypteret IPIP
- aktivt udviklende
- mange andre.
Men jeg er programmerer, så jeg vil kun øge N en smule, og lade udviklingen af rigtige protokoller til Ъ-udviklerne.
I et endnu ikke født -projekt, som jeg arbejder på nu, skal der etableres forbindelse til hoste bag NAT udefra. Ved at bruge protokoller med ordentlig kryptografi, kunne jeg ikke lade være med at føle, at det var som at skyde med kanon mod spurve. Da tunnelen hovedsageligt bruges til at bore et hul i NAT, er den interne trafik også typisk krypteret; der kæmpes for HTTPS.
Når jeg undersøger forskellige tunneleringsprotokoller, blev min indre perfektionist konstant tiltrukket af IPIP på grund af dets minimale overhead. Men det har halvandet væsentligt drawback for mine opgaver:
- det kræver offentlige IP'er på begge sider,
- og ingen autentificering.
Så perfektionisten trak sig tilbage til den mørke krog af kraniet, eller hvor han nu sidder.
Og en dag, mens jeg læste artikler om i Linux, stødte jeg på FOU (Foo-over-UDP), altså hvad som helst pakket ind i UDP. Indtil videre støttes kun IPIP og GUE (Generic UDP Encapsulation) af hvad som helst.
"Her er den sølvkugle! Jeg har nok med simpel IPIP." – tænkte jeg.
I virkeligheden viste kuglen sig ikke at være helt sølvfarvet. Indkapslingen i UDP løser det første problem – man kan oprette forbindelse til kunder bag NAT udefra ved at bruge en på forhånd etableret forbindelse, men her blomstrer den halve næste ulempe ved IPIP i nyt lys – bag de synlige offentlige IP'er og porten til kunden kan der gemme sig hvem som helst fra det private netværk (i ren IPIP findes dette problem ikke).
For at løse dette halvandet problem blev værktøjet I den er der implementeret en selvbygget mekanisme til autentificering af den eksterne host, uden at det påvirker kernens FOU, som effektivt vil håndtere pakker i kernens rum.
Din skript er ikke nødvendigt!
Okay, hvis du kender klientens offentlige port og IP (for eksempel, alle dine egne går ikke vilkårligt, NAT forsøger at mappe 1-til-1), kan du oprette en IPIP-over-FOU tunnel med følgende kommandoer, uden nogen skripter.
på serveren:
# Подгрузить модуль ядра 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
på klienten:
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
# Lokale, peer, peer_port, dev muligheder kan muligvis ikke understøttes af ældre kerner, de kan udelades.
# peer og peer_port bruges til at etablere forbindelsen straks, når FOU-listeren er oprettet.
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
hvor
ipipou*— navnet på den lokale tunnel-netværksinterface203.0.113.1— den offentlige IP for serveren198.51.100.2— den offentlige IP for klienten192.168.0.2— klientens IP, tildelt interface eth010001— klientens lokale port til FOU20001— klientens offentlige port til FOU10000— serverens offentlige port til FOUencap-csum— en mulighed for at tilføje en kontrolsum til UDP-kapslede UDP-pakker; kan erstattes mednoencap-csum, så man ikke behøver at beregne, integriteten overvåges og kontrolleres af det ydre kapslingslag (så længe pakken er inde i tunnelen)eth0— det lokale interface, som IPIP tunnelen vil blive bundet til172.28.0.1— klientens tunnelleinterface IP (privat)172.28.0.0— serverens tunnelleinterface IP (privat)
Så længe UDP-forbindelsen er aktiv, vil tunnelen forblive operationel; når den brydes, så må man se; hvis IP: klientporten forbliver den samme — vil det fungere, hvis den ændres — vil det brydes.
Det er lettest at vende alt tilbage ved at indlæse kerne-modulerne: modprobe -r fou ipip
Selv hvis autentificering ikke kræves, er de offentlige IP'er og klientporten ikke altid kendte og kan ofte være uforudsigelige eller ændre sig (afhængigt af typen af NAT). Hvis man udelader encap-dport på serversiden, vil tunnelen ikke fungere — den er ikke så smart, at den kan tage den eksterne port for forbindelsen. I dette tilfælde kan ipipou også hjælpe, eller WireGuard og lignende værktøjer kan være til nytte.
Hvordan fungerer det?
Klienten (hvad der normalt er bag NAT) opretter en tunnel (som i eksemplet ovenfor) og sender en pakke med autentificering til serveren, så den kan konfigurere tunnelen fra sin side. Afhængigt af indstillingerne kan dette være en tom pakke (bare for at serveren kan se de offentlige IP'er: porten for forbindelsen), eller med data som serveren kan bruge til at identificere klienten. Dataene kan være en simpel adgangssætning i klar tekst (jeg tænker på analogien med HTTP Basic Auth) eller signerede data i en bestemt form med en privat nøgle (svarende til HTTP Digest Auth, men lidt mere robust, se funktionen client_auth i koden).
På serveren (siden med den offentlige IP) opretter ipipou ved opstart en behandler til nfqueue og konfigurerer netfilter, så de relevante pakker sendes korrekt: pakker, der initialiserer forbindelsen, sendes til nfqueue, og [næsten] alle andre sendes direkte til lytteren FOU.
For dem der ikke er bekendt, er nfqueue (eller NetfilterQueue) en speciel funktion for amatører, der ikke kan udvikle kernelmoduler, der ved hjælp af netfilter (nftables/iptables) muliggør omdirigering af netværkspakker til brugerrummet, hvor de kan behandles med primitive værktøjer: modificeres (valgfrit) og sendes tilbage til kernen, eller droppes.
For nogle programmeringssprog findes der bindings til at arbejde med nfqueue, men til bash fandtes der ingen (heh, ikke overraskende), så vi måtte bruge python: ipipou bruger .
Hvis ydeevne ikke er kritisk, kan man relativt hurtigt og nemt skabe sin egen logik for at arbejde med pakker på et ret lavt niveau, for eksempel udvikle eksperimentelle dataoverførselsprotokoller eller drille lokale og fjerntliggende tjenester med usædvanlig adfærd.
Sammen med nfqueue arbejder rå sokler (raw sockets); for eksempel når tunnelen allerede er oprettet, og FOU lytter på den nødvendige port, kan man ikke sende en pakke fra denne port på normal vis — den er optaget, men man kan tage og sende en vilkårligt genereret pakke direkte ind i netværksinterfacet ved at bruge en rå sokkel, selvom det kræver lidt mere arbejde med at generere en sådan pakke. Sådan skabes pakker med autentificering i ipipou.
Da ipipou kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun kun.
Når ipipou-serveren modtager en autentificeret pakke, oprettes tunnelen, og alle efterfølgende pakker i forbindelsen behandles allerede af kernen uden om nfqueue. Hvis forbindelsen er udløbet, vil den første pakke i den næste blive sendt til nfqueue, afhængig af indstillinger, hvis det ikke er en autentificeringspakke, men fra den sidst gemte IP og port fra klienten, kan den enten blive sendt videre eller droppet. Hvis den autentificerede pakke kommer fra en ny IP og port, genkonfigureres tunnelen til at bruge dem.
En almindelig IPIP-over-FOU har et yderligere problem, når den arbejder med NAT – det er ikke muligt at oprette to IPIP-tunneler indkapslet i UDP med de samme IP'er, da FOU- og IPIP-modulerne er tilstrækkeligt isolerede fra hinanden. Det vil sige, at et par kunder med én offentlig IP ikke samtidig kan forbinde til én server på denne måde. I fremtiden, , bliver det løst på kernel-niveau, men det er ikke sikkert. Indtil da kan NAT-problemer løses med NAT – hvis det sker, at et par IP-adresser allerede er optaget af en anden tunnel, vil ipipou udføre NAT fra offentlig til alternativ privat IP, voilà! – man kan oprette tunneler, så længe portene ikke løber tør.
Da ikke alle pakker i forbindelsen er signeret, er sådan en simpel beskyttelse sårbar over for MITM, så hvis der ligger en skurk mellem klienten og serveren, der kan lytte til trafikken og styre den, kan han omdirigere autentificeringspakkerne gennem en anden adresse og skabe en tunnel fra en usikker vært.
Hvis nogen har idéer til, hvordan man kan løse dette, mens man holder det meste af trafikken i kernen, så tøv ikke – del dem.
For at sige det, har UDP-encapsulation vist sig at være meget effektivt. I forhold til indkapsling over IP er det meget mere stabilt og ofte hurtigere på trods af de ekstra omkostninger ved UDP-headeren. Dette skyldes, at størstedelen af værter på internettet kun fungerer acceptabelt med de tre mest populære protokoller: TCP, UDP, ICMP. En betydelig del kan endda helt afvise alt andet, eller behandle det langsommere, da det kun er optimeret til disse tre.
For example, that’s why QUICK, which serves as the basis for HTTP/3, was developed on top of UDP, not IP.
Well, enough talk, it’s time to see how this works in the 'real world'.
Battle
To simulate the real world, iperf3. In terms of closeness to reality, it’s about like simulating the real world in Minecraft, but for now it will do.
The competition involves:
- reference main channel
- the hero of this article ipipou
- OpenVPN with authentication but without encryption
- OpenVPN in 'everything included' mode
- WireGuard without PresharedKey, with MTU=1440 (since it's IPv4-only)
Technical details for geeks
Metrics are gathered with the following commands
på klienten:
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"
# Where "-b 12M" is the bandwidth of the main channel divided by the number of threads "-P", to avoid generating excess packets and degrading performance.
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 latency
ping -c 10 SERVER_IP | tail -1
on the server (runs simultaneously with the client):
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"
Tunnel configuration
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
client
/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 (without encryption, with authentication)
server
openvpn --genkey --secret ovpn.key # Then transfer ovpn.key to the client
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
client
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 (with encryption, authentication, over UDP, as it should be)
Configured using
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
client
/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
Resultater
An ugly raw table
The CPU load of the server is not very indicative, as many other services run there and sometimes consume resources:
proto båndbredde[Mbps] CPU_idle_client[%] CPU_idle_server[%]
# 20 Mbps kanal fra en mikrokontroller (4 core) til VPS (1 core) over Atlanten
# ren
UDP 20.4 99.80 93.34
TCP 19.2 99.67 96.68
ICMP latenstid min/gennemsnit/maks/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 latenstid min/gennemsnit/maks/mdev = 199.562/208.919/220.222/7.905 ms
# openvpn0 (kun autentificering, ingen kryptering)
UDP 19.3 99.89 72.90
TCP 16.1 95.95 88.46
ICMP latenstid min/gennemsnit/maks/mdev = 191.631/193.538/198.724/2.520 ms
# openvpn (fuld kryptering, autentificering osv.)
UDP 19.6 99.75 72.35
TCP 17.0 94.47 87.99
ICMP latenstid min/gennemsnit/maks/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 latenstid min/gennemsnit/maks/mdev = 217.925/223.601/230.696/3.266 ms
## omkring-1Gbps kanal mellem VPS i Europa og USA (1 core)
# ren
UDP 729 73.40 39.93
TCP 363 96.95 90.40
ICMP latenstid min/gennemsnit/maks/mdev = 106.867/106.994/107.126/0.066 ms
# ipipou
UDP 714 63.10 23.53
TCP 431 95.65 64.56
ICMP latenstid min/gennemsnit/maks/mdev = 107.444/107.523/107.648/0.058 ms
# openvpn0 (kun autentificering, ingen kryptering)
UDP 193 17.51 1.62
TCP 12 95.45 92.80
ICMP latenstid min/gennemsnit/maks/mdev = 107.191/107.334/107.559/0.116 ms
# wireguard
UDP 629 22.26 2.62
TCP 198 77.40 55.98
ICMP latenstid min/gennemsnit/maks/mdev = 107.616/107.788/108.038/0.128 ms
kanal på 20 Mbps


kanal på 1 optimistisk Gbps


I alle tilfælde er ipipou ret tæt på resultaterne fra basiskanalen, og det er fremragende!
Den ukrypterede tunnel openvpn opførte sig ret mærkeligt i begge tilfælde.
Hvis nogen har lyst til at teste, ville det være interessant at høre feedback.
Må IPv6 og NetPrickle være med os!
Kilde: habr.com
