ipipou: mer Àn bara en okrypterad tunnel

Vad sÀger vi till IPv6-guden?

ipipou: mer Àn bara en okrypterad tunnel
Korrekt, och vi sÀger samma sak till kryptografins gud idag.

HÀr kommer vi att prata om den okrypterade IPv4-tunneln, men inte om den "varma lampan", utan om den moderna "LED-en". HÀr finns ocksÄ rÄa sockets, och det pÄgÄr arbete med paket i anvÀnderrummet.

Det finns N tunneleringsprotokoll för alla smaker och fÀrger:

  • styliga, trendiga, ungdomliga WireGuard
  • multifunktionella, som schweiziska armĂ©knivar, OpenVPN och SSH
  • gamla och snĂ€lla GRE
  • maximalt enkla, snabba, helt okrypterade IPIP
  • aktivt utvecklande GENEVE
  • mĂ„nga andra.

Men jag Àr programmerare, sÄ jag ökar N med bara en brÄkdel, och överlÄter utvecklingen av riktiga protokoll till ď-utvecklarna.

I ett Ànnu ofött projektprojekt som jag arbetar med nu, mÄste jag nÄ hostar bakom NAT utifrÄn. Genom att anvÀnda protokoll med vuxen kryptografi, har jag hela tiden haft en kÀnsla av att detta Àr att skjuta med kanoner pÄ sparvar. Eftersom tunneln mestadels anvÀnds för att borra ett hÄl i NAT:en, Àr den interna trafiken vanligtvis ocksÄ krypterad, man satsar ÀndÄ pÄ HTTPS.

NÀr jag undersökte olika tunneleringsprotokoll, fÄngade min inre perfektionists uppmÀrksamhet IPIP pÄ grund av dess minimala overhead. Men det har en och en halv betydande nackdel för mina uppgifter:

  • det krĂ€ver offentliga IP pĂ„ bĂ„da sidor,
  • och ingen autentisering.

SÄ perfektionisten satt fast i ett mörkt hörn av skallen, eller dÀr han nu befinner sig.

Och en gÄng lÀste jag artiklar om nativt stödda tunnlar i Linux, och snubblade över FOU (Foo-over-UDP), dvs. vad som helst inbÀddat i UDP. Just nu stöds bara IPIP och GUE (Generic UDP Encapsulation).

"DĂ€r har vi silverkulan! För mig rĂ€cker det med vanlig IPIP." — tĂ€nkte jag.

I verkligheten visade sig kulan inte vara helt silverfĂ€rgad. InbĂ€ddningen i UDP löser det första problemet — kunder bakom NAT kan nĂ„s utifrĂ„n med en förhandsinstallerad anslutning, men hĂ€r blomstrar en del av IPIPs nĂ€sta nackdel i ett nytt ljus — bakom de synliga offentliga IP och klientens port kan vem som helst frĂ„n det privata nĂ€tverket gömma sig (i ren IPIP finns det inget sĂ„dant problem).

För att lösa detta halvproblem föddes verktyget ipipouI den implementeras en egen mekanism för autentisering av den fjÀrranslutna vÀrden, utan att störa den kÀrnfulla FOU, som snabbt och effektivt kommer att hantera paket i kÀrnans utrymme.

Din skript behövs inte!

Okej, om du kÀnner till den offentliga porten och IP-adressen för klienten (till exempel för att sÀkerstÀlla att de inte gÄr vart som helst, NAT försöker mappa portar 1-1), kan du skapa en IPIP-over-FOU-tunnel med följande kommandon, utan nÄgra skript.

pÄ servern:

# ĐŸĐŸĐŽĐłŃ€ŃƒĐ·ĐžŃ‚ŃŒ ĐŒĐŸĐŽŃƒĐ»ŃŒ яЮра 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

pÄ klienten:

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

