Aquí parlarem d'un túnel IPv4 no xifrat, però no d'un de "làmpada calenta", sinó d'un de "LED" modern. I també hi ha endolls en brut parpellejant aquí, i s'està treballant amb paquets a l'espai d'usuari.
Hi ha N protocols de túnel per a cada gust i color:
Però sóc programador, així que augmentaré N només en una fracció i deixaré el desenvolupament de protocols reals als desenvolupadors de Kommersant.
En un no nascut projecteEl que estic fent ara és arribar als amfitrions darrere de NAT des de l'exterior. Utilitzant protocols amb criptografia per a adults per a això, no vaig poder treure la sensació que era com disparar pardals amb un canó. Perquè el túnel s'utilitza en la seva major part només per fer forats a NAT-e, el trànsit intern també s'encripta, però encara s'ofeguen en HTTPS.
Mentre investigava diversos protocols de túnel, l'atenció del meu perfeccionista interior es va cridar una vegada i una altra a IPIP a causa de la seva mínima sobrecàrrega. Però té un inconvenient i mig significatiu per a les meves tasques:
requereix IP públiques d'ambdós costats,
i cap autenticació per a tu.
Per tant, el perfeccionista va ser conduït de nou al racó fosc del crani, o allà on s'asseu.
I després un dia, mentre llegia articles sobre túnels suportats de forma nativa a Linux em vaig trobar amb FOU (Foo-over-UDP), és a dir. sigui el que sigui, embolicat en UDP. Fins ara, només s'admeten IPIP i GUE (Encapsulació UDP genèrica).
"Aquí està la bala de plata! Un simple IPIP és suficient per a mi". - Vaig pensar.
De fet, la bala va resultar no ser completament platejada. L'encapsulació en UDP resol el primer problema: podeu connectar-vos als clients darrere de NAT des de l'exterior mitjançant una connexió preestablerta, però aquí la meitat del següent inconvenient de l'IPIP floreix amb una nova llum: qualsevol persona d'una xarxa privada pot amagar-se darrere del visible. IP pública i port de client (en IPIP pur aquest problema no existeix).
Per resoldre aquest problema i mig, va néixer la utilitat ipipou. Implementa un mecanisme casolà per autenticar un host remot, sense interrompre el funcionament de la FOU del nucli, que processarà de manera ràpida i eficient els paquets a l'espai del nucli.
No necessitem el teu guió!
D'acord, si coneixeu el port públic i la IP del client (per exemple, tots els que hi ha al darrere no van enlloc, NAT intenta mapejar els ports 1 en 1), podeu crear un túnel IPIP sobre FOU amb el següents ordres, sense cap script.
al servidor:
# Подгрузить модуль ядра 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
al client:
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
on
ipipou* — nom de la interfície de xarxa del túnel local
203.0.113.1 — Servidor IP públic
198.51.100.2 — IP pública del client
192.168.0.2 — IP del client assignada a la interfície eth0
10001 — Port de client local per a FOU
20001 — Port públic client per a FOU
10000 — port de servidor públic per a FOU
encap-csum — opció per afegir una suma de verificació UDP als paquets UDP encapsulats; es pot substituir per noencap-csum, sense oblidar, la integritat ja està controlada per la capa d'encapsulació exterior (mentre el paquet està dins del túnel)
eth0 — interfície local a la qual s'enllaçarà el túnel ipip
172.28.0.1 — IP de la interfície del túnel del client (privada)
172.28.0.0 — Interfície del servidor del túnel IP (privada)
Mentre la connexió UDP estigui viva, el túnel estarà en condicions de funcionament, però si es trenca, tindreu sort -si el port IP: del client segueix sent el mateix - viurà, si canvien - es trencarà.
La manera més senzilla de tornar-ho tot enrere és descarregar els mòduls del nucli: modprobe -r fou ipip
Encara que no sigui necessària l'autenticació, la IP i el port públics del client no sempre es coneixen i sovint són impredictibles o variables (segons el tipus de NAT). Si ometes encap-dport al costat del servidor, el túnel no funcionarà, no és prou intel·ligent per agafar el port de connexió remota. En aquest cas, ipipou també us pot ajudar, o WireGuard i altres com aquest us poden ajudar.
Com funciona?
El client (que normalment està darrere de NAT) obre un túnel (com a l'exemple anterior) i envia un paquet d'autenticació al servidor perquè configuri el túnel al seu costat. Segons la configuració, aquest pot ser un paquet buit (només perquè el servidor pugui veure la IP pública: port de connexió), o amb dades per les quals el servidor pugui identificar el client. Les dades poden ser una frase de contrasenya senzilla en text clar (em ve a la ment l'analogia amb HTTP Basic Auth) o dades dissenyades especialment signades amb una clau privada (similar a HTTP Digest Auth només més forta, vegeu la funció client_auth al codi).
Al servidor (al costat de la IP pública), quan s'inicia ipipou, crea un gestor de cues nfqueue i configura netfilter perquè s'enviïn els paquets necessaris on haurien d'estar: paquets que inicialitzen la connexió a la cua nfqueue, i [quasi] tota la resta va directament a l'oient FOU.
Per a aquells que no ho saben, nfqueue (o NetfilterQueue) és una cosa especial per als aficionats que no saben com desenvolupar mòduls del nucli, que amb netfilter (nftables/iptables) us permet redirigir paquets de xarxa a l'espai de l'usuari i processar-los allà fent servir primitius significa a mà: modificar (opcional) i tornar-lo al nucli, o descartar-lo.
Per a alguns llenguatges de programació hi ha enllaços per treballar amb nfqueue, per a bash no n'hi havia cap (je, no és sorprenent), vaig haver d'utilitzar python: ipipou utilitza NetfilterQueue.
Si el rendiment no és crític, amb aquesta cosa podeu inventar la vostra pròpia lògica de manera relativament ràpida i senzilla per treballar amb paquets a un nivell força baix, per exemple, crear protocols de transferència de dades experimentals o trobar serveis locals i remots amb un comportament no estàndard.
Els endolls en brut funcionen mà a mà amb nfqueue, per exemple, quan el túnel ja està configurat i FOU està escoltant al port desitjat, no podreu enviar un paquet des del mateix port de la manera habitual: està ocupat, però podeu agafar i enviar un paquet generat aleatòriament directament a la interfície de xarxa mitjançant un sòcol en brut, tot i que generar aquest paquet requerirà una mica més de retoc. Així és com es creen els paquets amb autenticació a ipipou.
Com que ipipou només processa els primers paquets de la connexió (i els que van aconseguir filtrar-se a la cua abans d'establir la connexió), el rendiment gairebé no es ressent.
Tan bon punt el servidor ipipou rep un paquet autenticat, es crea un túnel i tots els paquets posteriors de la connexió ja són processats pel nucli sense passar nfqueue. Si la connexió falla, el primer paquet del següent s'enviarà a la cua nfqueue, depenent de la configuració, si no es tracta d'un paquet amb autenticació, sinó des de l'última IP recordada i el port del client, es pot passar. activat o descartat. Si un paquet autenticat prové d'una IP i un port nous, el túnel es reconfigura per utilitzar-los.
L'IPIP-over-FOU habitual té un problema més quan es treballa amb NAT: és impossible crear dos túnels IPIP encapsulats en UDP amb la mateixa IP, perquè els mòduls FOU i IPIP estan bastant aïllats entre si. Aquells. un parell de clients darrere de la mateixa IP pública no es podran connectar simultàniament al mateix servidor d'aquesta manera. En el futur, potser, es resoldrà a nivell del nucli, però això no és segur. Mentrestant, els problemes de NAT es poden resoldre mitjançant NAT: si passa que un parell d'adreces IP ja està ocupada per un altre túnel, ipipou farà NAT d'una IP pública a una privada alternativa, voilà! - pots crear túnels fins que s'acabin els ports.
Perquè No tots els paquets de la connexió estan signats, aleshores aquesta protecció senzilla és vulnerable a MITM, de manera que si hi ha un dolent a l'aguait al camí entre el client i el servidor que pot escoltar el trànsit i manipular-lo, pot redirigir els paquets autenticats a través de una altra adreça i creeu un túnel des d'un amfitrió no fiable.
Si algú té idees sobre com solucionar-ho tot deixant la major part del trànsit al nucli, no dubteu a parlar.
Per cert, l'encapsulació en UDP s'ha demostrat molt bé. En comparació amb l'encapsulació per IP, és molt més estable i sovint més ràpid malgrat la sobrecàrrega addicional de la capçalera UDP. Això es deu al fet que la majoria dels amfitrions a Internet només funcionen bé amb els tres protocols més populars: TCP, UDP, ICMP. La part tangible pot descartar completament tota la resta, o processar-la més lentament, perquè només està optimitzada per a aquests tres.
Per exemple, aquesta és la raó per la qual QUICK, en què es basa HTTP/3, es va crear sobre UDP, i no sobre IP.
Bé, prou paraules, és hora de veure com funciona al "món real".
Batalla
S'utilitza per emular el món real iperf3. Pel que fa al grau de proximitat a la realitat, això és aproximadament el mateix que emular el món real a Minecraft, però de moment ho farà.
Participants al concurs:
canal principal de referència
l'heroi d'aquest article és ipipou
OpenVPN amb autenticació però sense xifratge
OpenVPN en mode tot inclòs
WireGuard sense PresharedKey, amb MTU=1440 (només des d'IPv4)
Dades tècniques per frikis Les mètriques es prenen amb les ordres següents:
al client:
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", чтобы лишние пакеты не плодить и не портить производительность.
Signe lleig humit
La càrrega de la CPU del servidor no és gaire indicativa, perquè... Hi ha molts altres serveis que hi funcionen, de vegades es consumeixen recursos:
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
Canal de 20 Mbps
canal per 1 Gbps optimista
En tots els casos, ipipou s'acosta bastant en rendiment al canal base, que és genial!
El túnel openvpn sense xifrar es va comportar de manera força estranya en ambdós casos.
Si algú el prova, serà interessant rebre comentaris.