ipipou: más que un túnel sin cifrar

¿Qué le decimos al dios IPv6?



IPv6?  Hoy no


Es cierto, y al dios de la encriptación, le diremos lo mismo hoy.



Aquí se tratará de un túnel IPv4 sin cifrar, pero no de una "lámpara cálida", sino de una moderna "LED". Y luego parpadean los sockets sin procesar, y hay trabajo con paquetes en el espacio de usuario.



Existen N protocolos de tunelización para todos los gustos y colores:



  • WireGuard elegante, moderno y juvenil
  • multifuncional como cuchillos suizos, OpenVPN y SSH
  • viejo y no malvado GRE
  • el IPIP más simple, inteligente y no encriptado en absoluto
  • desarrollando activamente GENEVE
  • muchos otros.


Pero soy un programador, por lo que aumentaré N solo en una fracción y dejaré el desarrollo de protocolos reales a los desarrolladores b.



En otro proyecto por nacer , en el que estoy involucrado actualmente, necesito llegar a los hosts detrás de NAT desde el exterior. Usando protocolos con criptografía de adultos para esto, nunca dejé la sensación de que era como una bala de cañón. Porque el túnel se usa en su mayor parte solo para hacer un agujero en NAT-e, el tráfico interno generalmente también está encriptado, sin embargo, están ahogados por HTTPS.



Mientras investigaba varios protocolos de tunelización, la atención de mi perfeccionista interior se centró en IPIP una y otra vez debido a su mínima sobrecarga. Pero tiene un inconveniente y medio significativo para mis tareas:



  • requiere IP públicas en ambos lados,
  • y sin autenticación para ti.


Por lo tanto, el perfeccionista fue devuelto a la esquina oscura del cráneo, o donde sea que se siente allí.



Y una vez, mientras leía artículos sobre túneles compatibles de forma nativa en Linux, me encontré con FOU (Foo-over-UDP), es decir, lo que sea, envuelto en UDP. Hasta ahora, solo IPIP y GUE (encapsulación UDP genérica) son compatibles con cualquier otra cosa.



“¡Aquí hay una bala de plata! Yo y un simple IPIP para los ojos ". Pensé.



De hecho, la bala no fue del todo plateada. La encapsulación en UDP resuelve el primer problema: puede conectarse a clientes detrás de NAT desde el exterior utilizando una conexión preestablecida, pero aquí la mitad de la siguiente desventaja de IPIP florece bajo una nueva luz: cualquier persona de la red privada puede ocultarse detrás de la IP pública visible y el puerto del cliente (en IPIP puro no hay ningún problema).



Para resolver este problema de uno y medio, nació la utilidad ipipou . Implementa un mecanismo de fabricación propia para autenticar un host remoto, sin interrumpir el funcionamiento de una FOU vigorosa, que procesará paquetes de manera rápida y eficiente en el espacio del kernel.



¡No necesito tu guión!



Bien, si conoce el puerto público y la IP del cliente (por ejemplo, todos los suyos, donde sea que vayan, NAT intenta asignar los puertos 1 a 1), puede crear un túnel IPIP sobre FOU con los siguientes comandos, sin ningún script.



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

#  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


Dónde

  • ipipou* - el nombre de la interfaz de red del túnel local
  • 203.0.113.1 - IP pública del servidor
  • 198.51.100.2 - IP pública del cliente
  • 192.168.0.2 - IP de cliente asignada a la interfaz eth0
  • 10001 - puerto de cliente local para FOU
  • 20001 - puerto de cliente público para FOU
  • 10000 - puerto de servidor público para FOU
  • encap-csum — UDP UDP ; noencap-csum, , ( )
  • eth0 — ipip
  • 172.28.0.1 — IP ()
  • 172.28.0.0 — IP ()


Mientras la conexión UDP esté viva, el túnel estará en un estado de funcionamiento, y cómo se rompe, qué suerte - si el puerto IP: del cliente sigue siendo el mismo - vivirá, cambiará - se romperá.



La forma más fácil de cambiar las cosas es descargando los módulos del kernel: modprobe -r fou ipip



incluso si no se requiere autenticación, la IP pública y el puerto del cliente no siempre se conocen y, a menudo, son impredecibles o modificables (según el tipo de NAT). Si lo omite encap-dporten el lado del servidor, el túnel no funcionará, no es lo suficientemente inteligente como para tomar el puerto de conexión remota. En este caso, ipipou también puede ayudar, bueno, o WireGuard y otros como él para ayudarlo.



¿Cómo funciona?



El cliente (que generalmente está detrás de NAT) configura un túnel (como en el ejemplo anterior) y envía un paquete autenticado al servidor para que pueda configurar el túnel desde su lado. Dependiendo de la configuración, puede ser un paquete vacío (solo para que el servidor vea la IP pública: puerto de conexión), o con datos por los cuales el servidor puede identificar al cliente. Los datos pueden ser una simple frase de contraseña de texto plano (me viene a la mente una analogía con HTTP Basic Auth) o datos especialmente formateados firmados con una clave privada (por analogía con HTTP Digest Auth, solo que más fuerte, consulte la función client_authen el código).



En el servidor (del lado de la IP pública), al inicio, ipipou crea un manejador de cola nfqueue y configura netfilter para que los paquetes necesarios se envíen a donde deben ir: los paquetes que inicializan la conexión a la cola nfqueue, y [casi] todo el resto directamente al oyente FOU.



Quien no está en el tema, nfqueue (o NetfilterQueue) es algo tan especial para los aficionados que no saben cómo desarrollar módulos del kernel , que por medio de netfilter (nftables / iptables) le permite redirigir paquetes de red al espacio de usuario y procesarlos allí con medios primitivos improvisados : modificar (opcional ) y devuélvala al grano o deséchela.



