ipipou: više od običnog nešifriranog tunela

Što poručujemo Bogu IPv6?

ipipou: više od običnog nešifriranog tunela
Tako je, danas ćemo isto reći bogu šifriranja.

Ovdje ćemo govoriti o nešifriranom IPv4 tunelu, ali ne o “toploj lampi”, već o modernom “LED” tunelu. Ovdje također bljeskaju sirovi soketi, au tijeku je rad s paketima u korisničkom prostoru.

Postoji N protokola tuneliranja za svaki ukus i boju:

  • moderan, moderan, mladenački WireGuard
  • višenamjenski, poput švicarskih noževa, OpenVPN i SSH
  • stari i ne zli GRE
  • najjednostavniji, brzi, potpuno nešifrirani IPIP
  • aktivno se razvija Geneve
  • mnogi drugi.

Ali ja sam programer, pa ću povećati N samo za djelić, a razvoj pravih protokola prepustiti programerima Kommersanta.

U jednom još nerođenom projektOno što sada radim jest doći do hostova iza NAT-a izvana. Koristeći za ovo protokole s kriptografijom za odrasle, nisam se mogao otresti osjećaja da je to kao pucanje vrabaca iz topa. Jer tunel se uglavnom koristi samo za bušenje rupa u NAT-e, interni promet je obično također šifriran, ali se i dalje utapaju u HTTPS.

Dok sam istraživao razne protokole za tuneliranje, pozornost mog unutarnjeg perfekcioniste uvijek je iznova privlačio IPIP zbog minimalnih troškova. Ali ima jedan i pol značajan nedostatak za moje zadatke:

  • zahtijeva javne IP adrese s obje strane,
  • i nema provjere autentičnosti za vas.

Stoga je perfekcionist stjeran natrag u mračni kut lubanje, ili gdje god on tamo sjedi.

A onda jednog dana, čitajući članke o nativno podržani tuneli u Linuxu sam naišao na FOU (Foo-over-UDP), tj. što god, umotano u UDP. Do sada su podržani samo IPIP i GUE (Generic UDP Encapsulation).

“Evo srebrnog metka! Dovoljan mi je jednostavan IPIP.” - Mislio sam.

Zapravo, pokazalo se da metak nije potpuno srebrn. Enkapsulacija u UDP rješava prvi problem - možete se spojiti na klijente iza NAT-a izvana koristeći unaprijed uspostavljenu vezu, ali ovdje polovica sljedećeg nedostatka IPIP-a procvjeta u novom svjetlu - bilo tko iz privatne mreže može se sakriti iza vidljive mreže. javni IP i port klijenta (u čistom IPIP-u ovaj problem ne postoji).

Za rješavanje ovog jednog i pol problema rođen je uslužni program ipipou. Implementira domaći mehanizam za autentifikaciju udaljenog računala, bez ometanja rada FOU kernela, koji će brzo i učinkovito obraditi pakete u kernel prostoru.

Ne treba nam tvoj scenarij!

U redu, ako znate javni port i IP klijenta (na primjer, svi iza njega ne idu nikamo, NAT pokušava mapirati portove 1-u-1), možete stvoriti IPIP-over-FOU tunel s slijedeći naredbe, bez ikakvih skripti.

na poslužitelju:

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

na klijentu:

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

gdje

  • ipipou* — naziv sučelja lokalne mreže tunela
  • 203.0.113.1 — javni IP poslužitelj
  • 198.51.100.2 — javni IP klijenta
  • 192.168.0.2 — IP klijenta dodijeljen sučelju eth0
  • 10001 — port lokalnog klijenta za FOU
  • 20001 — javni klijentski port za FOU
  • 10000 — port javnog poslužitelja za FOU
  • encap-csum — mogućnost dodavanja UDP kontrolne sume enkapsuliranim UDP paketima; može se zamijeniti sa noencap-csum, da ne spominjemo, integritet već kontrolira vanjski sloj enkapsulacije (dok je paket unutar tunela)
  • eth0 — lokalno sučelje na koje će ipip tunel biti vezan
  • 172.28.0.1 — IP sučelja klijentskog tunela (privatno)
  • 172.28.0.0 — IP tunel sučelje poslužitelja (privatno)