# Alternativen local, peer, peer_port, dev kan kanske inte stödjas av Àldre kÀrnor, de kan utelÀmnas.
# peer och peer_port anvÀnds för att skapa en anslutning direkt nÀr FOU-lyssnaren skapas.
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

  • ipipou* — namnet pĂ„ det lokala tunnel-nĂ€tverksgrĂ€nssnittet
  • 203.0.113.1 — den offentliga IP-adressen för servern
  • 198.51.100.2 — den offentliga IP-adressen för klienten
  • 192.168.0.2 — klientens IP-adress tilldelad grĂ€nssnittet eth0
  • 10001 — klientens lokala port för FOU
  • 20001 — klientens offentliga port för FOU
  • 10000 — serverns offentliga port för FOU
  • encap-csum — alternativ för att lĂ€gga till en kontrollsumma i inkapslade UDP-paket; kan bytas ut mot noencap-csum, sĂ„ att det inte berĂ€knas, integriteten kontrolleras av det yttre inkapslingslagret (sĂ„ lĂ€nge paketet befinner sig inom tunneln)
  • eth0 — den lokala grĂ€nssnitt dĂ€r ipip-tunneln kommer att kopplas
  • 172.28.0.1 — IP-adressen för klientens tunnelgrĂ€nssnitt (privat)
  • 172.28.0.0 — IP-adressen för serverns tunnelgrĂ€nssnitt (privat)

SĂ„ lĂ€nge UDP-anslutningen lever, kommer tunneln att förbli i fungerande tillstĂ„nd, men nĂ€r den bryts Ă€r det som det Ă€r — om IP: porten för klienten förblir densamma — kommer det att fungera, om de Ă€ndras — bryts den.

Det Àr enklast att ÄterstÀlla allt genom att ladda ur kÀrnmodulerna: modprobe -r fou ipip

Även om autentisering inte krĂ€vs, Ă€r offentliga IP-adresser och klientportar inte alltid kĂ€nda och Ă€r ofta oförutsĂ€gbara eller förĂ€nderliga (beroende pĂ„ typ av NAT). Om man utelĂ€mnar encap-dport pĂ„ servern, kommer tunneln inte att fungera, den Ă€r inte tillrĂ€ckligt smart för att ta den fjĂ€rranslutna porten för anslutningen. I sĂ„dana fall kan ipipou ocksĂ„ hjĂ€lpa, eller sĂ„ kan WireGuard och dess alternativ vara till hjĂ€lp.

Hur fungerar det?

Klienten (som vanligt bakom en NAT) etablerar en tunnel (som i exemplet ovan) och skickar en autentisering paket till servern för att konfigurera tunneln frÄn sin sida. Beroende pÄ instÀllningarna kan detta vara ett tomt paket (bara sÄ att servern ser den offentliga IP-adressen och portanslutningen), eller med data som servern kan anvÀnda för att identifiera klienten. Data kan vara en enkel lösenfras i ren text (jag kommer att tÀnka pÄ en liknelse med HTTP Basic Auth) eller signerad med en privat nyckel, speciellt formaterade data (i analogi med HTTP Digest Auth, men starkare, se funktionen client_auth i koden).

PÄ servern (sidan med den offentliga IP-adressen) skapar ipipou en hanterare för kön nfqueue vid start och konfigurerar netfilter sÄ att nödvÀndiga paket dirigeras dit de ska: paket som initierar anslutningen gÄr till kön nfqueue, medan [nÀstan] alla andra gÄr direkt till FOU-lyssnaren.

För de som inte Àr insatta, nfqueue (eller NetfilterQueue) Àr en speciell grej för nybörjare som inte kan utveckla kÀrnmoduler, som medel för netfilter (nftables/iptables) gör det möjligt att omdirigera nÀtverkspaket till anvÀndarutrymmet och bearbeta dem dÀr med primitiva verktyg: modifiera (valfritt) och skicka tillbaka dem till kÀrnan, eller slÀnga dem.

För vissa programmeringssprÄk finns det bindningar för att arbeta med nfqueue, men för bash hittade jag inget (heh, inte förvÄnande), sÄ jag var tvungen att anvÀnda python: ipipou anvÀnder NetfilterQueue.