Para algunos lenguajes de programación hay enlaces para trabajar con nfqueue, para bash no había (je, no es sorprendente), tuve que usar python: ipipou usa NetfilterQueue .



Si el rendimiento no es crítico, con la ayuda de esto, puede preparar su propia lógica de manera relativamente rápida y sencilla para trabajar con paquetes a un nivel bastante bajo, por ejemplo, esculpir protocolos de transferencia de datos experimentales o controlar servicios locales y remotos con un comportamiento no estándar.



Los sockets sin procesar funcionan de la mano con nfqueue, por ejemplo, cuando el túnel ya está configurado y FOU está escuchando en el puerto deseado, no funcionará de la forma habitual para enviar un paquete desde el mismo puerto; está ocupado, pero puede tomar y ejecutar un paquete generado aleatoriamente directamente en la red. interfaz usando un socket sin formato, aunque generar dicho paquete requerirá un poco más de trabajo. Así es como se crean los paquetes con autenticación en ipipou.



Dado que ipipou procesa solo los primeros paquetes de la conexión (bueno, aquellos que lograron filtrarse en la cola antes de que se estableciera la conexión), el rendimiento apenas se ve afectado.



Tan pronto como el servidor ipipou recibe un paquete autenticado, se crea un túnel y todos los paquetes subsiguientes en la conexión ya son procesados ​​por el kernel sin pasar por nfqueue. Si la conexión es mala, el primer paquete del siguiente se enviará a la cola nfqueue, dependiendo de la configuración, si no es un paquete de autenticación, pero de la última IP y puerto de cliente recordados, se puede pasar o descartar. Si un paquete autenticado proviene de una nueva IP y puerto, el túnel se reconfigura para usarlos.



El IPIP sobre FOU habitual tiene otro problema cuando se trabaja con NAT: no puede crear dos túneles IPIP encapsulados en UDP con la misma IP, porque los módulos FOU e IPIP están bastante aislados entre sí. Aquellos. un par de clientes detrás de la misma IP pública no podrán conectarse simultáneamente al mismo servidor de esta manera. En el futuro, puede que se resuelva a nivel de kernel, pero esto no es seguro. Mientras tanto, los problemas de NAT pueden ser resueltos por NAT - si sucede que un par de direcciones IP ya está ocupado por otro túnel, ipipou hará NAT desde el público a una IP privada alternativa, ¡voilá! - puede crear túneles hasta que se agoten los puertos.



Porque no todos los paquetes en la conexión están firmados, entonces una protección tan simple es vulnerable a MITM, por lo que si un villano acecha entre el cliente y el servidor, que puede escuchar y controlar el tráfico, puede redirigir los paquetes autenticados a través de otra dirección y crear un túnel desde un host que no es de confianza. ...



Si alguien tiene alguna idea sobre cómo solucionar este problema manteniendo la mayor parte del tráfico en el núcleo, no dude en hablar.



Por cierto, la encapsulación UDP ha funcionado muy bien. En comparación con la encapsulación sobre IP, es mucho más estable y a menudo más rápida a pesar de la sobrecarga adicional del encabezado UDP. Esto se debe al hecho de que la mayoría de los hosts en Internet funcionan bastante bien con solo los tres protocolos más populares: TCP, UDP, ICMP. La parte perceptible generalmente puede descartar todo lo demás, o procesar más lentamente, porque está optimizada solo para estos tres.



Por ejemplo, por lo tanto, QUICK, sobre la base de la cual se creó HTTP / 3, se creó sobre UDP, no sobre IP.



Bueno, basta de palabras, es hora de ver cómo funciona en el "mundo real".



Batalla



Se usa para emular el mundo real iperf3. En términos del grado de cercanía a la realidad, esto es aproximadamente lo mismo que emular el mundo real en Minecraft, pero por ahora servirá.



La competencia involucra:

  • canal maestro de referencia
  • el héroe de este artículo es ipipou
  • OpenVPN con autenticación pero sin cifrado
  • OpenVPN todo incluido
  • WireGuard sin PresharedKey, con MTU = 1440 (solo para IPv4)


Datos técnicos para geeks
Los siguientes comandos



del cliente toman las métricas :



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",         .


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


( ):



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"




ipipou



/etc/ipipou/server.conf:

server
number 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





/etc/ipipou/client.conf:

client
number 0
fou-local @eth0
fou-remote SERVER_IP:10000
tunl-ip 172.28.0.1
# pubkey of auth-key-b64: eQYNhD/Xwl6Zaq+z3QXDzNI77x8CEKqY1n5kt9bKeEI=
auth-key-b64 RuBZkT23na2Q4QH1xfmZCfRgSgPt5s362UPAFbecTso=
auth-secret topsecret
keepalive 27
verb 3


systemctl start ipipou@client



openvpn ( , )



openvpn --genkey --secret ovpn.key  #    ovpn.key 
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




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 (c , , UDP, )

openvpn-manage



wireguard



/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





/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



Tableta fea cruda
CPU , .. :



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 para 20 Mbps



comparación de ancho de banda a 20 Mbps



comparación de latencia a 20 Mbps



canal para 1 Gbps optimista



Comparación de ancho de banda de 1 Gbps



Comparación de la eficiencia de la CPU: Mbps / CPU_usage



En todos los casos, ipipou está bastante cerca en términos de rendimiento del canal base, ¡y eso es genial!



El túnel openvpn sin cifrar se comportó de manera bastante extraña en ambos casos.



Si alguien va a probarlo, será interesante escuchar comentarios.



¡Que IPv6 y NetPrickle estén con nosotros!



All Articles