ipipou: mear as allinnich in net fersifere tunnel

Wat sizze wy tsjin de God fan IPv6?

ipipou: mear as allinnich in net fersifere tunnel
Dat is krekt, wy sille hjoed itselde sizze tsjin de god fan fersifering.

Hjir sille wy prate oer in net-fersifere IPv4-tunnel, mar net oer in "waarme lamp", mar oer in moderne "LED". En d'r flitsen hjir ek rauwe sockets, en der wurdt wurke mei pakketten yn brûkersromte.

D'r binne N tunnelingprotokollen foar elke smaak en kleur:

  • stylish, fashionable, jeugd WireGuard
  • multyfunksjoneel, lykas Switserske messen, OpenVPN en SSH
  • âld en net kwea GRE
  • de meast ienfâldige, fluch, hielendal net fersifere IPIP
  • aktyf ûntwikkeljen GENEVE
  • in protte oaren.

Mar ik bin in programmeur, dus ik sil N mar in fraksje ferheegje, en de ûntwikkeling fan echte protokollen litte oan Kommersant-ûntwikkelders.

Yn ien ûnberne projektWat ik no doch is om hosts efter NAT fan bûten te berikken. Troch dêrfoar protokollen mei kryptografy foar folwoeksenen te brûken, koe ik it gefoel net skodzje dat it wie as it sjitten fan sparrows út in kanon. Omdat de tunnel wurdt brûkt foar it grutste part allinnich te poke gatten yn NAT-e, ynterne ferkear wurdt meastal ek fersifere, mar se noch ferdrinke yn HTTPS.

By it ûndersykjen fan ferskate tunnelingprotokollen, waard de oandacht fan myn ynderlike perfeksjonist hieltyd wer op IPIP lutsen fanwegen syn minimale overhead. Mar it hat ien en in heal wichtige tekoarten foar myn taken:

  • it fereasket iepenbiere IP's oan beide kanten,
  • en gjin autentikaasje foar jo.

Dêrom waard de perfeksjonist weromdreaun yn 'e tsjustere hoeke fan 'e skedel, of wêr't er dêr ek sit.

En dan op in dei, by it lêzen fan artikels oer native stipe tunnels yn Linux kaam ik FOU (Foo-over-UDP) tsjin, d.w.s. wat dan ek, ferpakt yn UDP. Oant no wurde allinich IPIP en GUE (Generic UDP Encapsulation) stipe.

"Hjir is de sulveren kûgel! In ienfâldige IPIP is genôch foar my. - Ik tocht.

De kûgel blykte trouwens net hielendal sulver te wêzen. Ynkapseling yn UDP lost it earste probleem op - jo kinne fan bûten ôf ferbine mei kliïnten efter NAT mei in foarôf fêststelde ferbining, mar hjir bloeit de helte fan 'e folgjende neidiel fan IPIP yn in nij ljocht - efter de sichtbere iepenbiere IP en kliïnthaven fan elkenien út in privee netwurk kin ferbergje (yn suver IPIP bestiet dit probleem net).

Om dit ien en in heal probleem op te lossen, waard it nut berne ipipou. It ymplementearret in selsmakke meganisme foar it autentisearjen fan in host op ôfstân, sûnder de wurking fan 'e kernel FOU te fersteuren, dy't pakketten fluch en effisjint yn kernelromte ferwurkje.

Wy hawwe jo skript net nedich!

Ok, as jo de iepenbiere poarte en IP fan 'e kliïnt kenne (bygelyks elkenien derachter giet net oeral, NAT besiket havens 1-in-1 yn kaart te bringen), kinne jo in IPIP-over-FOU-tunnel meitsje mei de folgjende kommando's, sûnder skripts.

op tsjinner:

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

op de klant:

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

