¿Qué le decimos a Dios IPv6?

Correcto, y hoy le diremos lo mismo a Dios de la encriptación.
Aquí se hablará de un túnel IPv4 sin cifrar, pero no de un "cálido y acogedor", sino de uno moderno "led". Y también se mencionan sockets crudos, y se trabaja con paquetes en el espacio de usuario.
Hay N protocolos de tunelización para todos los gustos y colores:
- elegantes, modernos, juveniles
- multifuncionales, como cuchillos suizos, OpenVPN y SSH
- el viejo y no maligno GRE
- el IPIP, extremadamente simple, rápido y sin cifrar
- en constante desarrollo
- y muchos otros.
Pero soy programador, por lo que aumentaré N solo un poco, dejando el desarrollo de verdaderos protocolos a los Ъ-desarrolladores.
En un proyecto aún no nacido Al investigar varios protocolos de tunelización, la atención de mi perfeccionista interno se vio atraída una y otra vez por IPIP debido a sus mínimos gastos generales. Sin embargo, tiene un par de desventajas sustanciales para mis tareas:
requiere IP públicas en ambos lados,
- y no hay autenticación en absoluto.
- Por lo tanto, el perfeccionista se sumió de nuevo en la oscura esquina de la caja craneal, o donde quiera que esté.
Y así, un día, leyendo artículos sobre
túneles soportados de forma nativa "¡Esa es la bala de plata! Con el simple IPIP tengo de sobra." - pensé.
En realidad, la bala no era completamente de plata. La encapsulación en UDP resuelve el primer problema: se puede conectar a los clientes detrás de NAT desde el exterior usando una conexión previamente establecida, pero aquí la mitad de la siguiente desventaja de IPIP florece de nuevo — detrás de las IP públicas visibles y el puerto del cliente puede estar cualquiera de la red privada (en IPIP puro no hay este problema).
Para resolver este problema de uno y medio, nació la utilidad
ipipou . Se ha implementado un mecanismo de autenticación de host remoto, sin interrumpir el funcionamiento del núcleo FOU, que procesará los paquetes de manera ágil y eficiente en el espacio del núcleo.
¡No necesitas tu script!
Bien, si conoces el puerto y la IP pública del cliente (por ejemplo, si no hay acceso aleatorio, NAT intenta mapear puertos 1 a 1), puedes crear un túnel IPIP-over-FOU con los siguientes comandos, sin necesidad de scripts.
en el 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
en el 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
# Las opciones local, peer, peer_port, dev pueden no ser soportadas por núcleos antiguos, se pueden omitir.
# peer y peer_port se utilizan para establecer la conexión inmediatamente al crear el listener FOU.
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
donde
ipipou*— nombre de la interfaz de red del túnel local203.0.113.1— IP pública del servidor198.51.100.2— IP pública del cliente192.168.0.2— IP del cliente asignada a la interfaz eth010001— puerto local del cliente para FOU20001— puerto público del cliente para FOU10000— puerto público del servidor para FOUencap-csum— opción para agregar un checksum UDP a los paquetes UDP encapsulados; se puede reemplazar pornoencap-csum, para no calcular, la integridad se controla a través de la capa externa de encapsulación (mientras el paquete esté dentro del túnel)eth0— interfaz local a la que se vinculará el túnel ipip172.28.0.1— IP de la interfaz del túnel del cliente (privada)172.28.0.0— IP de la interfaz del túnel del servidor (privada)
Mientras la conexión UDP esté activa, el túnel seguirá en funcionamiento, pero si se rompe, la suerte dictará; si la IP: puerto del cliente permanece igual, seguirá funcionando, si cambian—se romperá.
Es más fácil revertir todo descargando los módulos del núcleo: modprobe -r fou ipip
Incluso si no se requiere autenticación, las IP públicas y el puerto del cliente no siempre son conocidos y a menudo son impredecibles o cambiantes (dependiendo del tipo de NAT). Si se omite encap-dport del lado del servidor, el túnel no funcionará, no es lo suficientemente inteligente como para deducir el puerto remoto de la conexión. En este caso, ipipou también podría ayudar, o WireGuard y similares te serán útiles.
¿Cómo funciona?
El cliente (que generalmente está detrás de un NAT) establece un túnel (como en el ejemplo anterior) y envía un paquete de autenticación al servidor para que este configure el túnel desde su lado. Dependiendo de la configuración, esto puede ser un paquete vacío (simplemente para que el servidor vea la IP pública: puerto de la conexión), o con datos que permitan al servidor identificar al cliente. Los datos pueden ser una frase de contraseña simple en texto claro (me viene a la mente la analogía con HTTP Basic Auth) o datos firmados con una clave privada, especialmente formateados (similar a HTTP Digest Auth pero más fuerte, ver la función client_auth en el código).
En el servidor (el lado con IP pública), al iniciar ipipou se crea un manejador de cola nfqueue y se configura netfilter de tal manera que los paquetes necesarios se dirijan donde corresponde: los paquetes que inicializan la conexión a la cola nfqueue, y [casi] todos los demás directamente al listener FOU.
Para aquellos que no están familiarizados, nfqueue (o NetfilterQueue) es una herramienta especial para aficionados, que no saben desarrollar módulos del kernel, que mediante netfilter (nftables/iptables) permite redirigir paquetes de red al espacio de usuario y procesarlos allí con métodos sencillos: modificarlos (opcionalmente) y devolverlos al núcleo, o descartarlos.
Para algunos lenguajes de programación, existen enlaces para trabajar con nfqueue; para bash no encontré (jeje, no sorprende), tuve que usar python: ipipou utiliza .
Si el rendimiento no es crítico, con esta herramienta se puede crear de manera relativamente rápida y sencilla una lógica propia para trabajar con paquetes a un nivel bastante bajo, por ejemplo, desarrollar protocolos experimentales de transmisión de datos o molestar servicios locales y remotos con comportamientos no estándar.
Los sockets crudos (raw sockets) funcionan junto con nfqueue; por ejemplo, cuando el túnel ya está configurado y FOU escucha en el puerto requerido, no se puede enviar un paquete de forma ordinaria desde ese mismo puerto — está ocupado, pero se puede generar y enviar un paquete aleatorio directamente a la interfaz de red usando un socket crudo, aunque se necesitará un poco más de trabajo en la generación de dicho paquete. Así es como se crean en ipipou los paquetes de autenticación.
Dado que ipipou solo procesa los primeros paquetes de la conexión (y aquellos que lograron filtrarse en la cola antes de establecer la conexión), el rendimiento casi no se ve afectado.
Tan pronto como el servidor ipipou recibe un paquete que ha pasado la autenticación, se crea un túnel y todos los paquetes subsecuentes en la conexión son procesados por el núcleo, evitando nfqueue. Si la conexión ha caducado, el primer paquete siguiente será dirigido a la cola nfqueue, dependiendo de la configuración; si no es un paquete de autenticación, sino del último IP y puerto registrados del cliente, puede ser pasado más adelante o descartado. Si un paquete autenticado llega desde un nuevo IP y puerto, el túnel se reconfigura para su uso.
IPIP sobre FOU tiene otro problema al trabajar con NAT: no se puede crear dos túneles IPIP encapsulados en UDP con las mismas IP, ya que los módulos FOU e IPIP están suficientemente aislados entre sí. Es decir, un par de clientes detrás de una misma IP pública no podrán conectarse simultáneamente a un mismo servidor de esta manera. En el futuro, , se resolverá a nivel del núcleo, aunque no es seguro. Mientras tanto, los problemas de NAT se pueden resolver con NAT: si resulta que un par de direcciones IP ya están ocupadas por otro túnel, ipipou hará NAT desde la IP pública a una IP privada alternativa, ¡voilà! — Se pueden crear túneles hasta que se agoten los puertos.
Dado que no todos los paquetes en la conexión están firmados, esta sencilla protección es vulnerable a MITM, así que si hay un villano entre el cliente y el servidor que puede escuchar y manejar el tráfico, puede redirigir los paquetes de autenticación a través de otra dirección y crear un túnel desde un host no confiable.
Si alguien tiene ideas sobre cómo solucionar esto manteniendo la mayor parte del tráfico en el núcleo, no dude en expresarse.
Cabe mencionar que la encapsulación en UDP ha demostrado ser muy eficaz. En comparación con la encapsulación sobre IP, es mucho más estable y a menudo más rápida a pesar de los costos adicionales del encabezado UDP. Esto se debe a que en Internet, la mayoría de los hosts funcionan razonablemente solo con los tres protocolos más populares: TCP, UDP e ICMP. Una parte significativa puede incluso descartar todo lo demás o procesarlo más lentamente, ya que está optimizada solo para esos tres.
Por ejemplo, por eso QUICK, sobre el cual se creó HTTP/3, se desarrolló sobre UDP y no sobre IP.
Bueno, basta de palabras, es hora de ver cómo funciona en el «mundo real».
Batalla
Para simular el mundo real se utiliza iperf3. En cuanto a la cercanía a la realidad, es aproximadamente como simular el mundo real en Minecraft, pero por ahora está bien.
En la competencia participan:
- el canal base de referencia
- el héroe de este artículo ipipou
- OpenVPN con autenticación, pero sin cifrado
- OpenVPN en modo «todo incluido»
- WireGuard sin PresharedKey, con MTU=1440 (debido a que es solo IPv4)
Datos técnicos para los geeks
Las métricas se obtienen con estos comandos
en el 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"
# Donde "-b 12M" es el ancho de banda del canal base, dividido por el número de hilos "-P", para no generar paquetes innecesarios y no afectar el rendimiento.
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"
latencia ICMP
ping -c 10 SERVER_IP | tail -1
en el servidor (se ejecuta a la vez que el cliente):
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"
Configuración de túneles
ipipou
servidor
/etc/ipipou/server.conf:
servidor
número 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
cliente
/etc/ipipou/client.conf:
cliente
número 0
fou-local @eth0
fou-remote SERVER_IP:10000
tunl-ip 172.28.0.1
# clave pública de auth-key-b64: eQYNhD/Xwl6Zaq+z3QXDzNI77x8CEKqY1n5kt9bKeEI=
auth-key-b64 RuBZkT23na2Q4QH1xfmZCfRgSgPt5s362UPAFbecTso=
auth-secret topsecret
keepalive 27
verb 3
systemctl start ipipou@client
openvpn (sin cifrado, con autenticación)
servidor
openvpn --genkey --secret ovpn.key # Luego hay que enviar ovpn.key al cliente
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
cliente
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 (con cifrado, autenticación, a través de UDP, todo como se debe)
Configurado usando
wireguard
servidor
/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
cliente
/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
Resultados
Una tabla cruda y fea
La carga del CPU del servidor no es un buen indicador, ya que hay muchos otros servicios activos que a veces consumen recursos:
proto ancho de banda[Mbps] CPU_idle_client[%] CPU_idle_server[%]
# Canal de 20 Mbps desde un microcomputador (4 núcleos) hasta VPS (1 núcleo) a través del Atlántico
# puro
UDP 20.4 99.80 93.34
TCP 19.2 99.67 96.68
Latencia ICMP min/prom/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
Latencia ICMP min/prom/max/mdev = 199.562/208.919/220.222/7.905 ms
# openvpn0 (solo autenticación, sin cifrado)
UDP 19.3 99.89 72.90
TCP 16.1 95.95 88.46
Latencia ICMP min/prom/max/mdev = 191.631/193.538/198.724/2.520 ms
# openvpn (cifrado completo, autenticación, etc)
UDP 19.6 99.75 72.35
TCP 17.0 94.47 87.99
Latencia ICMP min/prom/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
Latencia ICMP min/prom/max/mdev = 217.925/223.601/230.696/3.266 ms
## Canal de aproximadamente 1 Gbps entre VPS de Europa y EE. UU. (1 núcleo)
# puro
UDP 729 73.40 39.93
TCP 363 96.95 90.40
Latencia ICMP min/prom/max/mdev = 106.867/106.994/107.126/0.066 ms
# ipipou
UDP 714 63.10 23.53
TCP 431 95.65 64.56
Latencia ICMP min/prom/max/mdev = 107.444/107.523/107.648/0.058 ms
# openvpn0 (solo autenticación, sin cifrado)
UDP 193 17.51 1.62
TCP 12 95.45 92.80
Latencia ICMP min/prom/max/mdev = 107.191/107.334/107.559/0.116 ms
# wireguard
UDP 629 22.26 2.62
TCP 198 77.40 55.98
Latencia ICMP min/prom/max/mdev = 107.616/107.788/108.038/0.128 ms
canal de 20 Mbps


canal de 1 Gbps optimista


En todos los casos, ipipou se acerca bastante a los indicadores del canal base, ¡y eso es genial!
El túnel de openvpn sin cifrado se comportó de manera bastante extraña en ambos casos.
Si alguien está por probarlo, sería interesante escuchar comentarios.
¡Que IPv6 y NetPrickle estén con nosotros!
Fuente: habr.com
