ipipou: više od samo nešifrovanog tunela

Šta govorimo Bogu IPv6?

ipipou: više od samo nešifrovanog tunela
Tako je, to ćemo danas reći bogu šifriranja.

Ovdje ćemo govoriti o nešifrovanom IPv4 tunelu, ali ne o onom „topla lampa“, već o modernom „LED“. A tu su i neobrađeni soketi koji bljeskaju ovdje, a u toku je rad sa paketima u korisničkom prostoru.

Postoji N protokola tuneliranja za svaki ukus i boju:

  • moderan, moderan, omladinski WireGuard
  • multifunkcionalni, poput švicarskih noževa, OpenVPN i SSH
  • star i ne zao GRE
  • najjednostavniji, brzi, potpuno nešifrirani IPIP
  • aktivno se razvija ŽENEVA
  • mnogi drugi.

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

U jednom nerođenom projektOno što sada radim je da dođem do hostova iza NAT-a izvana. Koristeći za to protokole sa kriptografijom za odrasle, nisam se mogao otarasiti osjećaja da je to kao pucanje vrapca iz topa. Jer tunel se uglavnom koristi samo za bušenje rupa u NAT-e, interni saobraćaj je obično takođe šifrovan, ali se i dalje utapa u HTTPS.

Dok sam istraživao razne protokole tuneliranja, pažnja mog unutrašnjeg perfekcioniste je uvijek iznova privlačila IPIP zbog minimalnih troškova. Ali ima jedan i po značajnih nedostataka za moje zadatke:

  • zahtijeva javne IP adrese s obje strane,
  • i nema autentifikacije za vas.

Stoga je perfekcionista otjeran nazad u tamni ugao lobanje, ili gdje god tamo sjedi.

A onda jednog dana, dok čitam članke dalje izvorno podržani tuneli u Linuxu sam naišao na FOU (Foo-over-UDP), tj. bilo šta, umotano u UDP. Do sada su podržani samo IPIP i GUE (generička UDP enkapsulacija).

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

U stvari, pokazalo se da metak nije bio potpuno srebrni. Enkapsulacija u UDP rješava prvi problem - možete se povezati s klijentima iza NAT-a izvana koristeći unaprijed uspostavljenu vezu, ali ovdje polovina sljedećeg nedostatka IPIP-a procvjeta u novom svjetlu - svako iz privatne mreže može se sakriti iza vidljivog javni IP i port klijenta (u čistom IPIP-u ovaj problem ne postoji).

Da bi riješio ovaj jedan i po problem, rođen je uslužni program ipipou. Implementira domaći mehanizam za autentifikaciju udaljenog hosta, bez ometanja rada kernela FOU, koji će brzo i efikasno obraditi pakete u prostoru kernela.

Ne treba nam tvoj scenario!

Ok, ako znate javni port i IP klijenta (na primjer, svi iza njega ne idu nikuda, NAT pokušava mapirati portove 1-u-1), možete kreirati IPIP-over-FOU tunel sa sljedeće komande, bez ikakvih skripti.

na serveru:

# Подгрузить модуль ядра 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 lokalnog tunelskog mrežnog interfejsa
  • 203.0.113.1 — javni IP server
  • 198.51.100.2 — javni IP klijenta
  • 192.168.0.2 — IP klijenta dodijeljen interfejsu eth0
  • 10001 — lokalni klijentski port za FOU
  • 20001 — javni klijentski port za FOU
  • 10000 — port javnog servera za FOU
  • encap-csum — opcija za dodavanje UDP kontrolne sume inkapsuliranim UDP paketima; može se zamijeniti sa noencap-csum, da ne spominjemo, integritet je već kontroliran od strane vanjskog sloja enkapsulacije (dok je paket unutar tunela)
  • eth0 — lokalni interfejs na koji će ipip tunel biti vezan
  • 172.28.0.1 — IP interfejsa klijentskog tunela (privatno)
  • 172.28.0.0 — IP tunel serverski interfejs (privatno)

Dokle god je UDP veza živa, tunel će biti u funkciji, ali ako se pokvari, imat ćete sreće - ako IP: port klijenta ostane isti - živjet će, ako se promijene - pokvariće se.

Najlakši način da sve vratite je da ispraznite module kernela: modprobe -r fou ipip

Čak i ako autentifikacija nije potrebna, klijentov javni IP i port nisu uvijek poznati i često su nepredvidivi ili varijabilni (ovisno o tipu NAT-a). Ako izostavite encap-dport na strani servera, tunel neće raditi, nije dovoljno pametan da preuzme port za udaljenu vezu. U ovom slučaju, ipipou također može pomoći, ili WireGuard i drugi slični mogu vam pomoći.

Как это работает?

Klijent (koji se obično nalazi iza NAT-a) otvara tunel (kao u gornjem primjeru) i šalje autentifikacijski paket serveru tako da on konfigurira tunel na svojoj strani. Ovisno o postavkama, to može biti prazan paket (samo da server vidi javni IP: port veze), ili sa podacima po kojima server može identificirati klijenta. Podaci mogu biti jednostavna pristupna fraza u čistom tekstu (na pamet mi pada analogija s HTTP Basic Auth) ili posebno dizajnirani podaci potpisani privatnim ključem (slično HTTP Digest Auth samo jači, pogledajte funkciju client_auth u kodu).

