ipipou: mehr als nur ein unverschlüsselter Tunnel

Was sagen wir zum IPv6-Gott?



IPv6?  Nicht heute


Richtig, und dem Gott der Verschlüsselung werden wir heute dasselbe sagen.



Hier geht es um einen unverschlüsselten IPv4-Tunnel, aber nicht um eine "warme Lampe", sondern um eine moderne "LED". Und dann blinken Raw-Sockets, und im Benutzerbereich wird mit Paketen gearbeitet.



Es gibt N Tunnelprotokolle für jeden Geschmack und jede Farbe:



  • stilvoller, trendiger, jugendlicher WireGuard
  • multifunktional wie Schweizer Messer, OpenVPN und SSH
  • alt und nicht böse GRE
  • das einfachste, intelligenteste, überhaupt nicht verschlüsselte IPIP
  • GENEVE aktiv entwickeln
  • viele andere.


Aber ich bin ein Programmierer, also werde ich N nur um einen Bruchteil erhöhen und die Entwicklung realer Protokolle den B-Entwicklern überlassen.



In einem anderen ungeborenen Projekt , an dem ich gerade beteiligt bin, muss ich Hosts hinter NAT von außen erreichen. Ich habe dafür Protokolle mit Erwachsenen-Kryptographie verwendet und nie das Gefühl hinterlassen, dass es wie eine Kanonenkugel ist. weil Der Tunnel wird größtenteils nur verwendet, um ein Loch in NAT-e zu stechen. Der interne Datenverkehr wird normalerweise ebenfalls verschlüsselt, ertrinkt jedoch für HTTPS.



Bei der Untersuchung verschiedener Tunnelprotokolle wurde die Aufmerksamkeit meines inneren Perfektionisten aufgrund seines minimalen Overheads immer wieder auf IPIP gelenkt. Aber es hat eineinhalb bedeutende Nachteile für meine Aufgaben:



  • es erfordert öffentliche IPs auf beiden Seiten,
  • und keine Authentifizierung für Sie.


Daher wurde der Perfektionist zurück in die dunkle Ecke des Schädels oder wo immer er dort sitzt getrieben.



Und einmal stieß ich beim Lesen von Artikeln über nativ unterstützte Tunnel unter Linux auf FOU (Foo-over-UDP), d. H. was auch immer, eingewickelt in UDP. Bisher werden nur IPIP und GUE (Generic UDP Encapsulation) unterstützt.



„Hier ist eine Silberkugel! Ich und ein einfaches IPIP für die Augen. " Ich dachte.



Tatsächlich war die Kugel nicht ganz aus Silber. Die Kapselung in UDP löst das erste Problem: Sie können von außen über eine zuvor hergestellte Verbindung eine Verbindung zu Clients hinter NAT herstellen, aber hier taucht die Hälfte des nächsten Nachteils von IPIP in einem neuen Licht auf - jeder aus dem privaten Netzwerk kann sich hinter der sichtbaren öffentlichen IP und dem Client-Port (in reinem IPIP) verstecken Es gibt kein Problem).



Um dieses eineinhalb Problem zu lösen, wurde das Dienstprogramm ipipou geboren . Es implementiert einen selbst erstellten Mechanismus zur Authentifizierung eines Remote-Hosts, ohne den Betrieb einer starken FOU zu stören, die Pakete im Kernelraum schnell und effizient verarbeitet.



Brauche dein Skript nicht!



Ok, wenn Sie den öffentlichen Port und die IP des Clients kennen (z. B. alle Ihre eigenen, NAT versucht, die Ports 1 zu 1 zuzuordnen, wo immer sie sich befinden), können Sie einen IPIP-over-FOU-Tunnel mit den folgenden Befehlen ohne Skripte erstellen.



auf dem Server:

#    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


auf dem Client:

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


Wo

  • ipipou* - Der Name der lokalen Tunnelnetzwerkschnittstelle
  • 203.0.113.1 - öffentliche IP des Servers
  • 198.51.100.2 - öffentliche IP des Clients
  • 192.168.0.2 - Client-IP, die der eth0-Schnittstelle zugewiesen ist
  • 10001 - lokaler Client-Port für FOU
  • 20001 - öffentlicher Client-Port für FOU
  • 10000 - öffentlicher Server-Port für FOU
  • encap-csum — UDP UDP ; noencap-csum, , ( )
  • eth0 — ipip
  • 172.28.0.1 — IP ()
  • 172.28.0.0 — IP ()


