ipipou: daugiau nei tik nešifruotas tunelis

Ką sakome IPv6 Dievui?

ipipou: daugiau nei tik nešifruotas tunelis
Teisingai, šiandien tą patį pasakysime šifravimo dievui.

Čia kalbėsime apie nešifruotą IPv4 tunelį, bet ne apie „šiltą lempą“, o apie modernią „LED“. Taip pat čia mirksi neapdoroti lizdai, vyksta darbas su paketais vartotojo erdvėje.

Kiekvienam skoniui ir spalvai yra N tuneliavimo protokolų:

  • stilinga, madinga, jaunatviška WireGuard
  • daugiafunkciniai, pavyzdžiui, šveicariški peiliai, OpenVPN ir SSH
  • senas ir neblogas GRE
  • Paprasčiausias, greitas, visiškai nešifruotas IPIP
  • aktyviai vystosi GENĖVĖ
  • daugelis kitų.

Bet aš esu programuotojas, todėl N padidinsiu tik trupmena, o tikrų protokolų kūrimą paliksiu Kommersant kūrėjams.

Viename negimusiame juodraštįTai, ką dabar darau, yra pasiekti šeimininkus už NAT iš išorės. Tam naudodamas protokolus su suaugusiųjų kriptografija, negalėjau atsikratyti jausmo, kad tai lyg iš patrankos šaudyti į žvirblius. Nes tunelis dažniausiai naudojamas tik NAT-e skylėms kišti, vidinis srautas dažniausiai taip pat šifruojamas, bet jie vis tiek paskęsta HTTPS.

Tyrinėjant įvairius tuneliavimo protokolus, mano vidinio perfekcionisto dėmesį vėl ir vėl patraukė IPIP dėl minimalių papildomų išlaidų. Tačiau jis turi pusantro reikšmingo mano užduočių trūkumų:

  • tam reikia viešųjų IP iš abiejų pusių,
  • ir jums jokio autentifikavimo.

Todėl perfekcionistas buvo nuvarytas atgal į tamsų kaukolės kampą arba kur jis ten sėdi.

Ir tada vieną dieną, skaitant straipsnius apie natūraliai palaikomi tuneliai Linuxe susidūriau su FOU (Foo-over-UDP), t.y. bet koks, suvyniotas į UDP. Kol kas palaikomos tik IPIP ir GUE (bendroji UDP inkapsuliacija).

„Štai sidabrinė kulka! Man užtenka paprasto IPIP. - As maniau.

Tiesą sakant, kulka pasirodė ne visiškai sidabrinė. Inkapsuliacija UDP išsprendžia pirmąją problemą – galite prisijungti prie klientų už NAT iš išorės naudodami iš anksto nustatytą ryšį, tačiau čia pusė kito IPIP trūkumo išryškėja naujoje šviesoje – už matomo gali pasislėpti bet kas iš privataus tinklo. viešasis IP ir kliento prievadas (grynajame IPIP ši problema neegzistuoja).

Norint išspręsti šią pusantros problemos, gimė įrankis ipipou. Jis įgyvendina namuose sukurtą nuotolinio pagrindinio kompiuterio autentifikavimo mechanizmą, netrikdydamas branduolio FOU veikimo, kuris greitai ir efektyviai apdoros paketus branduolio erdvėje.

Mums nereikia jūsų scenarijaus!

Gerai, jei žinote kliento viešąjį prievadą ir IP (pavyzdžiui, visi, esantys už jo, niekur neina, NAT bando susieti prievadus 1-in-1), galite sukurti IPIP-over-FOU tunelį su sekančias komandas, be jokių scenarijų.

serveryje:

# Подгрузить модуль ядра 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

ant kliento:

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

kur

  • ipipou* — vietinio tunelio tinklo sąsajos pavadinimas
  • 203.0.113.1 — viešasis IP serveris
  • 198.51.100.2 - viešas kliento IP
  • 192.168.0.2 — sąsajai eth0 priskirtas kliento IP
  • 10001 — FOU vietinis kliento prievadas
  • 20001 — viešasis FOU kliento prievadas
  • 10000 — viešasis serverio prievadas, skirtas FOU
  • encap-csum - galimybė pridėti UDP kontrolinę sumą į inkapsuliuotus UDP paketus; galima pakeisti noencap-csum, jau nekalbant, vientisumą jau kontroliuoja išorinis kapsulės sluoksnis (kol paketas yra tunelio viduje)
  • eth0 — vietinė sąsaja, su kuria bus susietas ipip tunelis
  • 172.28.0.1 - kliento tunelio sąsajos IP (privatus)
  • 172.28.0.0 - IP tunelio serverio sąsaja (privati)