Na serveru (strana s javnom IP-om), kada se ipipou pokrene, kreira nfqueue queue handler i konfigurira netfilter tako da se potrebni paketi šalju tamo gdje bi trebali biti: paketi koji inicijaliziraju vezu s nfqueue redom i [skoro] sve ostalo ide direktno slušaocu FOU.

Za one koji ne znaju, nfqueue (ili NetfilterQueue) je posebna stvar za amatere koji ne znaju kako razviti module kernela, koji pomoću netfiltera (nftables/iptables) omogućavaju preusmjeravanje mrežnih paketa u korisnički prostor i obradu ih tamo koristeći primitivno sredstvo pri ruci: modificirati (opciono) i vratiti ga kernelu, ili ga odbaciti.

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

Ako performanse nisu kritične, pomoću ove stvari možete relativno brzo i lako smisliti vlastitu logiku za rad s paketima na prilično niskom nivou, na primjer, kreirati eksperimentalne protokole za prijenos podataka ili trolovati lokalne i udaljene usluge nestandardnim ponašanjem.

Raw utičnice rade ruku pod ruku sa nfqueue, na primjer, kada je tunel već konfiguriran i FOU sluša na željenom portu, nećete moći poslati paket sa istog porta na uobičajen način - zauzet je, ali možete uzeti i poslati nasumično generisani paket direktno na mrežni interfejs koristeći sirovu utičnicu, iako će za generisanje takvog paketa biti potrebno malo više popravljanja. Ovako se kreiraju paketi sa autentifikacijom u ipipou.

Budući da ipipou obrađuje samo prve pakete iz veze (i one koji su uspjeli procuriti u red prije uspostavljanja veze), performanse gotovo da ne trpe.

Čim ipipou server primi autentificirani paket, kreira se tunel i svi naredni paketi u vezi su već obrađeni od strane kernela zaobilazeći nfqueue. Ako veza ne uspije, tada će prvi paket sljedećeg biti poslan u nfqueue queue, ovisno o postavkama, ako nije paket s autentifikacijom, ali sa zadnjeg zapamćenog IP-a i klijentskog porta, može se ili proslijediti uključeno ili odbačeno. Ako autentificirani paket dolazi s novog IP-a i porta, tunel se rekonfigurira da ih koristi.

Uobičajeni IPIP-over-FOU ima još jedan problem pri radu sa NAT-om - nemoguće je kreirati dva IPIP tunela inkapsulirana u UDP sa istim IP-om, jer su FOU i IPIP moduli prilično izolovani jedan od drugog. One. par klijenata iza iste javne IP adrese neće moći istovremeno da se poveže na isti server na ovaj način. U budućnosti, moguće, to će biti riješeno na nivou kernela, ali to nije sigurno. U međuvremenu, NAT probleme može riješiti NAT - ako se dogodi da je par IP adresa već zauzet drugim tunelom, ipipou će učiniti NAT sa javnog na alternativni privatni IP, voila! - možete kreirati tunele dok ne ponestane portova.

Jer Nisu svi paketi u konekciji potpisani, onda je ova jednostavna zaštita ranjiva na MITM, pa ako na putu između klijenta i servera vreba negativac koji može slušati promet i manipulirati njime, on može preusmjeriti autentificirane pakete kroz drugu adresu i kreirajte tunel od nepouzdanog hosta.

Ako neko ima ideje kako to popraviti, a da najveći dio prometa ostane u jezgri, ne oklijevajte da progovorite.

Inače, inkapsulacija u UDP se jako dobro pokazala. U poređenju sa enkapsulacijom preko IP-a, ona je mnogo stabilnija i često brža uprkos dodatnim opterećenjima UDP zaglavlja. To je zbog činjenice da većina hostova na Internetu dobro radi samo sa tri najpopularnija protokola: TCP, UDP, ICMP. Opipljivi dio može potpuno odbaciti sve ostalo, ili to sporije obrađivati, jer je optimiziran samo za ovo troje.

Na primjer, ovo je razlog zašto 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 stepena bliskosti sa stvarnošću, ovo je otprilike isto kao oponašanje stvarnog svijeta u Minecraftu, ali za sada će to biti dovoljno.

Učesnici takmičenja:

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

Tehnički podaci za štreberke
Metrike 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 latencija

ping -c 10 SERVER_IP | tail -1

na serveru (radi istovremeno sa 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

mušterija
/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, sa 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

mušterija

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 (sa enkripcijom, autentifikacijom, putem UDP-a, sve kako se očekuje)
Konfigurirano korištenjem openvpn-manage

Wireguard
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

mušterija
/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

Rezulʹtaty

Vlažan ružan znak
Opterećenje procesora servera 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 samo nešifrovanog tunela

ipipou: više od samo nešifrovanog tunela

kanala po 1 optimističkom Gbps

ipipou: više od samo nešifrovanog tunela

ipipou: više od samo nešifrovanog tunela

U svim slučajevima, ipipou je po performansama prilično blizu osnovnom kanalu, što je odlično!

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

Ako će neko to testirati, bit će zanimljivo čuti povratne informacije.

Neka IPv6 i NetPrickle budu s nama!

izvor: www.habr.com

Dodajte komentar