Ce îi spunem lui Dumnezeu IPv6?

Corect, și lui Dumnezeu criptării îi vom spune același lucru astăzi.
Aici va fi vorba despre un tunel IPv4 necriptat, dar nu despre un "lampă caldă" ci despre unul modern "LED". Și aici apar socketuri brute, iar lucrul cu pachetele se desfășoară în spațiul utilizatorului.
Există N protocoale de tunelare pentru toate gusturile:
- stilos, la modă, pentru tineri
- multifuncționale, precum cuțitele elvețiene, OpenVPN și SSH
- vechi și mai puțin rău GRE
- maxim simplu, rapid, deloc criptat IPIP
- în continuă dezvoltare
- multe altele.
Dar eu sunt programator, așa că voi crește N doar cu o mică cotă, iar dezvoltarea protocoalelor adevărate o voi lăsa dezvoltatorilor profesioniști.
Într-un proiect care încă nu s-a născut Examinând diverse protocoale de tunelare, atenția perfecționistului meu interior a fost tot mai mult atrasă de IPIP datorită cheltuielilor sale minime. Dar are o jumătate de dezavantaj esențial pentru sarcinile mele:
necesită IP-uri publice de ambele părți,
- și nu ai nicio autentificare.
- Așa că perfecționistul a început să se retragă din nou în colțul întunecat al cutiei craniene, sau unde se află el.
Și așa, citind articole despre
tuneluri nativ suportate "Iată-o, glonțul de argint! Mie îmi ajunge un IPIP simplu." — m-am gândit.
În realitate, glonțul s-a dovedit a fi nu complet din argint. Împachetarea în UDP rezolvă prima problemă — se poate conecta din exterior la clienții aflați în spatele NAT-ului folosind o conexiune stabilită anterior, dar aici partea a doua a dezavantajului IPIP înflorește sub o nouă lumină — în spatele IP-urilor publice vizibile și portului clientului se poate ascunde oricine dintr-o rețea privată (în IPIP-ul pur nu există această problemă).
Pentru a rezolva această problemă parțială, a fost creat utilitarul
ipipou Aceasta include un mecanism homemade de autentificare a gazdelor la distanță, fără a afecta funcționarea FOU-ului nuclear, care va procesa rapid și eficient pachetele în spațiul nucleului.
Nu ai nevoie de scriptul tău!
Bine, dacă știi portul public și IP-ul clientului (de exemplu, aceștia nu se duc nicăieri, NAT-ul încearcă să mapeze porturile 1-1), poți crea un tunel IPIP-over-FOU cu următoarele comenzi, fără scripturi.
pe 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
pe 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
# Opțiunile local, peer, peer_port, dev pot să nu fie acceptate de nucleele mai vechi, le poți omite.
# peer și peer_port sunt utilizate pentru a crea o conexiune imediat la crearea FOU-listener-ului.
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
unde
ipipou*— numele interfeței de rețea tunnel locale203.0.113.1— IP-ul public al serverului198.51.100.2— IP-ul public al clientului192.168.0.2— IP-ul clientului, atribuit interfeței eth010001— portul local al clientului pentru FOU20001— portul public al clientului pentru FOU10000— portul public al serverului pentru FOUencap-csum— opțiune pentru adăugarea unei sume de control UDP în pachetele UDP înveșmântate; poate fi înlocuită cunoencap-csum, pentru a nu calcula, integritatea fiind controlată de stratul extern al înveșmântării (atâta vreme cât pachetul se află în tunel)eth0— interfața locală la care va fi legat tunelul ipip172.28.0.1— IP-ul interfeței tunnel a clientului (privat)172.28.0.0— IP-ul interfeței tunnel a serverului (privat)
Atâta vreme cât conexiunea UDP este activă, tunelul va funcționa, iar când se rupe, va depinde — dacă IP-ul: portul clientului rămân aceleași — va funcționa, dacă se schimbă — se va rupe.
Cel mai simplu mod de a răsturna totul este încărcând modulele nucleului: modprobe -r fou ipip
Chiar dacă autentificarea nu este necesară, IP-urile publice și portul clientului nu sunt întotdeauna cunoscute și adesea imprevizibile sau variabile (în funcție de tipul de NAT). Dacă omitem encap-dport de partea serverului, tunelul nu va funcționa, nu este atât de inteligent să ia portul de conectare la distanță. În acest caz, ipipou poate ajuta de asemenea, sau WireGuard și alte soluții similare pot fi de ajutor.
Cum funcționează?
Clientul (ceea ce este de obicei în spatele NAT-ului) ridică un tunel (ca în exemplul de mai sus) și trimite un pachet cu autentificare către server, pentru ca acesta să configureze tunelul de partea sa. În funcție de setări, acest lucru poate fi un pachet gol (doar pentru ca serverul să vadă IP-urile publice: portul de conexiune), sau cu date prin care serverul poate să identifice clientul. Datele pot fi o simplă frază parolă în text simplu (se poate face o analogie cu HTTP Basic Auth) sau date semnate cu o cheie privată, special pregătite (asemănătoare cu HTTP Digest Auth, dar mai puternice, vezi funcția client_auth în cod).
Pe server ( partea cu IP-ul public), la pornirea ipipou, se creează un handler pentru coada nfqueue și se configurează netfilter astfel încât pachetele necesare să fie direcționate corespunzător: pachetele care inițiază conexiunea în coada nfqueue, iar [aproape] toate celelalte direct în listener-ul FOU.
Cine nu este familiarizat, nfqueue (sau NetfilterQueue) este un mecanism special pentru începători, care nu știu să dezvolte module de kernel, care, folosind netfilter (nftables/iptables), permite redirecționarea pachetelor de rețea în spațiul utilizatorului și procesarea acestora acolo cu instrumente primitive: modificarea (opțional) și returnarea la kernel, sau abandonarea acestora.
Pentru anumite limbaje de programare există binding-uri pentru lucrul cu nfqueue, însă pentru bash nu s-au găsit (huh, nu e surprinzător), a fost necesar să folosim python: ipipou folosește .
Dacă performanța nu este critică, cu ajutorul acestui mecanism poți crea rapid și ușor propria logică de lucru cu pachetele la un nivel destul de inferior, de exemplu să dezvolți protocoale experimentale de transfer de date sau să troll-ezi servicii locale și externe cu comportamente neobișnuite.
La unison cu nfqueue lucrează socket-urile brute (raw sockets), de exemplu, când tunelul este deja configurat, și FOU ascultă pe portul dorit, nu poți trimite un pachet din acest port folosind metoda obișnuită — este ocupat, dar poți lua și să trimiți un pachet generat aleatoriu direct în interfața de rețea folosind un socket brut, chiar dacă va trebui să te ocupi puțin mai mult de generarea unui astfel de pachet. Astfel de pachete cu autentificare sunt create în ipipou.
Deoarece ipipou procesează doar primele pachete din conexiune (și cele care au reușit să se strecoare în coadă înainte de a stabili conexiunea), performanța nu este aproape deloc afectată.
Când serverul ipipou primește un pachet care a trecut autentificarea, tunelul este creat, iar toate pachetele următoare din conexiune sunt procesate de nucleu, ocolind nfqueue. Dacă conexiunea expiră, primul pachet următor va fi direcționat în coada nfqueue, în funcție de setări; dacă nu este un pachet de autentificare, dar provine de la ultimul IP și port cunoscut al clientului, acesta poate fi fie trecut mai departe, fie abandonat. Dacă un pachet autentificat vine de la un IP și port noi, tunelul va fi reconfigurat pentru a-i utiliza.
IPIP-over-FOU obișnuit are o altă problemă atunci când lucrează cu NAT — nu se pot crea două tuneluri IPIP încapsulate în UDP cu aceleași IP-uri, deoarece modulele FOU și IPIP sunt suficient de izolate una de alta. Asta înseamnă că o pereche de clienți ce folosesc același IP public nu se pot conecta simultan la același server în acest mod. În viitor, , aceasta va fi rezolvată la nivelul nucleului, dar nu este sigur. Până atunci, problemele NAT-ului pot fi rezolvate prin NAT — dacă se întâmplă ca o pereche de adrese IP să fie deja ocupate de un alt tunel, ipipou va face NAT de pe IP-ul public pe un IP privat alternativ, voila! — pot fi create tuneluri până când porțile se vor termina.
Deoarece nu toate pachetele din conexiune sunt semnate, această protecție simplă este vulnerabilă la MITM, așa că, dacă între client și server se află un adversar care poate asculta traficul și să-l controleze, acesta poate redirecționa pachetele de autentificare printr-o altă adresă și poate crea un tunel de la un gazdă neîncredere.
Dacă cineva are idei despre cum să rezolve aceasta lăsând cea mai mare parte a traficului în nucleu, nu ezitați — exprimați-vă.
Ca dovadă, încapsularea în UDP s-a dovedit a fi foarte eficientă. Comparativ cu încapsularea peste IP, este mult mai stabilă și adesea mai rapidă, în ciuda costurilor suplimentare ale antetului UDP. Acest lucru se datorează faptului că, pe internet, majoritatea gazdelor funcționează decent doar cu cele trei protocoale cele mai populare: TCP, UDP, ICMP. O parte semnificativă poate respinge complet tot restul sau să-l proceseze mai încet, deoarece este optimizată doar pentru aceste trei.
De exemplu, de aceea QUICK, pe baza căruia a fost creat HTTP/3, a fost dezvoltat exact peste UDP, și nu peste IP.
Ei bine, destul cu vorbele, este timpul să vedem cum funcționează în «lumea reală».
Bătălie
Pentru a emula lumea reală se folosește iperf3. Din punct de vedere al apropierii de realitate, este cam ca emularea lumii reale în Minecraft, dar deocamdată este suficient.
În competiție participă:
- canalul de referință principal
- eroarea acestui articol ipipou
- OpenVPN cu autentificare, dar fără criptare
- OpenVPN în modul «totul inclus»
- WireGuard fără PresharedKey, cu MTU=1440 (deoarece doar IPv4)
Date tehnice pentru geeki
Metricile sunt obținute cu comenzile următoare
pe client:
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"
# Unde "-b 12M" este lățimea de bandă a canalului principal, împărțită la numărul de fire "-P", pentru a nu genera pachete suplimentare și a nu afecta performanța.
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"
latenta ICMP
ping -c 10 SERVER_IP | tail -1
pe server (pornește simultan cu clientul):
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"
Configurarea tunelurilor
ipipou
serverul
/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 (fără criptare, cu autentificare)
serverul
openvpn --genkey --secret ovpn.key # Apoi trebuie să transferi ovpn.key clientului
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 (cu criptare, autentificare, prin UDP, cum ar trebui să fie)
Configurat folosind
wireguard
serverul
/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
Rezultate
Un tabel neîngrijit și urât
Încărcarea CPU-ului serverului nu este foarte relevantă, deoarece rulează multe alte servicii care uneori consumă resurse:
lățimea de bandă[Mbps] CPU_idle_client[%] CPU_idle_server[%]
# 20 Mbps canal de microcomputers (4 core) până la VPS (1 core) prin Atlantica
# pur
UDP 20.4 99.80 93.34
TCP 19.2 99.67 96.68
ICMP latență min/med/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 latență min/med/max/mdev = 199.562/208.919/220.222/7.905 ms
# openvpn0 (doar autentificare, fără criptare)
UDP 19.3 99.89 72.90
TCP 16.1 95.95 88.46
ICMP latență min/med/max/mdev = 191.631/193.538/198.724/2.520 ms
# openvpn (criptare completă, autentificare, etc)
UDP 19.6 99.75 72.35
TCP 17.0 94.47 87.99
ICMP latență min/med/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 latență min/med/max/mdev = 217.925/223.601/230.696/3.266 ms
## canal aproape de 1Gbps între VPS Europa și SUA (1 core)
# pur
UDP 729 73.40 39.93
TCP 363 96.95 90.40
ICMP latență min/med/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 latență min/med/max/mdev = 107.444/107.523/107.648/0.058 ms
# openvpn0 (doar autentificare, fără criptare)
UDP 193 17.51 1.62
TCP 12 95.45 92.80
ICMP latență min/med/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 latență min/med/max/mdev = 107.616/107.788/108.038/0.128 ms
canal de 20 Mbps


canal de 1 Gbps optimist


În toate cazurile, ipipou este destul de aproape de performanțele canalului de bază, ceea ce este minunat!
Tunelul openvpn necriptat a avut un comportament destul de ciudat în ambele cazuri.
Dacă cineva intenționează să testeze, ar fi interesant să auzim păreri.
Să fie cu noi IPv6 și NetPrickle!
Sursa: habr.com