Solange die UDP-Verbindung besteht, befindet sich der Tunnel in einem funktionierenden Zustand und wie er bricht, wie viel Glück - wenn der IP: -Port des Clients gleich bleibt - wird er leben, sich ändern - er wird brechen.



Der einfachste Weg, dies zu ändern, ist das Entladen von Kernelmodulen: modprobe -r fou ipip



Auch wenn keine Authentifizierung erforderlich ist, sind die öffentliche IP-Adresse und der Client-Port nicht immer bekannt und oft unvorhersehbar oder änderbar (abhängig vom NAT-Typ). Wenn Sie es encap-dportauf der Serverseite weglassen , funktioniert der Tunnel nicht. Er ist nicht intelligent genug, um den Remoteverbindungsport zu verwenden. In diesem Fall kann ipipou auch helfen, oder WireGuard und andere wie er können Ihnen helfen.



Wie es funktioniert?



Der Client (der normalerweise hinter NAT steht) richtet einen Tunnel ein (wie im obigen Beispiel) und sendet ein authentifiziertes Paket an den Server, damit er den Tunnel von seiner Seite aus konfigurieren kann. Abhängig von den Einstellungen kann dies ein leeres Paket sein (nur damit der Server den öffentlichen IP: Verbindungsport sieht) oder Daten, anhand derer der Server den Client identifizieren kann. Die Daten können eine einfache Klartext-Passphrase sein (eine Analogie zu HTTP Basic Auth fällt ein) oder speziell formatierte Daten, die mit einem privaten Schlüssel signiert sind (in Analogie zu HTTP Digest Auth, nur stärker, siehe Funktion client_authim Code).



Auf dem Server (Seite mit öffentlicher IP) erstellt ipipou beim Starten einen nfqueue-Warteschlangenhandler und konfiguriert netfilter so, dass die erforderlichen Pakete an den Ort gesendet werden, an den sie gehen sollen: die Pakete, die die Verbindung zur nfqueue-Warteschlange initialisieren, und [fast] den gesamten Rest direkt an den FOU-Listener.



Wer nicht im Thema ist, nfqueue (oder NetfilterQueue) ist eine besondere Sache für Amateure, die nicht wissen, wie man Kernelmodule entwickelt . Mit Hilfe von netfilter (nftables / iptables) können Sie Netzwerkpakete in den Benutzerraum umleiten und dort mit primitiven improvisierten Mitteln verarbeiten : modifizieren (optional) ) und gib es dem Kernel zurück oder verwerfe es.



Für einige Programmiersprachen gibt es Bindungen für die Arbeit mit nfqueue, für Bash gab es keine (heh, nicht überraschend), ich musste Python verwenden: ipipou verwendet NetfilterQueue .



Wenn die Leistung nicht kritisch ist, können Sie mit Hilfe dieser Funktion relativ schnell und einfach Ihre eigene Logik für die Arbeit mit Paketen auf einer relativ niedrigen Ebene erstellen, z. B. experimentelle Datenübertragungsprotokolle erstellen oder lokale und Remote-Dienste mit nicht standardisiertem Verhalten trollen.



Raw-Sockets arbeiten Hand in Hand mit nfqueue. Wenn beispielsweise der Tunnel bereits konfiguriert ist und FOU den gewünschten Port abhört, funktioniert das Senden eines Pakets über denselben Port nicht auf die übliche Weise. Es ist ausgelastet, aber Sie können ein zufällig generiertes Paket direkt in das Netzwerk aufnehmen und ausführen Schnittstelle mit einem Raw-Socket, obwohl Sie etwas mehr über das Generieren eines solchen Pakets basteln müssen. Auf diese Weise werden Pakete mit Authentifizierung in ipipou erstellt.



Da ipipou nur die ersten Pakete von der Verbindung verarbeitet (also diejenigen, die es geschafft haben, in die Warteschlange zu gelangen, bevor die Verbindung hergestellt wurde), leidet die Leistung kaum.