Sve dok je UDP veza živa, tunel će biti u ispravnom stanju, ali ako se pokvari, bit ćete sretni - ako klijentov IP: port ostane isti - živjet će, ako se promijene - pokvarit će se.

Najlakši način da sve vratite unazad je istovar modula kernela: modprobe -r fou ipip

Čak i ako provjera autentičnosti nije potrebna, klijentov javni IP i port nisu uvijek poznati i često su nepredvidivi ili promjenjivi (ovisno o vrsti NAT-a). Ako izostavite encap-dport na strani poslužitelja, tunel neće raditi, nije dovoljno pametan da preuzme priključak za udaljenu vezu. U ovom slučaju može pomoći i ipipou ili WireGuard i njemu slični.

Kako se to radi?

Klijent (koji je obično iza NAT-a) otvara tunel (kao u gornjem primjeru) i šalje paket provjere autentičnosti poslužitelju tako da on konfigurira tunel na svojoj strani. Ovisno o postavkama, to može biti prazan paket (samo da poslužitelj može vidjeti javni IP: port veze), ili s podacima po kojima poslužitelj može identificirati klijenta. Podaci mogu biti jednostavna šifra u jasnom tekstu (na pamet pada analogija s HTTP Basic Auth) ili posebno dizajnirani podaci potpisani privatnim ključem (slično HTTP Digest Authu samo jače, pogledajte funkciju client_auth u kodu).

Na poslužitelju (strana s javnom IP-om), kada se ipipou pokrene, stvara nfqueue rukovatelj redom čekanja i konfigurira netfilter tako da se potrebni paketi šalju tamo gdje bi trebali biti: paketi koji inicijaliziraju vezu s nfqueue redom čekanja i [skoro] sve ostalo ide ravno slušatelju FOU.

Za one koji nisu upućeni, nfqueue (ili NetfilterQueue) je posebna stvar za amatere koji ne znaju razvijati module kernela, koji pomoću netfiltera (nftables/iptables) omogućuje preusmjeravanje mrežnih paketa u korisnički prostor i njihovu obradu tamo pomoću primitivna sredstva pri ruci: modificirajte (opcionalno ) i vratite je jezgri ili je odbacite.

Za neke programske jezike postoje vezanja za rad s nfqueue, za bash ih nije bilo (heh, nije iznenađujuće), morao sam koristiti python: ipipou koristi NetfilterQueue.

Ako izvedba nije kritična, pomoću ove stvari možete relativno brzo i lako osmisliti vlastitu logiku za rad s paketima na prilično niskoj razini, na primjer, stvoriti eksperimentalne protokole za prijenos podataka ili kontrolirati lokalne i udaljene usluge s nestandardnim ponašanjem.

Neobrađeni soketi rade ruku pod ruku s nfqueueom, na primjer, kada je tunel već konfiguriran i FOU sluša željeni port, nećete moći poslati paket s istog porta na uobičajeni način - zauzet je, ali možete uzeti i poslati nasumično generirani paket izravno na mrežno sučelje koristeći sirovu utičnicu, iako će generiranje takvog paketa zahtijevati malo više petljanja. Ovako se kreiraju paketi s autentifikacijom u ipipou.

Budući da ipipou obrađuje samo prve pakete iz veze (i one koji su uspjeli procuriti u red prije nego što je veza uspostavljena), izvedba gotovo da ne trpi.

Čim ipipou poslužitelj primi autentificirani paket, stvara se tunel i sve sljedeće pakete u vezi već obrađuje kernel zaobilazeći nfqueue. Ako veza ne uspije, tada će prvi paket sljedećeg biti poslan u red čekanja nfqueue, ovisno o postavkama, ako to nije paket s autentifikacijom, već sa zadnje zapamćene IP adrese i porta klijenta, može se proslijediti ili na ili odbačeno. Ako autentificirani paket dolazi s novog IP-a i priključka, tunel se rekonfigurira da ih koristi.

