Aquí falaremos dun túnel IPv4 sen cifrar, pero non dun "lámpada quente", senón dun moderno "LED". E tamén hai sockets en bruto parpadeando aquí, e está a traballar con paquetes no espazo de usuario.
Pero eu son programador, polo que vou aumentar N só nunha fracción e deixarei o desenvolvemento de protocolos reais aos desenvolvedores de Kommersant.
Nun non nacido proxectoO que estou facendo agora é chegar aos anfitrións detrás de NAT desde fóra. Usando protocolos con criptografía para adultos para iso, non puiden sacudir a sensación de que era como disparar a pardais dun canón. Porque o túnel úsase na súa maior parte só para facer buracos en NAT-e, o tráfico interno adoita estar tamén cifrado, pero aínda se afogan en HTTPS.
Mentres investigaba varios protocolos de tunelización, a atención do meu perfeccionista interior chamoulle unha e outra vez a IPIP debido á súa mínima sobrecarga. Pero ten un inconveniente e medio significativo para as miñas tarefas:
require IPs públicas de ambos os dous lados,
e sen autenticación para ti.
Polo tanto, o perfeccionista foi conducido de volta ao recuncho escuro da caveira, ou onde queira que estea alí sentado.
E entón un día, mentres lía artigos sobre túneles soportados de forma nativa en Linux atopeime con FOU (Foo-over-UDP), é dicir. o que sexa, envolto en UDP. Ata agora, só se admiten IPIP e GUE (Encapsulación UDP xenérica).
"Aquí está a bala de prata! Un simple IPIP é suficiente para min". - Pensei.
De feito, a bala resultou non ser completamente prata. A encapsulación en UDP resolve o primeiro problema: pode conectarse aos clientes detrás de NAT desde o exterior mediante unha conexión preestablecida, pero aquí a metade do seguinte inconveniente de IPIP florece baixo unha nova luz: calquera persoa dunha rede privada pode esconderse detrás do visible. IP pública e porto cliente (en IPIP puro este problema non existe).
Para resolver este problema e medio, naceu a utilidade ipipou. Implementa un mecanismo feito na casa para autenticar un host remoto, sen interromper o funcionamento da FOU do núcleo, que procesará de forma rápida e eficiente os paquetes no espazo do núcleo.
Non necesitamos o teu guión!
Ok, se coñeces o porto público e a IP do cliente (por exemplo, todos os que están detrás del non van a ningún lado, NAT intenta mapear portos 1 en 1), podes crear un túnel IPIP sobre FOU co seguintes comandos, sen ningún script.
no 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
no cliente:
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
onde
ipipou* — nome da interface de rede local do túnel
203.0.113.1 - Servidor IP público
198.51.100.2 — IP pública do cliente
192.168.0.2 — IP do cliente asignada á interface eth0
10001 — porto de cliente local para FOU
20001 — porto público cliente para FOU
10000 — porto de servidor público para FOU
encap-csum — opción para engadir unha suma de verificación UDP aos paquetes UDP encapsulados; pode ser substituído por noencap-csum, sen mencionar que a integridade xa está controlada pola capa de encapsulación exterior (mentres o paquete está dentro do túnel)
eth0 — interface local á que se enlazará o túnel ipip
172.28.0.1 — IP da interface do túnel do cliente (privada)
172.28.0.0 - Interfaz do servidor de túnel IP (privado)
Mentres a conexión UDP estea activa, o túnel estará funcionando, pero se rompe, terás sorte -se o porto IP: do cliente segue a ser o mesmo - vivirá, se cambian - romperase.
A forma máis sinxela de darlle voltas atrás é descargar os módulos do núcleo: modprobe -r fou ipip
Aínda que non sexa necesaria a autenticación, a IP pública e o porto do cliente non sempre se coñecen e adoitan ser imprevisibles ou variables (dependendo do tipo de NAT). Se omites encap-dport no lado do servidor, o túnel non funcionará, non é o suficientemente intelixente para tomar o porto de conexión remota. Neste caso, ipipou tamén pode axudar, ou WireGuard e outros similares poden axudarche.
Como funciona isto?
O cliente (que adoita estar detrás de NAT) abre un túnel (como no exemplo anterior) e envía un paquete de autenticación ao servidor para que configure o túnel ao seu lado. Dependendo da configuración, este pode ser un paquete baleiro (só para que o servidor poida ver a IP pública: porto de conexión), ou con datos polos que o servidor pode identificar o cliente. Os datos poden ser unha simple frase de paso en texto claro (vénme á mente a analoxía con HTTP Basic Auth) ou datos especialmente deseñados asinados cunha clave privada (semellante a HTTP Digest Auth só é máis forte, consulte a función client_auth no código).
No servidor (o lado coa IP pública), cando se inicia ipipou, crea un manejador de colas nfqueue e configura netfilter para que se envíen os paquetes necesarios onde deberían estar: paquetes que inician a conexión coa cola nfqueue, e [case] todo o resto vai directo ao oínte FOU.
Para os que non o saben, nfqueue (ou NetfilterQueue) é algo especial para os afeccionados que non saben como desenvolver módulos do núcleo, que usando netfilter (nftables/iptables) permite redirixir os paquetes de rede ao espazo do usuario e procesalos alí usando primitivo significa a man: modificar (opcional) e devolvelo ao núcleo, ou descartalo.
Para algunhas linguaxes de programación hai ligazóns para traballar con nfqueue, para bash non había ningunha (je, non é sorprendente), tiven que usar python: ipipou usa NetfilterQueue.
Se o rendemento non é crítico, usando isto podes inventar de xeito relativamente rápido e sinxelo a túa propia lóxica para traballar con paquetes a un nivel bastante baixo, por exemplo, crear protocolos experimentais de transferencia de datos ou buscar servizos locais e remotos cun comportamento non estándar.
Os sockets en bruto funcionan da man con nfqueue, por exemplo, cando o túnel xa está configurado e FOU está escoitando no porto desexado, non poderás enviar un paquete dende o mesmo porto do xeito habitual: está ocupado, pero pode levar e enviar un paquete xerado aleatoriamente directamente á interface de rede usando un socket en bruto, aínda que xerar un paquete deste tipo requirirá un pouco máis de retoques. Así é como se crean os paquetes con autenticación en ipipou.
Dado que ipipou só procesa os primeiros paquetes da conexión (e os que conseguiron filtrarse na cola antes de establecerse a conexión), o rendemento case non se ve afectado.
Tan pronto como o servidor ipipou recibe un paquete autenticado, créase un túnel e todos os paquetes posteriores da conexión xa son procesados polo núcleo evitando nfqueue. Se a conexión falla, entón o primeiro paquete do seguinte enviarase á cola nfqueue, dependendo da configuración, se non se trata dun paquete con autenticación, senón do último IP e porto cliente lembrado, pódese pasar ou ben. activado ou descartado. Se un paquete autenticado procede dunha IP e un porto novos, o túnel reconfigurarase para usalos.
O IPIP-sobre-FOU habitual ten un problema máis cando se traballa con NAT: é imposible crear dous túneles IPIP encapsulados en UDP coa mesma IP, porque os módulos FOU e IPIP están bastante illados entre si. Eses. un par de clientes detrás da mesma IP pública non poderá conectarse simultaneamente ao mesmo servidor deste xeito. No futuro, quizais, resolverase a nivel do núcleo, pero isto non é certo. Mentres tanto, os problemas de NAT pódense resolver mediante NAT: se ocorre que un par de enderezos IP xa está ocupado por outro túnel, ipipou fará o NAT de IP pública a outra privada alternativa, ¡voíla! - podes crear túneles ata que se esgoten os portos.
Porque Non todos os paquetes da conexión están asinados, entón esta protección sinxela é vulnerable ao MITM, polo que se hai un malo á espreita no camiño entre o cliente e o servidor que pode escoitar o tráfico e manipulalo, pode redirixir os paquetes autenticados. a través doutro enderezo e cree un túnel desde un host non fiable.
Se alguén ten ideas sobre como solucionar isto mentres deixa a maior parte do tráfico no núcleo, non dubide en falar.
Por certo, a encapsulación en UDP demostrouse moi ben. En comparación coa encapsulación sobre IP, é moito máis estable e moitas veces máis rápido a pesar da sobrecarga adicional da cabeceira UDP. Isto débese ao feito de que a maioría dos servidores en Internet só funcionan ben cos tres protocolos máis populares: TCP, UDP e ICMP. A parte tanxible pode descartar completamente todo o demais, ou procesala máis lentamente, porque está optimizada só para estes tres.
Por exemplo, é por iso que QUICK, no que se basea HTTP/3, creouse enriba de UDP, e non de IP.
Ben, palabras suficientes, é hora de ver como funciona no "mundo real".
Batalla
Usado para emular o mundo real iperf3. En canto ao grao de proximidade á realidade, isto é aproximadamente o mesmo que emular o mundo real en Minecraft, pero por agora si.
Participantes no concurso:
canle principal de referencia
o heroe deste artigo é ipipou
OpenVPN con autenticación pero sen cifrado
OpenVPN en modo todo incluído
WireGuard sen PresharedKey, con MTU=1440 (só desde IPv4)
Datos técnicos para frikis As métricas tómanse cos seguintes comandos:
no cliente:
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", чтобы лишние пакеты не плодить и не портить производительность.