Sobald der ipipou-Server ein authentifiziertes Paket empfängt, wird ein Tunnel erstellt und alle nachfolgenden Pakete in der Verbindung werden bereits vom Kernel verarbeitet, der nfqueue umgeht. Wenn die Verbindung schlecht ist, wird das erste Paket des nächsten abhängig von den Einstellungen an die Warteschlange nfqueue gesendet. Wenn es sich nicht um ein Authentifizierungspaket handelt, sondern um die zuletzt gespeicherte IP und den Client-Port, kann es entweder weitergeleitet oder verworfen werden. Wenn ein authentifiziertes Paket von einer neuen IP und einem neuen Port stammt, wird der Tunnel für die Verwendung neu konfiguriert.



Die übliche IPIP-over-FOU hat ein weiteres Problem bei der Arbeit mit NAT: Sie können nicht zwei in UDP gekapselte IPIP-Tunnel mit derselben IP erstellen, da die FOU- und IPIP-Module ziemlich voneinander isoliert sind. Jene. Ein Paar von Clients hinter derselben öffentlichen IP kann auf diese Weise nicht gleichzeitig eine Verbindung zu demselben Server herstellen. In Zukunft kann es auf Kernel-Ebene gelöst werden, aber das ist nicht sicher. In der Zwischenzeit können NAT-Probleme durch NAT gelöst werden. Wenn ein IP-Adresspaar bereits von einem anderen Tunnel belegt ist, wechselt ipipou von einer öffentlichen zu einer alternativen privaten IP, voila! - Sie können Tunnel erstellen, bis die Ports leer sind.



weil Da nicht alle Pakete in der Verbindung signiert sind, ist ein derart einfacher Schutz für MITM anfällig. Wenn also ein Bösewicht zwischen dem Client und dem Server lauert, der den Datenverkehr abhören und steuern kann, kann er authentifizierte Pakete über eine andere Adresse umleiten und einen Tunnel von einem nicht vertrauenswürdigen Host erstellen ...



Wenn jemand Ideen hat, wie dies behoben werden kann, während der Großteil des Datenverkehrs im Kern bleibt, können Sie sich gerne melden.



Die UDP-Kapselung hat sich übrigens sehr gut bewährt. Im Vergleich zur Kapselung über IP ist sie trotz des zusätzlichen UDP-Header-Overheads viel stabiler und häufig schneller. Dies liegt an der Tatsache, dass die Mehrheit der Hosts im Internet mit nur den drei beliebtesten Protokollen erträglich gut funktioniert: TCP, UDP, ICMP. Der materielle Teil kann im Allgemeinen alles andere verwerfen oder langsamer verarbeiten, da er nur für diese drei optimiert ist.



Beispielsweise wurde QUICK, auf dessen Grundlage HTTP / 3 erstellt wurde, über UDP und nicht über IP erstellt.



Gut genug Worte, es ist Zeit zu sehen, wie es in der "realen Welt" funktioniert.



Schlacht



Wird verwendet, um die reale Welt zu emulieren iperf3. In Bezug auf den Grad der Nähe zur Realität geht es um die Nachahmung der realen Welt in Minecraft, aber im Moment wird es reichen.



Der Wettbewerb beinhaltet:

  • Referenz-Master-Kanal
  • Der Held dieses Artikels ist ipipou
  • OpenVPN mit Authentifizierung, aber ohne Verschlüsselung
  • OpenVPN All Inclusive
  • WireGuard ohne PresharedKey, mit MTU = 1440 (nur für IPv4)


Technische Daten für Geeks
Metriken werden von den folgenden Befehlen



auf dem Client übernommen:



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"


ICMP-Latenz

ping -c 10 SERVER_IP | tail -1


( ):



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"




ipipou



/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





/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 ( , )



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




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 (c , , UDP, )

openvpn-manage



wireguard



/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





/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



Ergebnisse



Rohe hässliche Tablette
CPU , .. :



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




Kanal für 20 Mbit / s



Bandbreitenvergleich bei 20 Mbit / s



Vergleich der Latenz bei 20 Mbit / s



Kanal für 1 optimistische Gbit / s



1-Gbit / s-Bandbreitenvergleich



Vergleich der CPU-Effizienz: Mbit / s / CPU-Auslastung



In allen Fällen liegt ipipou in Bezug auf die Leistung ziemlich nahe am Basiskanal, und das ist großartig!



Der unverschlüsselte openvpn-Tunnel verhielt sich in beiden Fällen ziemlich seltsam.



Wenn jemand es testen wird, wird es interessant sein, Feedback zu hören.



Mögen IPv6 und NetPrickle bei uns sein!



All Articles