Kol gyvas UDP ryšys, tunelis veiks, bet jei nutrūks, pasiseks – jei kliento IP: prievadas liks toks pat – gyvuos, jei keisis – suges.

Lengviausias būdas viską pasukti atgal yra iškrauti branduolio modulius: modprobe -r fou ipip

Net jei autentifikavimo nereikia, kliento viešasis IP ir prievadas ne visada yra žinomi ir dažnai yra nenuspėjami arba kintantys (priklausomai nuo NAT tipo). Jei praleisite encap-dport serverio pusėje tunelis neveiks, nėra pakankamai protingas paimti nuotolinio ryšio prievadą. Tokiu atveju gali padėti ir ipipou, arba WireGuard ir kiti panašūs.

Kaip tai veikia?

Klientas (kuris paprastai yra už NAT) atidaro tunelį (kaip aukščiau pateiktame pavyzdyje) ir siunčia autentifikavimo paketą į serverį, kad jis sukonfigūruotų tunelį savo pusėje. Priklausomai nuo nustatymų, tai gali būti tuščias paketas (tik tam, kad serveris matytų viešą IP: ryšio prievadą), arba su duomenimis, pagal kuriuos serveris gali identifikuoti klientą. Duomenys gali būti paprasta slaptažodžio frazė aiškiame tekste (atsižvelgiama į analogiją su HTTP Basic Auth) arba specialiai sukurti duomenys, pasirašyti privačiu raktu (panašiai kaip HTTP santraukos autentifikavimas, tik stipresnis, žr. client_auth kode).

Serveryje (toje pusėje, kurioje yra viešasis IP), kai ipipou paleidžiamas, jis sukuria nfqueue eilės tvarkyklę ir sukonfigūruoja netfilter, kad reikalingi paketai būtų siunčiami ten, kur jie turi būti: paketai, inicijuojantys ryšį su nfqueue eile, ir [beveik] visa kita eina tiesiai į klausytoją FOU.

Nežinantiems, nfqueue (arba NetfilterQueue) yra ypatingas dalykas mėgėjams, kurie nemoka kurti branduolio modulių, kurie naudojant netfilter (nftables/iptables) leidžia nukreipti tinklo paketus į vartotojo erdvę ir ten juos apdoroti. primityvios priemonės: modifikuoti (neprivaloma) ir grąžinti branduoliui arba išmesti.

Kai kurioms programavimo kalboms yra susiejimas darbui su nfqueue, bash jų nebuvo (heh, nenuostabu), turėjau naudoti python: ipipou uses NetfilterQueue.

Jei našumas nėra labai svarbus, naudodamiesi šiuo dalyku galite gana greitai ir lengvai susikurti savo logiką, kaip dirbti su gana žemo lygio paketais, pavyzdžiui, sukurti eksperimentinius duomenų perdavimo protokolus arba nestandartinio elgesio vietines ir nuotolines paslaugas.

Raw sockets veikia kartu su nfqueue, pavyzdžiui, kai tunelis jau sukonfigūruotas ir FOU klausosi norimame prievade, negalėsite išsiųsti paketo iš to paties prievado įprastu būdu – jis užimtas, bet galite paimti ir nusiųsti atsitiktinai sugeneruotą paketą tiesiai į tinklo sąsają naudodami neapdorotą lizdą, nors norint sukurti tokį paketą, reikės šiek tiek daugiau padirbėti. Taip ipipou sukuriami paketai su autentifikavimu.

Kadangi ipipou apdoroja tik pirmuosius ryšio paketus (ir tuos, kurie sugebėjo nutekėti į eilę prieš užmezgant ryšį), našumas beveik nenukenčia.

Kai tik ipipou serveris gauna autentifikuotą paketą, sukuriamas tunelis ir visi tolesni ryšio paketai jau apdorojami branduolio, apeinant nfqueue. Jei nepavyks prisijungti, pirmas kito paketas bus siunčiamas į nfqueue eilę, priklausomai nuo nustatymų, jei tai ne paketas su autentifikavimu, bet iš paskutinio prisiminto IP ir kliento prievado, jis gali būti perduotas arba įjungtas arba išmestas. Jei autentifikuotas paketas gaunamas iš naujo IP ir prievado, tunelis iš naujo sukonfigūruojamas, kad juos naudotų.