Om prestanda inte Àr kritisk kan man med hjÀlp av detta enkelt och relativt snabbt skapa egen logik för arbetet med paket pÄ en ganska lÄg nivÄ, till exempel designa experimentella datatransmissionsprotokoll eller trolla lokala och fjÀrrtjÀnster med ovanligt beteende.

Tillsammans med nfqueue fungerar rĂ„a sockets (raw sockets), till exempel nĂ€r tunneln redan Ă€r konfigurerad och FOU lyssnar pĂ„ rĂ€tt port, gĂ„r det inte att skicka ett paket frĂ„n den porten pĂ„ vanligt sĂ€tt — den Ă€r upptagen, men man kan ta och skicka ett godtyckligt genererat paket direkt till nĂ€tverksgrĂ€nssnittet med en rĂ„ socket, Ă€ven om det krĂ€vs lite mer arbete för genereringen av ett sĂ„dant paket. SĂ„ hĂ€r skapas autentiseringspaket i ipipou.

Eftersom ipipou endast bearbetar de första paketen frÄn anslutningen (och Àven de som lyckades smita in i kön innan anslutningen upprÀttades) pÄverkas prestandan nÀstan inte.

SÄ snart ipipou-servern fÄr ett paket som har passerat autentiseringen, skapas tunneln och alla efterföljande paket i anslutningen bearbetas redan av kÀrnan utan att gÄ igenom nfqueue. Om anslutningen har tidsbegrÀnsats, kommer det första paketet för nÀsta att skickas till nfqueue, beroende pÄ instÀllningarna; om detta inte Àr ett autentiseringspaket, utan frÄn den senaste registrerade IP-adressen och klientens port, kan det antingen tillÄtas att gÄ vidare eller kastas bort. Om ett autentiserat paket anlÀnder frÄn nya IP-adresser och portar, omkonfigureras tunneln för att anvÀnda dem.

En vanlig IPIP-over-FOU har ytterligare ett problem nĂ€r den arbetar med NAT – det gĂ„r inte att skapa tvĂ„ IPIP-tunnlar inkapslade i UDP med samma IP, eftersom FOU och IPIP-modulerna Ă€r ganska isolerade frĂ„n varandra. Det vill sĂ€ga, ett par klienter bakom en offentlig IP kan inte ansluta till samma server pĂ„ det sĂ€ttet samtidigt. I framtiden, Ă€r möjligt, kommer detta att lösas pĂ„ kĂ€rnnivĂ„, men det Ă€r osĂ€kert. Under tiden kan NAT-problem hanteras genom NAT – om det sĂ„ hĂ€nder att ett par IP-adresser redan anvĂ€nds av en annan tunnel, kommer ipipou att göra NAT frĂ„n den offentliga till en alternativ privat IP, voila! – du kan skapa tunnlar tills portar tar slut.

Eftersom inte alla paket i anslutningen Àr signerade, Àr denna enkla skyddsmetod sÄrbar för MITM, sÄ om det finns en skurk pÄ vÀgen mellan klienten och servern som kan lyssna pÄ trafiken och styra den, kan denne omdirigera autentiseringspaket via en annan adress och skapa en tunnel frÄn en otillförlitlig vÀrd.

Om nÄgon har idéer om hur man kan ÄtgÀrda detta och samtidigt behÄlla huvudparten av trafiken i kÀrnan, tveka inte - kom med förslag.

För att nÀmna det, har inkapslingen i UDP visat sig vara mycket pÄlitlig. JÀmfört med inkapsling ovanpÄ IP Àr den mycket mer stabil och ofta snabbare trots de extra overheadkostnaderna för UDP-huvudet. Detta beror pÄ att en stor del av vÀrdarna pÄ Internet endast fungerar anstÀndigt med de tre mest populÀra protokollen: TCP, UDP, ICMP. En mÀrkbar del kan helt enkelt avvisa allt annat eller bearbeta det lÄngsammare, eftersom de endast Àr optimerade för dessa tre.

