Zde budeme hovořit o nešifrovaném IPv4 tunelu, nikoli však o „teplém lampovém“, ale o moderním „LED“. A také zde blikají raw sockety a pracuje se s pakety v uživatelském prostoru.
Existuje N tunelovacích protokolů pro každý vkus a barvu:
Jsem ale programátor, takže N zvýším jen o zlomek a vývoj skutečných protokolů nechám na vývojářích Kommersantu.
V jednom nenarozeném projektTo, co teď dělám, je oslovit hostitele za NAT zvenčí. Když jsem k tomu použil protokoly s dospělou kryptografií, nemohl jsem se zbavit pocitu, že to bylo jako střílet vrabce z děla. Protože tunel slouží z větší části jen k vrtání děr v NAT-e, interní provoz je většinou také šifrovaný, ale stejně se topí v HTTPS.
Při zkoumání různých tunelovacích protokolů byla pozornost mého vnitřního perfekcionisty znovu a znovu přitahována k IPIP kvůli jeho minimální režii. Ale pro mé úkoly to má jednu a půl významné nevýhody:
vyžaduje veřejné IP adresy na obou stranách,
a žádné ověření pro vás.
Proto byl perfekcionista zahnán zpět do temného koutu lebky, nebo kamkoli tam sedí.
A pak jednoho dne, při čtení článků o nativně podporované tunely v Linuxu jsem narazil na FOU (Foo-over-UDP), tzn. cokoliv, zabalené v UDP. Zatím jsou podporovány pouze IPIP a GUE (Generic UDP Encapsulation).
„Tady je stříbrná kulka! Stačí mi jednoduchý IPIP.“ - Myslel jsem.
Ve skutečnosti se ukázalo, že kulka nebyla úplně stříbrná. Zapouzdření v UDP řeší první problém - ke klientům za NAT se můžete připojit zvenčí pomocí předem vytvořeného připojení, ale zde se polovina další nevýhody IPIP rozkvétá v novém světle - kdokoli z privátní sítě se může schovat za viditelné veřejná IP a klientský port (v čistém IPIP tento problém neexistuje).
K vyřešení tohoto jeden a půl problému se zrodil nástroj ipipou. Implementuje podomácku vyrobený mechanismus pro autentizaci vzdáleného hostitele, aniž by narušil provoz jádra FOU, který bude rychle a efektivně zpracovávat pakety v prostoru jádra.
Nepotřebujeme váš skript!
Dobře, pokud znáte veřejný port a IP klienta (například všichni za ním nikam nejdou, NAT se snaží mapovat porty 1-v-1), můžete vytvořit tunel IPIP-over-FOU pomocí následující příkazy, bez jakýchkoli skriptů.
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 klientovi:
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
kde
ipipou* — název síťového rozhraní lokálního tunelu
203.0.113.1 — veřejný IP server
198.51.100.2 — veřejná IP klienta
192.168.0.2 — IP klienta přiřazená rozhraní eth0
10001 — místní klientský port pro FOU
20001 — veřejný klientský port pro FOU
10000 — veřejný port serveru pro FOU
encap-csum — možnost přidat kontrolní součet UDP k zapouzdřeným paketům UDP; lze nahradit noencap-csumnemluvě o tom, že integrita je již řízena vnější zapouzdřovací vrstvou (zatímco paket je uvnitř tunelu)
eth0 — lokální rozhraní, na které bude ipip tunel vázán
172.28.0.1 — IP rozhraní klientského tunelu (soukromé)
172.28.0.0 — Rozhraní serveru IP tunelu (soukromé)
Dokud bude připojení UDP živé, bude tunel fungovat, ale pokud se rozbije, budete mít štěstí - pokud IP: port klienta zůstane stejný - bude žít, pokud se změní - prolomí se.
Nejjednodušší způsob, jak vše vrátit zpět, je uvolnit moduly jádra: modprobe -r fou ipip
I když není vyžadována autentizace, veřejná IP a port klienta nejsou vždy známy a často jsou nepředvídatelné nebo proměnlivé (v závislosti na typu NAT). Pokud vynecháte encap-dport na straně serveru nebude tunel fungovat, není dost chytrý, aby vzal port vzdáleného připojení. V tomto případě může pomoci i ipipou nebo vám může pomoci WireGuard a další jemu podobní.
Jak to funguje?
Klient (který je obvykle za NAT) otevře tunel (jako ve výše uvedeném příkladu) a odešle autentizační paket na server, aby nakonfiguroval tunel na své straně. V závislosti na nastavení to může být prázdný paket (jen proto, aby server viděl veřejnou IP: spojovací port), nebo s daty, podle kterých může server identifikovat klienta. Data mohou být jednoduchá přístupová fráze v čistém textu (napadá mě analogie s HTTP Basic Auth) nebo speciálně navržená data podepsaná soukromým klíčem (podobně jako HTTP Digest Auth jen silnější, viz funkce client_auth v kódu).
Na serveru (na straně s veřejnou IP), když se ipipou spustí, vytvoří obsluhu fronty nfqueue a nakonfiguruje netfilter tak, aby se potřebné pakety posílaly tam, kde mají být: pakety inicializující připojení k frontě nfqueue a [téměř] vše ostatní jde přímo k posluchači FOU.
Pro neznalé je nfqueue (nebo NetfilterQueue) speciální věc pro amatéry, kteří nevědí, jak vyvíjet moduly jádra, které pomocí netfilter (nftables/iptables) umožňují přesměrovat síťové pakety do uživatelského prostoru a zpracovat je tam pomocí primitivní prostředky po ruce: upravit (volitelné) a vrátit to jádru nebo je zahodit.
Pro některé programovací jazyky existují vazby pro práci s nfqueue, pro bash žádná nebyla (heh, není se čemu divit), musel jsem použít python: ipipou používá NetfilterQueue.
Pokud výkon není kritický, pomocí této věci si můžete poměrně rychle a snadno vymyslet vlastní logiku pro práci s pakety na poměrně nízké úrovni, například vytvořit experimentální protokoly přenosu dat nebo trollovat místní a vzdálené služby s nestandardním chováním.
Raw sockety fungují ruku v ruce s nfqueue, například když je tunel již nakonfigurován a FOU naslouchá na požadovaném portu, paket ze stejného portu nebudete moci odeslat běžným způsobem - je zaneprázdněn, ale můžete vzít a odeslat náhodně vygenerovaný paket přímo do síťového rozhraní pomocí raw socketu, i když generování takového paketu bude vyžadovat trochu více práce. Takto se v ipipou vytvářejí pakety s autentizací.
Vzhledem k tomu, že ipipou zpracovává pouze první pakety z připojení (a ty, kterým se podařilo uniknout do fronty před navázáním připojení), výkon téměř neutrpí.
Jakmile server ipipou přijme ověřený paket, vytvoří se tunel a všechny následující pakety ve spojení jsou již zpracovávány jádrem, které obchází nfqueue. Pokud se spojení nezdaří, tak do fronty nfqueue bude podle nastavení odeslán první paket dalšího, pokud se nejedná o paket s autentizací, ale z poslední zapamatované IP a klientského portu, lze jej buď předat na nebo vyřazeny. Pokud ověřený paket pochází z nové IP adresy a portu, tunel se překonfiguruje tak, aby je používal.
Obvyklý IPIP-over-FOU má při práci s NAT ještě jeden problém - nelze vytvořit dva IPIP tunely zapouzdřené v UDP se stejnou IP, protože moduly FOU a IPIP jsou od sebe dost izolované. Tito. dvojice klientů za stejnou veřejnou IP se nebude moci tímto způsobem současně připojit ke stejnému serveru. Napříště, možná, bude to řešeno na úrovni jádra, ale není to jisté. Mezitím lze problémy s NATem vyřešit NATem - pokud se stane, že pár IP adres je již obsazen jiným tunelem, ipipou udělá NAT z veřejné na alternativní privátní IP, voila! - můžete vytvářet tunely, dokud nedojdou porty.
Protože Ne všechny pakety ve spojení jsou podepsané, pak je tato jednoduchá ochrana zranitelná vůči MITM, takže pokud na cestě mezi klientem a serverem číhá padouch, který může naslouchat provozu a manipulovat s ním, může přesměrovat ověřené pakety přes jinou adresu a vytvořte tunel z nedůvěryhodného hostitele.
Pokud má někdo nápady, jak to opravit a přitom ponechat většinu provozu v jádru, neváhejte se ozvat.
Mimochodem, zapouzdření v UDP se velmi osvědčilo. Ve srovnání se zapouzdřením přes IP je mnohem stabilnější a často rychlejší navzdory dodatečné režii hlavičky UDP. To je způsobeno skutečností, že většina hostitelů na internetu funguje dobře pouze se třemi nejoblíbenějšími protokoly: TCP, UDP, ICMP. Hmotná část může vše ostatní úplně zahodit, případně zpracovat pomaleji, protože je optimalizována pouze pro tyto tři.
To je například důvod, proč byl QUICK, na kterém je založen HTTP/3, vytvořen nad UDP, a ne nad IP.
No, dost slov, je čas vidět, jak to funguje v „reálném světě“.
Bitva
Používá se k napodobení skutečného světa iperf3. Pokud jde o míru blízkosti reality, je to přibližně stejné jako emulace skutečného světa v Minecraftu, ale zatím to bude stačit.
Účastníci soutěže:
referenční hlavní kanál
hrdinou tohoto článku je ipipou
OpenVPN s ověřováním, ale bez šifrování
OpenVPN v režimu all-inclusive
WireGuard bez PresharedKey, s MTU=1440 (od pouze IPv4)
Technická data pro geeky Metriky se přebírají pomocí následujících příkazů:
na klientovi:
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", чтобы лишние пакеты не плодить и не портить производительность.