ipipou: viac ako len nešifrovaný tunel

Čo hovoríme Bohu IPv6?

ipipou: viac ako len nešifrovaný tunel
To je pravda, to isté povieme dnes bohu šifrovania.

Tu sa budeme baviť o nešifrovanom IPv4 tuneli, nie však o „teplej lampe“, ale o modernej „LED“. A blikajú tu aj raw sockety a pracuje sa s paketmi v užívateľskom priestore.

Existuje N tunelovacích protokolov pre každý vkus a farbu:

  • štýlový, módny, mladistvý WireGuard
  • multifunkčné, ako sú švajčiarske nože, OpenVPN a SSH
  • starý a nie zlý GRE
  • najjednoduchší, najrýchlejší, úplne nešifrovaný IPIP
  • aktívne rozvíjať GENEVE
  • mnoho dalších.

Som ale programátor, takže N zvýšim len o zlomok a vývoj skutočných protokolov nechám na vývojárov z Kommersantu.

V jednom nenarodenom projektTo, čo teraz robím, je osloviť hostiteľov za NAT zvonku. Pomocou protokolov s kryptografiou pre dospelých som sa nemohol zbaviť pocitu, že je to ako strieľať vrabce z dela. Pretože tunel sa pouziva z vacsej casti len na vysekanie dier v NAT-e, interna komunikacia je vacsinou tiez sifrovana, ale aj tak sa topia v HTTPS.

Počas skúmania rôznych tunelovacích protokolov sa pozornosť môjho vnútorného perfekcionistu znova a znova upútala na IPIP kvôli jeho minimálnej réžii. Má však jeden a pol významných nevýhod pre moje úlohy:

  • vyžaduje verejné IP adresy na oboch stranách,
  • a žiadne overenie pre vás.

Preto bol perfekcionista zahnaný späť do temného kúta lebky, alebo kamkoľvek si tam sadne.

A potom jedného dňa, pri čítaní článkov o natívne podporované tunely v Linuxe som narazil na FOU (Foo-over-UDP), t.j. čokoľvek, zabalené v UDP. Zatiaľ sú podporované iba IPIP a GUE (Generic UDP Encapsulation).

„Tu je strieborná guľka! Stačí mi jednoduchý IPIP.“ - Myslel som.

V skutočnosti sa ukázalo, že guľka nie je úplne strieborná. Zapuzdrenie v UDP rieši prvý problém – ku klientom za NAT sa môžete pripojiť zvonku pomocou vopred vytvoreného spojenia, ale tu sa polovica ďalšej nevýhody IPIP rozkvitá v novom svetle – ktokoľvek zo súkromnej siete sa môže schovať za viditeľné verejná IP a klientsky port (v čistom IPIP tento problém neexistuje).

Na vyriešenie tohto jeden a pol problému sa zrodil nástroj ipipou. Implementuje podomácky vytvorený mechanizmus na autentifikáciu vzdialeného hostiteľa, bez narušenia prevádzky FOU jadra, ktorý bude rýchlo a efektívne spracovávať pakety v priestore jadra.

Nepotrebujeme váš skript!

Ok, ak poznáte verejný port a IP klienta (napríklad všetci za ním nikam nechodia, NAT sa snaží mapovať porty 1 v 1), môžete vytvoriť tunel IPIP-over-FOU pomocou nasledujúce príkazy 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

u klienta:

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

kde

  • ipipou* — názov sieťového rozhrania lokálneho tunela
  • 203.0.113.1 — verejný IP server
  • 198.51.100.2 — verejná IP klienta
  • 192.168.0.2 — IP klienta priradená k rozhraniu eth0
  • 10001 — miestny klientsky port pre FOU
  • 20001 — verejný klientsky port pre FOU
  • 10000 — verejný port servera pre FOU
  • encap-csum — možnosť pridať kontrolný súčet UDP k zapuzdreným paketom UDP; možno nahradiť noencap-csumNehovoriac o tom, že integrita je už riadená vonkajšou vrstvou zapuzdrenia (keď je paket vo vnútri tunela)
  • eth0 — lokálne rozhranie, ku ktorému bude pripojený tunel ipip
  • 172.28.0.1 — IP rozhrania klientskeho tunela (súkromné)
  • 172.28.0.0 — Rozhranie servera IP tunela (súkromné)