Till exempel, dÀrför byggdes QUICK, pÄ vilket HTTP/3 Àr baserat, just ovanpÄ UDP, och inte ovanpÄ IP.

NÄvÀl, nog med snack, lÄt oss se hur det fungerar i den "verkliga vÀrlden".

Strid

För att efterlikna den verkliga vÀrlden anvÀnds iperf3. NÀr det gÀller hur nÀra verkligheten det Àr, Àr det ungefÀr som att efterlikna den verkliga vÀrlden i Minecraft, men för nu fÄr det duga.

I tÀvlingen deltar:

  • referens huvudkanal
  • huvudpersonen i denna artikel ipipou
  • OpenVPN med autentisering, men utan kryptering
  • OpenVPN i "alla inkluderat" lĂ€ge
  • WireGuard utan PresharedKey, med MTU=1440 (eftersom endast IPv4)

Teknisk information för nördar
MÀtvÀrden tas med hjÀlp av följande kommandon

pÄ klienten:

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"
# DÀr "-b 12M" Àr bandbredden för huvudkanalen, delad med antal strömmar "-P", för att inte skapa onödiga paket och försÀmra prestanda.

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-latens

ping -c 10 SERVER_IP | tail -1

pÄ servern (startas samtidigt som klienten):

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"

Tunnelkonfiguration

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 (utan kryptering, med autentisering)
server

openvpn --genkey --secret ovpn.key  # Sedan mÄste ovpn.key skickas till klienten
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 (med kryptering, autentisering, via UDP, precis som det ska vara)
InstÀllt med hjÀlp av 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

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

Resultat

RĂ„ ful tabell
CPU-belastningen pÄ servern Àr inte sÀrskilt representativ, eftersom det körs mÄnga andra tjÀnster som ibland anvÀnder resurser:

proto bandbredd[Mbps] CPU_idle_client[%] CPU_idle_server[%]
# 20 Mbps-kanal frÄn mikrodator (4 kÀrnor) till VPS (1 kÀrna) över Atlanten
# ren
UDP 20.4      99.80 93.34
TCP 19.2      99.67 96.68
ICMP latens 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 latens min/med/max/mdev = 199.562/208.919/220.222/7.905 ms
# openvpn0 (endast autentisering, ingen kryptering)
UDP 19.3      99.89 72.90
TCP 16.1      95.95 88.46
ICMP latens min/med/max/mdev = 191.631/193.538/198.724/2.520 ms
# openvpn (full kryptering, autentisering etc)
UDP 19.6      99.75 72.35
TCP 17.0      94.47 87.99
ICMP latens 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 latens min/med/max/mdev = 217.925/223.601/230.696/3.266 ms

## cirka-1Gbps kanal mellan VPS Europa och USA (1 kÀrna)
# ren
UDP 729      73.40 39.93
TCP 363      96.95 90.40
ICMP latens 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 latens min/med/max/mdev = 107.444/107.523/107.648/0.058 ms
# openvpn0 (endast autentisering, ingen kryptering)
UDP 193      17.51  1.62
TCP  12      95.45 92.80
ICMP latens 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 latens min/med/max/mdev = 107.616/107.788/108.038/0.128 ms

kanal pÄ 20 Mbps

ipipou: mer Àn bara en okrypterad tunnel

ipipou: mer Àn bara en okrypterad tunnel

kanal pÄ 1 optimistisk Gbps

ipipou: mer Àn bara en okrypterad tunnel

ipipou: mer Àn bara en okrypterad tunnel

I alla fall Àr ipipou ganska nÀra baslinjen i prestanda, och det Àr fantastiskt!

Den okrypterade openvpn-tunneln upptrÀdde ganska konstigt i bÄda fallen.

Om nÄgon vill testa, skulle det vara intressant att höra feedback.

MĂ„ IPv6 och NetPrickle vara med oss!

KĂ€lla: habr.com

Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar đŸ”„ Köp pĂ„litlig webbhotell med DDoS-skydd, VPS VDS-servrar | ProHoster