wêr

  • ipipou* - namme fan 'e lokale tunnelnetwurkynterface
  • 203.0.113.1 - iepenbiere IP-tsjinner
  • 198.51.100.2 - iepenbiere IP fan 'e kliïnt
  • 192.168.0.2 - client IP tawiisd oan ynterface eth0
  • 10001 - lokale client haven foar FOU
  • 20001 - iepenbiere client haven foar FOU
  • 10000 - iepenbiere tsjinner haven foar FOU
  • encap-csum - opsje om in UDP-kontrôlesum ta te foegjen oan ynkapsele UDP-pakketten; kin wurde ferfongen troch noencap-csum, net te ferjitten, yntegriteit wurdt al regele troch de bûtenste ynkapselingslaach (wylst it pakket yn 'e tunnel is)
  • eth0 - lokale ynterface wêrmei de ipip-tunnel sil wurde bûn
  • 172.28.0.1 - IP fan 'e client tunnel ynterface (privee)
  • 172.28.0.0 - IP-tunnelserverynterface (privee)

Salang't de UDP-ferbining libbet, sil de tunnel yn wurkjende steat wêze, mar as it brekt, sille jo gelok wêze - as de IP-poarte fan 'e kliïnt itselde bliuwt - it sil libje, as se feroarje - it sil brekke.

De maklikste manier om alles werom te kearen is om de kernelmodules út te laden: modprobe -r fou ipip

Sels as autentikaasje net fereaske is, binne de iepenbiere IP en poarte fan 'e kliïnt net altyd bekend en binne faaks ûnfoarspelber of fariabele (ôfhinklik fan it NAT-type). As jo ​​weilitte encap-dport oan de tsjinner kant, de tunnel sil net wurkje, it is net tûk genôch te nimmen de ôfstân ferbining haven. Yn dit gefal kin ipipou ek helpe, of WireGuard en oaren lykas it kinne jo helpe.

Hoe wurket it?

De kliïnt (dy't meastentiids efter NAT is) iepenet in tunnel (lykas yn it foarbyld hjirboppe), en stjoert in autentikaasjepakket nei de tsjinner, sadat it de tunnel oan 'e kant konfigurearret. Ofhinklik fan 'e ynstellings kin dit in leech pakket wêze (krekt sadat de tsjinner de iepenbiere IP: ferbiningspoarte sjen kin), of mei gegevens wêrmei't de tsjinner de kliïnt identifisearje kin. De gegevens kinne in ienfâldige passphrase wêze yn dúdlike tekst (de analogy mei HTTP Basic Auth komt yn 't sin) of spesjaal ûntworpen gegevens ûndertekene mei in privee kaai (lykas HTTP Digest Auth allinich sterker, sjoch funksje client_auth yn de koade).

Op 'e tsjinner (de kant mei it iepenbiere IP), as ipipou begjint, makket it in nfqueue-wachtrige handler en konfigurearret netfilter sadat de nedige pakketten stjoerd wurde wêr't se moatte wêze: pakketten dy't de ferbining mei de nfqueue-wachtrige initialisearje, en [hast] al de rest giet direkt nei de harker FOU.

Foar dyjingen dy't it net witte, is nfqueue (as NetfilterQueue) in spesjaal ding foar amateurs dy't net witte hoe't se kernelmodules ûntwikkelje moatte, wêrmei jo netfilter (nftables / iptables) kinne omliede netwurkpakketten nei brûkersromte en ferwurkje se dêr mei primitive middels by de hân: wizigje (opsjoneel) en jou it werom nei de kearn, of ferwiderje it.

Foar guon programmeartalen binne d'r bindingen foar wurkjen mei nfqueue, foar bash wie d'r gjin (heh, net ferrassend), ik moast python brûke: ipipou brûkt NetfilterQueue.

As prestaasje net kritysk is, mei dit ding kinne jo relatyf fluch en maklik jo eigen logika meitsje foar it wurkjen mei pakketten op in frij leech nivo, bygelyks eksperimintele gegevensferfierprotokollen oanmeitsje, of lokale en op ôfstân tsjinsten mei net-standert gedrach trollje.

Raw sockets wurkje hân yn hân mei nfqueue, bygelyks, as de tunnel al konfigurearre is en FOU harket op 'e winske poarte, kinne jo net op 'e gewoane manier in pakket fan deselde haven stjoere - it is drok, mar jo kinne nimme en stjoer in willekeurich oanmakke pakket direkt nei it netwurk ynterface mei help fan in rau socket, hoewol't it generearjen fan sa'n pakket sil fereaskje in bytsje mear tinken. Dit is hoe't pakketten mei autentikaasje wurde makke yn ipipou.

Om't ipipou allinich de earste pakketten fan 'e ferbining ferwurket (en dejingen dy't yn 'e wachtrige slaggen te lekken foardat de ferbining waard oprjochte), hat prestaasjes hast net lije.

Sadree't de ipipou-tsjinner in authentisearre pakket ûntfangt, wurdt in tunnel makke en alle folgjende pakketten yn 'e ferbining binne al ferwurke troch de kernel dy't nfqueue omgiet. As de ferbining mislearret, dan sil it earste pakket fan 'e folgjende stjoerd wurde nei de nfqueue-wachtrige, ôfhinklik fan' e ynstellings, as it net in pakket is mei autentikaasje, mar fan 'e lêste ûnthâlde IP en client-poarte, kin it trochjûn wurde op of ôfset. As in authentisearre pakket komt fan in nije IP en poarte, wurdt de tunnel opnij konfigureare om se te brûken.

De gewoane IPIP-over-FOU hat noch ien probleem by it wurkjen mei NAT - it is ûnmooglik om twa IPIP-tunnels te meitsjen ynkapsele yn UDP mei deselde IP, om't de FOU- en IPIP-modules frijwat isolearre binne fan elkoar. Dy. in pear kliïnten efter deselde iepenbiere IP sil net tagelyk kinne ferbine mei deselde tsjinner op dizze manier. Yn de takomst, mooglik, it sil oplost wurde op it kernelnivo, mar dit is net wis. Yn 'e tuskentiid kinne NAT-problemen wurde oplost troch NAT - as it bart dat in pear IP-adressen al beset binne troch in oare tunnel, sil ipipou NAT dwaan fan iepenbier nei in alternatyf privee IP, voila! - jo kinne tunnels oanmeitsje oant de havens op binne.

Omdat Net alle pakketten yn 'e ferbining binne ûndertekene, dan is dizze ienfâldige beskerming kwetsber foar MITM, dus as d'r in smjunt op it paad leit tusken de kliïnt en de tsjinner dy't nei it ferkear harkje kin en it manipulearje kin, kin hy autentike pakketten omliede fia in oar adres en meitsje in tunnel fan in net fertroude host.

As immen ideeën hat oer hoe't jo dit kinne reparearje wylst it grutste part fan it ferkear yn 'e kearn bliuwt, aarf dan net om te praten.

Trouwens, ynkapseling yn UDP hat himsels tige goed bewiisd. Yn ferliking mei ynkapseling oer IP is it folle stabiler en faak flugger nettsjinsteande de ekstra overhead fan 'e UDP-header. Dit komt troch it feit dat de measte hosts op it ynternet allinich goed wurkje mei de trije populêrste protokollen: TCP, UDP, ICMP. It taastbere diel kin al it oare folslein ferwiderje, of it stadiger ferwurkje, om't it allinich foar dizze trije is optimalisearre.

Dit is bygelyks wêrom QUICK, wêrop HTTP/3 basearre is, is makke boppe op UDP, en net boppe IP.

No, genôch wurden, it is tiid om te sjen hoe't it wurket yn 'e "echte wrâld".

Fjildslach

Wurdt brûkt om de echte wrâld te emulearjen iperf3. Wat de mjitte fan tichtby de realiteit oanbelanget, is dit sawat itselde as it emulearjen fan 'e echte wrâld yn Minecraft, mar foar no sil it dwaan.

Dielnimmers oan de kompetysje:

  • ferwizing wichtichste kanaal
  • de held fan dit artikel is ipipou
  • OpenVPN mei autentikaasje mar gjin fersifering
  • OpenVPN yn all-inclusive modus
  • WireGuard sûnder PresharedKey, mei MTU = 1440 (sûnt IPv4-allinnich)

Technyske gegevens foar geeks
Metriken wurde nommen mei de folgjende kommando's:

op de klant:

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 latency

ping -c 10 SERVER_IP | tail -1

op de tsjinner (rint tagelyk mei de client):

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"

Tunnel konfiguraasje

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

klant
/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 (gjin fersifering, mei autentikaasje)
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

klant

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 (mei fersifering, autentikaasje, fia UDP, alles lykas ferwachte)
Konfigurearre mei help fan openvpn-behear

wire guard
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

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

Resultaten

Fochtich lelijk teken
Server CPU-load is net heul yndikatyf, om't ... D'r rinne dêr in protte oare tsjinsten, soms ite se boarnen op:

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 kanaal

ipipou: mear as allinnich in net fersifere tunnel

ipipou: mear as allinnich in net fersifere tunnel

kanaal per 1 optimistysk Gbps

ipipou: mear as allinnich in net fersifere tunnel

ipipou: mear as allinnich in net fersifere tunnel

Yn alle gefallen is ipipou yn prestaasjes frij ticht by it basiskanaal, wat geweldich is!

De net-fersifere openvpn-tunnel gedrage him yn beide gefallen frij nuver.

As immen it sil testen, sil it ynteressant wêze om feedback te hearren.

Mei IPv6 en NetPrickle by ús wêze!

Boarne: www.habr.com

Add a comment