Így van, ma ugyanezt mondjuk a titkosítás istenének.
Itt egy titkosítatlan IPv4 alagútról lesz szó, de nem egy „meleglámpáról”, hanem egy modern „LED”-ről. És itt is villognak a nyers socketek, és zajlik a munka a csomagokkal a felhasználói térben.
Minden ízléshez és színhez N alagútkezelési protokoll létezik:
De programozó vagyok, ezért az N-t csak töredékével növelem, a valódi protokollok fejlesztését pedig a Kommersant fejlesztőire bízom.
Egy meg nem születettben programAmit most csinálok, az az, hogy kívülről elérem a NAT mögötti házigazdákat. Felnőtt titkosítási protokollokat használva erre, nem tudtam megszabadulni attól az érzéstől, mintha ágyúból verebeket lőnék ki. Mert az alagutat nagyrészt csak a NAT-e-n való lyukasztásra használják, a belső forgalom is általában titkosítva van, de így is belefulladnak a HTTPS-be.
A különféle alagútkezelési protokollok kutatása közben a belső perfekcionistám figyelmét újra és újra felkeltette az IPIP a minimális rezsi miatt. De van másfél jelentős hátránya a feladataim szempontjából:
mindkét oldalon nyilvános IP-címekre van szükség,
és nincs hitelesítés neked.
Ezért a perfekcionistát visszaterelték a koponya sötét sarkába, vagy bárhová, ahol ül.
Aztán egy nap, miközben cikkeket olvasok róla natívan támogatott alagutak Linuxban találkoztam a FOU-val (Foo-over-UDP), azaz. mindegy, UDP-be csomagolva. Eddig csak az IPIP és a GUE (Generic UDP Encapsulation) támogatott.
„Itt az ezüstgolyó! Nekem elég egy egyszerű IPIP.” - Azt gondoltam.
Valójában kiderült, hogy a golyó nem teljesen ezüst. Az UDP-be ágyazás megoldja az első problémát – a NAT mögötti kliensekhez kívülről is kapcsolódhat egy előre kialakított kapcsolat segítségével, de itt az IPIP következő hátrányának fele új megvilágításban virágzik – a magánhálózatból bárki elbújhat a látható mögé. nyilvános IP és kliens port (tiszta IPIP esetén ez a probléma nem létezik).
Ennek a másfél problémának a megoldására született meg a segédprogram ipipou. Saját készítésű mechanizmust valósít meg a távoli gazdagép hitelesítésére anélkül, hogy megzavarná a kernel FOU működését, amely gyorsan és hatékonyan dolgozza fel a csomagokat a kerneltérben.
Nincs szükségünk a forgatókönyvére!
Ok, ha ismeri a kliens nyilvános portját és IP-jét (pl. mögötte mindenki nem megy sehova, a NAT megpróbálja leképezni a portokat 1 az 1-ben), létrehozhat egy IPIP-over-FOU alagutat a a következő parancsokat, szkriptek nélkül.
szerveren:
# Подгрузить модуль ядра 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
az ügyfélen:
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
ahol
ipipou* — a helyi alagúthálózati interfész neve
203.0.113.1 — nyilvános IP-szerver
198.51.100.2 — az ügyfél nyilvános IP-címe
192.168.0.2 — az eth0 interfészhez rendelt kliens IP
10001 — helyi ügyfélport a FOU számára
20001 — nyilvános ügyfélport a FOU számára
10000 — nyilvános szerver port a FOU számára
encap-csum — lehetőség UDP-ellenőrző összeg hozzáadására a beágyazott UDP-csomagokhoz; helyettesíthető noencap-csum, nem beszélve arról, hogy az integritást már a külső tokozási réteg szabályozza (amíg a csomag az alagútban van)
eth0 — helyi interfész, amelyhez az ipip alagút hozzá lesz kötve
172.28.0.1 — a kliens alagút interfész IP-je (privát)
172.28.0.0 — IP tunnel szerver interfész (privát)
Amíg az UDP kapcsolat él, az alagút üzemképes, de ha megszakad, akkor szerencséd lesz - ha a kliens IP: portja változatlan marad - él, ha változnak - megszakad.
A legegyszerűbb módja annak, hogy mindent visszafordítson, a kernelmodulok eltávolítása: modprobe -r fou ipip
Még ha nincs is szükség hitelesítésre, az ügyfél nyilvános IP-címe és portja nem mindig ismert, és gyakran kiszámíthatatlan vagy változó (a NAT típusától függően). Ha kihagyja encap-dport szerver oldalon az alagút nem fog működni, nem elég okos a távoli kapcsolat portját venni. Ebben az esetben az ipipou is segíthet, vagy a WireGuard és a hozzá hasonlók.
Hogyan működik?
A kliens (amely általában a NAT mögött van) megnyit egy alagutat (mint a fenti példában), és hitelesítési csomagot küld a kiszolgálónak, hogy az a maga oldalán konfigurálja az alagutat. Ez a beállításoktól függően lehet üres csomag (csak azért, hogy a szerver lássa a nyilvános IP: kapcsolati portot), vagy olyan adatokkal, amelyek alapján a szerver azonosítani tudja a klienst. Az adatok lehetnek egyszerű jelmondatok egyértelmű szövegben (a HTTP Basic Auth analógiája jut eszembe), vagy speciálisan tervezett, privát kulccsal aláírt adat (hasonlóan a HTTP Digest Auth-hoz, csak erősebb, lásd a funkciót client_auth a kódban).
A szerveren (a nyilvános IP-vel rendelkező oldalon) az ipipou elindulásakor létrehoz egy nfqueue sorkezelőt, és beállítja a netfiltert úgy, hogy a szükséges csomagok oda kerüljenek elküldésre, ahol lenniük kell: az nfqueue sorhoz való csatlakozást inicializáló csomagok, és [majdnem] az összes többi egyenesen a FOU hallgatóhoz kerül.
Azok számára, akik nem ismerik, az nfqueue (vagy NetfilterQueue) egy speciális dolog az amatőrök számára, akik nem tudják, hogyan kell kernelmodulokat fejleszteni, ami a netfilter (nftables/iptables) segítségével lehetővé teszi a hálózati csomagok átirányítását a felhasználói térbe, és ott feldolgozva. primitív azt jelenti, hogy kéznél van: módosítsd (opcionális ) és add vissza a kernelnek, vagy dobd el.
Néhány programozási nyelvhez vannak kötések az nfqueue-val való munkavégzéshez, a bash-hoz nem volt (heh, nem meglepő), pythont kellett használnom: ipipou használ NetfilterQueue.
Ha a teljesítmény nem kritikus, akkor ezzel a dologgal viszonylag gyorsan és egyszerűen kitalálhatja a saját logikáját a meglehetősen alacsony szintű csomagokkal való munkavégzéshez, például kísérleti adatátviteli protokollokat készíthet, vagy helyi és távoli szolgáltatásokat nem szabványos viselkedéssel.
A nyers socketek kéz a kézben működnek az nfqueue-val, például amikor az alagút már konfigurálva van, és a FOU a kívánt porton figyel, akkor ugyanarról a portról nem fog tudni csomagot küldeni a szokásos módon – foglalt, de egy véletlenszerűen generált csomagot nyers socket segítségével közvetlenül a hálózati interfészre vehetünk és küldhetünk, bár egy ilyen csomag előállítása még egy kis trükközést igényel. Így jönnek létre a hitelesítéssel ellátott csomagok az ipipou-ban.
Mivel az ipipou csak a kapcsolat első csomagjait dolgozza fel (és azokat, amelyeknek sikerült a sorba szivárogniuk a kapcsolat létrejötte előtt), a teljesítmény szinte nem csorbul.
Amint az ipipou kiszolgáló hitelesített csomagot kap, egy alagút jön létre, és a kapcsolat minden további csomagját már feldolgozza a kernel, megkerülve az nfqueue-t. Ha a kapcsolat meghiúsul, akkor a következő első csomagja az nfqueue sorba kerül, beállításoktól függően, ha nem hitelesítéssel rendelkező csomag, hanem az utoljára emlékezett IP-ről és kliens portról, akkor vagy átadható bekapcsolva vagy eldobva. Ha egy hitelesített csomag új IP-címről és portról érkezik, az alagút újrakonfigurálva van ezek használatára.
A szokásos IPIP-over-FOU-nak van még egy problémája a NAT-tal való munka során - lehetetlen létrehozni két UDP-be burkolt IPIP alagutat ugyanazzal az IP-vel, mivel a FOU és az IPIP modulok meglehetősen el vannak szigetelve egymástól. Azok. ugyanazon nyilvános IP-cím mögött lévő klienspárok nem tudnak egyszerre csatlakozni ugyanahhoz a szerverhez ilyen módon. A jövőben, lehetséges, kernel szinten lesz megoldva, de ez nem biztos. Addig is a NAT-problémák megoldhatók NAT-tal - ha előfordul, hogy egy IP-címpárt már elfoglal egy másik alagút, akkor az ipipou a NAT-ot nyilvánosról alternatív privát IP-re végzi, íme! - alagutakat hozhat létre, amíg el nem fogynak a portok.
Mert A kapcsolaton belül nem minden csomag van aláírva, így ez az egyszerű védelem sebezhető a MITM-mel szemben, így ha a kliens és a szerver közötti úton egy gazember ólálkodik, aki meg tudja hallgatni a forgalmat és manipulálni tudja azt, át tudja irányítani a hitelesített csomagokat egy másik címet, és hozzon létre egy alagutat egy nem megbízható gazdagépről.
Ha valakinek van ötlete a probléma megoldására, miközben a forgalom nagy részét a magban hagyja, ne habozzon megszólalni.
Egyébként az UDP-be való tokozás nagyon jól bevált. Az IP-n keresztüli beágyazáshoz képest sokkal stabilabb és gyakran gyorsabb az UDP-fejléc többletterhelése ellenére. Ez annak a ténynek köszönhető, hogy az interneten a legtöbb gazdagép csak a három legnépszerűbb protokollal működik jól: TCP, UDP, ICMP. A kézzelfogható rész minden mást teljesen el tud dobni, vagy lassabban dolgozza fel, mert csak erre a háromra van optimalizálva.
Például ezért jött létre a QUICK, amelyen a HTTP/3 alapul, az UDP-n, és nem az IP-n.
Nos, elég a szóból, ideje megnézni, hogyan működik ez a „való világban”.
Csata
A való világ utánzására használják iperf3. A valósághoz való közelség mértékét tekintve ez megközelítőleg megegyezik a valós világ Minecraftban való utánzásával, de egyelőre megteszi.
A verseny résztvevői:
referencia fő csatorna
ennek a cikknek a hőse ipipou
OpenVPN hitelesítéssel, de titkosítás nélkül
OpenVPN all-inclusive módban
WireGuard PresharedKey nélkül, MTU=1440 (csak IPv4 óta)
Technikai adatok strébereknek A metrikák a következő parancsokkal vehetők fel:
az ügyfélen:
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", чтобы лишние пакеты не плодить и не портить производительность.