Įprastas IPIP-over-FOU turi dar vieną bėdą dirbant su NAT – neįmanoma sukurti dviejų IPIP tunelių, įterptų į UDP su tuo pačiu IP, nes FOU ir IPIP moduliai yra gana izoliuoti vienas nuo kito. Tie. Klientų pora, esanti už to paties viešojo IP, negalės vienu metu prisijungti prie to paties serverio tokiu būdu. Ateityje, galbūt, tai bus išspręsta branduolio lygiu, bet tai nėra tikra. Tuo tarpu NAT problemas gali išspręsti NAT – jei atsitiks taip, kad IP adresų pora jau bus užimta kito tunelio, ipipou atliks NAT iš viešojo į alternatyvų privatų IP, voila! - galite kurti tunelius, kol baigsis prievadai.

Nes Ne visi ryšio paketai yra pasirašyti, tada ši paprasta apsauga yra pažeidžiama MITM, taigi, jei kelyje tarp kliento ir serverio slepiasi piktadarys, galintis klausytis srauto ir juo manipuliuoti, jis gali peradresuoti autentifikuotus paketus per kitą adresą ir sukurkite tunelį iš nepatikimo pagrindinio kompiuterio .

Jei kas nors turi idėjų, kaip tai ištaisyti paliekant didžiąją dalį srauto centre, nedvejodami pasikalbėkite.

Beje, inkapsuliavimas į UDP labai gerai pasiteisino. Palyginti su inkapsuliavimu per IP, jis yra daug stabilesnis ir dažnai greitesnis, nepaisant papildomų UDP antraštės išlaidų. Taip yra dėl to, kad dauguma interneto kompiuterių gerai veikia tik su trimis populiariausiais protokolais: TCP, UDP, ICMP. Apčiuopiama dalis gali visiškai išmesti visa kita arba apdoroti lėčiau, nes ji optimizuota tik šiems trims.

Pavyzdžiui, todėl QUICK, kuriuo pagrįstas HTTP/3, buvo sukurtas ant UDP, o ne ant IP.

Na, užtenka žodžių, laikas pažiūrėti, kaip tai veikia „realiame pasaulyje“.

Mūšis

Naudojamas mėgdžioti realų pasaulį iperf3. Kalbant apie artumo realybei laipsnį, tai yra maždaug toks pat, kaip imituoti realų pasaulį „Minecraft“, bet kol kas tai tiks.

Konkurso dalyviai:

  • pagrindinio kanalo nuoroda
  • šio straipsnio herojus yra ipipou
  • OpenVPN su autentifikavimu, bet be šifravimo
  • OpenVPN viskas įskaičiuota režimu
  • „WireGuard“ be išankstinio bendrinimo rakto, su MTU=1440 (tik IPv4)

Techniniai duomenys geeks
Metrika paimama naudojant šias komandas:

ant kliento:

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 delsa

ping -c 10 SERVER_IP | tail -1

serveryje (veikia vienu metu su klientu):

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"

Tunelio konfigūracija

ipipou
serverio
/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

klientas
/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 (be šifravimo, su autentifikavimu)
serverio

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

klientas

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 (su šifravimu, autentifikavimu, per UDP, viskas, kaip tikėtasi)
Sukonfigūruotas naudojant openvpn-manage

vielos apsauga
serverio
/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

klientas
/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

rezultatai

Drėgnas bjaurus ženklas
Serverio procesoriaus apkrova nėra labai orientacinė, nes... Ten veikia daug kitų paslaugų, kartais jos sunaudoja išteklius:

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 kanalas

ipipou: daugiau nei tik nešifruotas tunelis

ipipou: daugiau nei tik nešifruotas tunelis

kanalas už 1 optimistinį Gbps

ipipou: daugiau nei tik nešifruotas tunelis

ipipou: daugiau nei tik nešifruotas tunelis

Visais atvejais ipipou yra gana artimas baziniam kanalui, o tai yra puiku!

Nešifruotas openvpn tunelis abiem atvejais elgėsi gana keistai.

Jei kas ketina išbandyti, bus įdomu išgirsti atsiliepimus.

Tegul IPv6 ir NetPrickle būna su mumis!

Šaltinis: www.habr.com

Добавить комментарий