ipipou: më shumë se thjesht një tunel i pakriptuar

Çfarë po i themi Zotit të IPv6?

ipipou: më shumë se thjesht një tunel i pakriptuar
Kjo është e drejtë, ne do t'i themi të njëjtën gjë zotit të kriptimit sot.

Këtu do të flasim për një tunel IPv4 të pakriptuar, por jo për një "llambë të ngrohtë", por për një "LED" moderne. Dhe këtu ka edhe priza të papërpunuara, dhe puna është duke u zhvilluar me paketat në hapësirën e përdoruesit.

Ekzistojnë N protokolle tunelimi për çdo shije dhe ngjyrë:

  • elegant, në modë, rinor WireGuard
  • multifunksionale, si thikat zvicerane, OpenVPN dhe SSH
  • GRE e vjetër dhe jo e keqe
  • IPIP më i thjeshtë, i shpejtë, plotësisht i pakriptuar
  • duke u zhvilluar në mënyrë aktive GJENI
  • shumë të tjerë.

Por unë jam një programues, kështu që do të rris N vetëm me një fraksion dhe do t'ua lë zhvillimin e protokolleve reale zhvilluesve të Kommersant.

Në një të palindur projektiAjo që po bëj tani është të arrij hostet pas NAT nga jashtë. Duke përdorur protokolle me kriptografi të të rriturve për këtë, nuk mund të lëkundema ndjesinë se ishte si të gjuaje harabela nga një top. Sepse tuneli përdoret në pjesën më të madhe vetëm për të hapur vrima në NAT-e, trafiku i brendshëm zakonisht është gjithashtu i koduar, por ato ende mbyten në HTTPS.

Ndërsa hulumtoja protokollet e ndryshme të tunelit, vëmendja e perfeksionistit tim të brendshëm u tërhoq nga IPIP pa pushim për shkak të shpenzimeve të tij minimale. Por ka një të metë e gjysmë domethënëse për detyrat e mia:

  • kërkon IP publike nga të dyja anët,
  • dhe nuk ka vërtetim për ju.

Prandaj, perfeksionisti u shty përsëri në cepin e errët të kafkës, ose kudo që ai ulet atje.

Dhe pastaj një ditë, duke lexuar artikuj në tunele të mbështetur në mënyrë vendase në Linux hasa në FOU (Foo-over-UDP), d.m.th. çfarëdo, të mbështjellë me UDP. Deri më tani, mbështeten vetëm IPIP dhe GUE (Generic UDP Encapsulation).

“Këtu është plumbi i argjendtë! Më mjafton një IPIP i thjeshtë.” - Une mendova.

Në fakt, plumbi rezultoi të mos ishte plotësisht i argjendtë. Enkapsulimi në UDP zgjidh problemin e parë - ju mund të lidheni me klientët pas NAT nga jashtë duke përdorur një lidhje të paracaktuar, por këtu gjysma e pengesës tjetër të IPIP lulëzon në një dritë të re - kushdo nga një rrjet privat mund të fshihet pas të dukshmes IP publike dhe porta e klientit (në IPIP të pastër ky problem nuk ekziston).

Për të zgjidhur këtë problem një e gjysmë, lindi shërbimi ipipou. Ai zbaton një mekanizëm të bërë në shtëpi për vërtetimin e një hosti të largët, pa ndërprerë funksionimin e kernelit FOU, i cili do të përpunojë shpejt dhe me efikasitet paketat në hapësirën e kernelit.

Ne nuk kemi nevojë për skenarin tuaj!

Ok, nëse e dini portën publike dhe IP-në e klientit (për shembull, të gjithë pas saj nuk shkojnë askund, NAT përpiqet të hartojë portet 1-në-1), mund të krijoni një tunel IPIP-mbi-FOU me komandat e mëposhtme, pa asnjë skript.

në 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

mbi klientin:

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

ku

  • ipipou* — emri i ndërfaqes së rrjetit të tunelit lokal
  • 203.0.113.1 — server IP publik
  • 198.51.100.2 — IP publike e klientit
  • 192.168.0.2 — IP-ja e klientit e caktuar në ndërfaqen eth0
  • 10001 — porti lokal i klientit për FOU
  • 20001 — porta e klientit publik për FOU
  • 10000 — porta e serverit publik për FOU
  • encap-csum — opsioni për të shtuar një shumë kontrolli UDP në paketat e kapsuluara të UDP; mund të zëvendësohet nga noencap-csum, për të mos përmendur, integriteti tashmë kontrollohet nga shtresa e jashtme e kapsulimit (ndërsa paketa është brenda tunelit)
  • eth0 — ndërfaqja lokale në të cilën do të lidhet tuneli ipip
  • 172.28.0.1 — IP e ndërfaqes së tunelit të klientit (private)
  • 172.28.0.0 — Ndërfaqja e serverit të tunelit IP (private)