Kým bude pripojenie UDP živé, tunel bude fungovať, ale ak sa pokazí, budete mať šťastie - ak IP: port klienta zostane rovnaký - bude žiť, ak sa zmenia - preruší sa.

Najjednoduchší spôsob, ako vrátiť všetko späť, je uvoľniť moduly jadra: modprobe -r fou ipip

Aj keď sa autentifikácia nevyžaduje, verejná IP a port klienta nie sú vždy známe a často sú nepredvídateľné alebo premenlivé (v závislosti od typu NAT). Ak vynecháte encap-dport na strane servera tunel nebude fungovať, nie je dosť inteligentný na to, aby zabral port vzdialeného pripojenia. V tomto prípade môže pomôcť aj ipipou, prípadne vám môže pomôcť WireGuard a jemu podobné.

Ako to funguje?

Klient (ktorý je zvyčajne za NAT) otvorí tunel (ako vo vyššie uvedenom príklade) a odošle autentifikačný paket na server, aby nakonfiguroval tunel na svojej strane. V závislosti od nastavení to môže byť prázdny paket (len preto, aby server videl verejnú IP: port pripojenia), alebo s údajmi, podľa ktorých server dokáže identifikovať klienta. Dáta môžu byť jednoduchá prístupová fráza vo forme čistého textu (napadá ma analógia s HTTP Basic Auth) alebo špeciálne navrhnuté dáta podpísané súkromným kľúčom (podobne ako HTTP Digest Auth len silnejšie, pozri funkciu client_auth v kóde).

Na serveri (na strane s verejnou IP), keď sa ipipou spustí, vytvorí obsluhu fronty nfqueue a nakonfiguruje netfilter tak, aby sa potrebné pakety posielali tam, kde majú byť: pakety inicializujúce pripojenie k fronte nfqueue a [takmer] všetko ostatné ide priamo k poslucháčovi FOU.

Pre tých, ktorí nevedia, nfqueue (alebo NetfilterQueue) je špeciálna vec pre amatérov, ktorí nevedia, ako vyvíjať moduly jadra, ktoré vám pomocou netfilter (nftables/iptables) umožňujú presmerovať sieťové pakety do používateľského priestoru a spracovať ich tam pomocou primitívne prostriedky po ruke: upravte (voliteľné) a dajte ho späť do jadra alebo ho zahoďte.

Pre niektoré programovacie jazyky existujú väzby pre prácu s nfqueue, pre bash neboli žiadne (heh, nie je prekvapujúce), musel som použiť python: ipipou používa NetfilterQueue.

Ak výkon nie je kritický, pomocou tejto veci si môžete pomerne rýchlo a jednoducho vymyslieť vlastnú logiku pre prácu s paketmi na pomerne nízkej úrovni, napríklad vytvoriť experimentálne protokoly prenosu dát alebo trolovať lokálne a vzdialené služby s neštandardným správaním.

Raw sockety fungujú ruka v ruke s nfqueue, napríklad keď je tunel už nakonfigurovaný a FOU počúva na požadovanom porte, nebudete môcť poslať paket z rovnakého portu obvyklým spôsobom - je zaneprázdnený, ale môžete vziať a odoslať náhodne vygenerovaný paket priamo do sieťového rozhrania pomocou surového soketu, aj keď vygenerovanie takéhoto paketu bude vyžadovať trochu viac práce. Takto sa v ipipou vytvárajú pakety s autentifikáciou.

Keďže ipipou spracováva iba prvé pakety z pripojenia (a tie, ktoré stihli uniknúť do fronty pred vytvorením pripojenia), výkon takmer neutrpí.

Akonáhle server ipipou prijme overený paket, vytvorí sa tunel a všetky nasledujúce pakety v spojení už spracuje jadro obchádzajúce nfqueue. Ak spojenie zlyhá, do fronty nfqueue sa v závislosti od nastavení odošle prvý paket nasledujúceho, ak nejde o paket s autentifikáciou, ale z poslednej zapamätanej IP a klientskeho portu, môže sa buď odovzdať na alebo vyradené. Ak autentifikovaný paket pochádza z novej IP a portu, tunel sa prekonfiguruje tak, aby ich používal.