Uobičajeni IPIP-over-FOU ima još jedan problem kada radi s NAT-om - nemoguće je stvoriti dva IPIP tunela enkapsulirana u UDP s istim IP-om, jer su FOU i IPIP moduli prilično izolirani jedan od drugog. Oni. par klijenata iza iste javne IP adrese neće se moći istovremeno spojiti na isti poslužitelj na ovaj način. U budućnosti, možda, to će se riješiti na razini kernela, ali to nije sigurno. U međuvremenu, probleme s NAT-om može riješiti NAT - ako se dogodi da je par IP adresa već zauzet drugim tunelom, ipipou će napraviti NAT s javnog na alternativni privatni IP, voila! - možete stvarati tunele dok ne ponestane portova.

Jer Nisu svi paketi u vezi potpisani, tada je ova jednostavna zaštita ranjiva na MITM, pa ako postoji zlikovac koji vreba na putu između klijenta i poslužitelja koji može slušati promet i njime manipulirati, on može preusmjeriti autentificirane pakete putem drugu adresu i stvorite tunel s nepouzdanog računala.

Ako netko ima ideje kako to popraviti, a da pritom većinu prometa ostavi u jezgri, ne ustručavajte se reći.

Usput, enkapsulacija u UDP-u se vrlo dobro pokazala. U usporedbi s enkapsulacijom preko IP-a, mnogo je stabilnija i često brža unatoč dodatnim troškovima UDP zaglavlja. To je zbog činjenice da većina hostova na Internetu dobro radi samo s tri najpopularnija protokola: TCP, UDP, ICMP. Opipljivi dio može u potpunosti odbaciti sve ostalo, ili ga obrađivati ​​sporije, jer je optimiziran samo za ovo troje.

Na primjer, zbog toga je QUICK, na kojem se temelji HTTP/3, kreiran na vrhu UDP-a, a ne na vrhu IP-a.

Pa, dosta riječi, vrijeme je da vidimo kako to funkcionira u "stvarnom svijetu".

Bitka

Koristi se za oponašanje stvarnog svijeta iperf3. Što se tiče stupnja bliskosti stvarnosti, to je otprilike isto kao oponašanje stvarnog svijeta u Minecraftu, ali za sada će to učiniti.

Sudionici natječaja:

  • referentni glavni kanal
  • junak ovog članka je ipipou
  • OpenVPN s autentifikacijom, ali bez enkripcije
  • OpenVPN u sveobuhvatnom načinu rada
  • WireGuard bez PresharedKey, s MTU=1440 (samo od IPv4)

Tehnički podaci za geekove
Mjerni podaci se uzimaju pomoću sljedećih naredbi:

na klijentu:

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 kašnjenje

ping -c 10 SERVER_IP | tail -1

na poslužitelju (radi istovremeno s klijentom):

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"

Konfiguracija 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

klijent
/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 enkripcije, s autentifikacijom)
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

klijent

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 (s enkripcijom, autentifikacijom, preko UDP-a, sve prema očekivanjima)
Konfigurirano pomoću openvpn-upravljanje

žičani čuvar
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

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

Nalazi

Vlažan ružan znak
Opterećenje procesora poslužitelja nije baš indikativno, jer... Postoje mnoge druge usluge koje rade tamo, ponekad pojedu resurse:

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 kanal

ipipou: više od običnog nešifriranog tunela

ipipou: više od običnog nešifriranog tunela

kanala po 1 optimističnom Gbps

ipipou: više od običnog nešifriranog tunela

ipipou: više od običnog nešifriranog tunela

U svim slučajevima, ipipou je po performansama vrlo blizu osnovnom kanalu, što je sjajno!

Nešifrirani openvpn tunel ponašao se prilično čudno u oba slučaja.

Ako ga netko namjerava testirati, bit će zanimljivo čuti povratne informacije.

Neka IPv6 i NetPrickle budu s nama!

Izvor: www.habr.com

Dodajte komentar