Për sa kohë që lidhja UDP është e gjallë, tuneli do të jetë në gjendje pune, por nëse prishet, do të keni fat - nëse IP: porti i klientit mbetet i njëjtë - ai do të jetojë, nëse ndryshojnë - do të prishet.

Mënyra më e lehtë për të kthyer gjithçka është të shkarkoni modulet e kernelit: modprobe -r fou ipip

Edhe nëse nuk kërkohet vërtetimi, IP-ja dhe porta publike e klientit nuk njihen gjithmonë dhe shpesh janë të paparashikueshme ose të ndryshueshme (në varësi të llojit NAT). Nëse e lëshoni encap-dport në anën e serverit, tuneli nuk do të funksionojë, nuk është mjaft i zgjuar për të marrë portën e lidhjes në distancë. Në këtë rast, ipipou mund të ndihmojë gjithashtu, ose WireGuard dhe të tjerë si ai mund t'ju ndihmojnë.

Si funksionon kjo gjë?

Klienti (i cili është zakonisht pas NAT) hap një tunel (si në shembullin e mësipërm) dhe dërgon një paketë vërtetimi te serveri në mënyrë që ai të konfigurojë tunelin në anën e tij. Në varësi të cilësimeve, kjo mund të jetë një paketë boshe (vetëm që serveri të shohë IP-në publike: portin e lidhjes), ose me të dhëna me të cilat serveri mund të identifikojë klientin. Të dhënat mund të jenë një frazë e thjeshtë kalimi në tekst të qartë (të vjen ndërmend analogjia me HTTP Basic Auth) ose të dhëna të krijuara posaçërisht të nënshkruara me një çelës privat (i ngjashëm me HTTP Digest Auth vetëm më i fortë, shih funksionin client_auth në kod).

Në server (në anën me IP-në publike), kur ipipou fillon, ai krijon një mbajtës të radhës nfqueue dhe konfiguron netfilterin në mënyrë që paketat e nevojshme të dërgohen aty ku duhet të jenë: paketat që inicializojnë lidhjen me radhën nfqueue, dhe [pothuajse] të gjitha të tjerat shkojnë drejt e te dëgjuesi FOU.

Për ata që nuk e dinë, nfqueue (ose NetfilterQueue) është një gjë e veçantë për amatorët që nuk dinë të zhvillojnë module kernel, të cilat duke përdorur netfilter (nftables/iptables) ju lejon të ridrejtoni paketat e rrjetit në hapësirën e përdoruesit dhe t'i përpunoni ato atje duke përdorur mjete primitive në dispozicion: modifiko (opsionale ) dhe ktheje atë në kernel, ose hidhe atë.