Bežný IPIP-over-FOU má pri práci s NAT ešte jeden problém - nie je možné vytvoriť dva IPIP tunely zapuzdrené v UDP s rovnakou IP, pretože moduly FOU a IPIP sú od seba dosť izolované. Tie. dvojica klientov za rovnakou verejnou IP sa nebude môcť týmto spôsobom súčasne pripojiť k rovnakému serveru. Nabudúce, možná, bude sa to riešiť na úrovni jadra, ale nie je to isté. Medzitým sa problémy s NATom dajú vyriešiť NATom - ak sa stane, že pár IP adries je už obsadených iným tunelom, ipipou urobí NAT z verejnej na alternatívnu súkromnú IP, voila! - môžete vytvárať tunely, kým sa neminú porty.

Pretože Nie všetky pakety v spojení sú podpísané, potom je táto jednoduchá ochrana zraniteľná voči MITM, takže ak na ceste medzi klientom a serverom číha zloduch, ktorý môže načúvať prevádzke a manipulovať s ňou, môže presmerovať overené pakety cez inú adresu a vytvorte tunel z nedôveryhodného hostiteľa.

Ak má niekto nápady, ako to napraviť a zároveň ponechať väčšinu návštevnosti v jadre, neváhajte sa ozvať.

Mimochodom, zapuzdrenie v UDP sa osvedčilo veľmi dobre. V porovnaní so zapuzdrením cez IP je oveľa stabilnejšia a často rýchlejšia napriek dodatočnej réžii hlavičky UDP. Je to spôsobené tým, že väčšina hostiteľov na internete funguje dobre iba s tromi najpopulárnejšími protokolmi: TCP, UDP, ICMP. Hmotná časť dokáže všetko ostatné úplne vyhodiť, prípadne spracovať pomalšie, pretože je optimalizovaná len pre tieto tri.

Napríklad to je dôvod, prečo bol QUICK, na ktorom je založený HTTP/3, vytvorený nad UDP, a nie nad IP.

No dosť slov, je čas vidieť, ako to funguje v „reálnom svete“.

Bitka

Používa sa na napodobňovanie skutočného sveta iperf3. Pokiaľ ide o mieru blízkosti k realite, je to približne rovnaké ako emulácia skutočného sveta v Minecrafte, ale zatiaľ to bude stačiť.

Účastníci súťaže:

  • referenčný hlavný kanál
  • hrdinom tohto článku je ipipou
  • OpenVPN s autentifikáciou, ale bez šifrovania
  • OpenVPN v režime all-inclusive
  • WireGuard bez predzdieľaného kľúča, s MTU=1440 (od iba IPv4)

Technické údaje pre geekov
Metriky sa získavajú pomocou nasledujúcich príkazov:

u klienta:

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 latencia

ping -c 10 SERVER_IP | tail -1

na serveri (beží 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"

Konfigurácia tunela

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

zákazníka
/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  # Затем надо передать 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

zákazníka

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 podľa očakávania)
Konfigurované pomocou openvpn-manage

drôtený chránič
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

zákazníka
/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

Vlhké škaredé znamenie
Zaťaženie CPU servera nie je príliš orientačné, pretože... Beží tam mnoho ďalších služieb, ktoré niekedy spotrebujú zdroje:

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

20 Mbps kanál

ipipou: viac ako len nešifrovaný tunel

ipipou: viac ako len nešifrovaný tunel

kanál na 1 optimistický Gbps

ipipou: viac ako len nešifrovaný tunel

ipipou: viac ako len nešifrovaný tunel

Vo všetkých prípadoch je ipipou výkonom dosť blízko k základnému kanálu, čo je skvelé!

Nezašifrovaný openvpn tunel sa v oboch prípadoch správal dosť zvláštne.

Ak to niekto bude testovať, bude zaujímavé počuť spätnú väzbu.

Nech sú IPv6 a NetPrickle s nami!

Zdroj: hab.com

Pridať komentár