Për disa gjuhë programimi ka lidhje për të punuar me nfqueue, për bash nuk kishte asnjë (heh, nuk është për t'u habitur), më duhej të përdor python: ipipou përdor NetfilterQueue.

Nëse performanca nuk është kritike, duke përdorur këtë gjë, ju mund të krijoni relativisht shpejt dhe me lehtësi logjikën tuaj për të punuar me paketa në një nivel mjaft të ulët, për shembull, të krijoni protokolle eksperimentale të transferimit të të dhënave ose të kontrolloni shërbimet lokale dhe të largëta me sjellje jo standarde.

Prizat e papërpunuara punojnë dorë për dore me nfqueue, për shembull, kur tuneli është tashmë i konfiguruar dhe FOU po dëgjon në portën e dëshiruar, nuk do të mund të dërgoni një paketë nga e njëjta port në mënyrën e zakonshme - është e zënë, por ju mund të merrni dhe dërgoni një paketë të krijuar në mënyrë rastësore direkt në ndërfaqen e rrjetit duke përdorur një prizë të papërpunuar, megjithëse gjenerimi i një pakete të tillë do të kërkojë pak më shumë kujdes. Kështu krijohen paketat me vërtetim në ipipou.

Meqenëse ipipou përpunon vetëm paketat e para nga lidhja (dhe ato që arritën të rrjedhin në radhë përpara se të vendosej lidhja), performanca pothuajse nuk vuan.

Sapo serveri ipipou merr një paketë të vërtetuar, krijohet një tunel dhe të gjitha paketat pasuese në lidhje përpunohen tashmë nga kerneli duke anashkaluar nfqueue. Nëse lidhja dështon, atëherë paketa e parë e asaj tjetër do të dërgohet në radhën nfqueue, në varësi të cilësimeve, nëse nuk është një paketë me vërtetim, por nga IP-ja e fundit e kujtuar dhe porta e klientit, mund të kalohet ose mbi ose hedhur poshtë. Nëse një paketë e vërtetuar vjen nga një IP dhe port i ri, tuneli rikonfigurohet për t'i përdorur ato.

IPIP-mbi-FOU i zakonshëm ka një problem më shumë kur punoni me NAT - është e pamundur të krijohen dy tunele IPIP të kapsuluara në UDP me të njëjtën IP, sepse modulet FOU dhe IPIP janë mjaft të izoluara nga njëri-tjetri. ato. një palë klientësh pas të njëjtës IP publike nuk do të mund të lidhen njëkohësisht me të njëjtin server në këtë mënyrë. Në të ardhmen, ndoshta, do të zgjidhet në nivelin e kernelit, por kjo nuk është e sigurt. Ndërkohë, problemet e NAT mund të zgjidhen nga NAT - nëse ndodh që një palë IP adresash tashmë janë të zëna nga një tunel tjetër, ipipou do të bëjë NAT nga publike në një IP alternative private, voila! - mund të krijoni tunele derisa portat të mbarojnë.

Sepse Jo të gjitha paketat në lidhje janë të nënshkruara, atëherë kjo mbrojtje e thjeshtë është e pambrojtur ndaj MITM, kështu që nëse ka një zuzar që fshihet në rrugën midis klientit dhe serverit i cili mund të dëgjojë trafikun dhe ta manipulojë atë, ai mund t'i ridrejtojë paketat e vërtetuara përmes një adresë tjetër dhe krijoni një tunel nga një host i pabesueshëm.

Nëse dikush ka ide se si ta rregullojë këtë duke lënë pjesën më të madhe të trafikut në thelb, mos hezitoni të flisni.

Nga rruga, kapsulimi në UDP është dëshmuar shumë mirë. Krahasuar me kapsulimin mbi IP, ai është shumë më i qëndrueshëm dhe shpesh më i shpejtë pavarësisht nga shpenzimet shtesë të kokës UDP. Kjo për faktin se shumica e hosteve në internet funksionojnë mirë vetëm me tre protokollet më të njohura: TCP, UDP, ICMP. Pjesa e prekshme mund të heqë plotësisht gjithçka tjetër, ose ta përpunojë më ngadalë, sepse është e optimizuar vetëm për këto tre.

Për shembull, kjo është arsyeja pse QUICK, në të cilin bazohet HTTP/3, u krijua në krye të UDP, dhe jo në krye të IP.

Epo, mjaft fjalë, është koha për të parë se si funksionon në "botën reale".

Beteja

Përdoret për të imituar botën reale iperf3. Për sa i përket shkallës së afërsisë me realitetin, kjo është afërsisht e njëjtë me imitimin e botës reale në Minecraft, por tani për tani do të ndodhë.

Pjesëmarrësit në konkurs:

  • referencë kanali kryesor
  • heroi i këtij artikulli është ipipou
  • OpenVPN me vërtetim, por pa kriptim
  • OpenVPN në modalitetin gjithëpërfshirës
  • WireGuard pa PresharedKey, me MTU=1440 (që vetëm me IPv4)

Të dhëna teknike për geeks
Metrikat merren me komandat e mëposhtme:

mbi klientin:

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"

latente ICMP

ping -c 10 SERVER_IP | tail -1

në server (punon njëkohësisht me klientin):

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"

Konfigurimi i tunelit

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

klient
/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 (pa kriptim, me vërtetim)
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

klient

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 (me kriptim, vërtetim, përmes UDP, gjithçka siç pritej)
Konfiguruar duke përdorur openvpn-menaxho

telgjeli
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

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

Gjetjet

Shenjë e shëmtuar e lagur
Ngarkesa e CPU-së së serverit nuk është shumë treguese, sepse... Ka shumë shërbime të tjera që funksionojnë atje, ndonjëherë ato hanë burime:

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

Kanali 20 Mbps

ipipou: më shumë se thjesht një tunel i pakriptuar

ipipou: më shumë se thjesht një tunel i pakriptuar

kanal për 1 Gbps optimist

ipipou: më shumë se thjesht një tunel i pakriptuar

ipipou: më shumë se thjesht një tunel i pakriptuar

Në të gjitha rastet, ipipou është mjaft afër në performancë me kanalin bazë, gjë që është e mrekullueshme!

Tuneli i pakriptuar openvpn u soll mjaft çuditshëm në të dyja rastet.

Nëse dikush do ta testojë atë, do të jetë interesante të dëgjosh reagime.

Qofshin me ne IPv6 dhe NetPrickle!

Burimi: www.habr.com

Shto një koment