Migración de OpenVPN a WireGuard para combinar redes en una red L2

Migración de OpenVPN a WireGuard para combinar redes en una red L2

Quisiera compartir mi experiencia sobre cómo unir redes en tres apartamentos geográficamente separados, cada uno de los cuales utiliza routers con OpenWRT como puerta de enlace, en una única red. Al elegir un método para conectar las redes entre L3 con enrutamiento de subredes y L2 con bridging, donde todos los nodos de la red estarían en una sola subred, se prefirió el segundo método, que es más complejo de configurar pero ofrece mayores posibilidades, ya que en la red creada se planeaba el uso transparente de las tecnologías Wake-on-Lan y DLNA.

Parte 1: Antecedentes

Como protocolo para implementar esta tarea, se eligió inicialmente OpenVPN, ya que, en primer lugar, puede crear un dispositivo tap, que se agrega sin problemas al puente, y, en segundo lugar, OpenVPN admite el funcionamiento a través del protocolo TCP, lo cual también era importante, ya que en ninguno de los apartamentos había una dirección IP dedicada y no pude usar STUN porque, por alguna razón, mi proveedor bloquea las conexiones entrantes por UDP desde sus redes, mientras que el protocolo TCP me permitía redirigir el puerto del servidor VPN en un VPS alquilado a través de SSH. Sí, este enfoque genera una mayor carga, ya que los datos se cifran dos veces, pero no quise incluir el VPS en mi red privada, ya que existía el riesgo de que terceros obtuvieran control sobre él; por lo tanto, tener dicho dispositivo en la red doméstica era extremadamente indeseable y decidí pagar por la seguridad con una mayor carga.

Para redirigir el puerto en el router donde se planeaba desplegar el servidor, se utilizó el programa sshtunnel. No entraré en los detalles de su configuración, ya que es bastante fácil, simplemente señalaré que su tarea era redirigir el puerto TCP 1194 del router al VPS. Luego se configuró el servidor OpenVPN en el dispositivo tap0, que se conectó al puente br-lan. Después de verificar la conexión al recién creado servidor desde mi portátil, quedó claro que la idea de redirigir el puerto había funcionado y mi portátil se convirtió en miembro de la red del router, aunque físicamente no estuviera en ella.

Lo único que quedaba por hacer era asignar direcciones IP en los diferentes apartamentos de tal manera que no hubiera conflictos y configurar los routers como clientes de OpenVPN.
Se eligieron las siguientes direcciones IP para los routers y rangos de servidores DHCP:

  • 192.168.10.1 con el rango 192.168.10.2 — 192.168.10.80 para el servidor
  • 192.168.10.100 con el rango 192.168.10.101 — 192.168.10.149 para el enrutador en el apartamento №2
  • 192.168.10.150 con el rango 192.168.10.151 — 192.168.10.199 para el enrutador en el apartamento №3

También era necesario asignar exactamente estas direcciones para los enrutadores cliente del servidor OpenVPN, mediante la adición de la siguiente línea en su configuración:

ifconfig-pool-persist /etc/openvpn/ipp.txt 0

y añadiendo las siguientes líneas en el archivo /etc/openvpn/ipp.txt:

flat1_id 192.168.10.100
flat2_id 192.168.10.150

donde flat1_id y flat2_id son los nombres de los dispositivos indicados al crear certificados para conectarse a OpenVPN

Luego, se configuraron los clientes OpenVPN en los enrutadores, los dispositivos tap0 en ambos fueron añadidos al puente br-lan. En esta etapa parecía que todo estaba en orden, ya que las tres redes se veían entre sí y funcionaban como una sola. Sin embargo, surgió un detalle no muy agradable: a veces los dispositivos podían recibir una dirección IP que no correspondía a su enrutador, con todas las consecuencias que eso conlleva. Por alguna razón, el enrutador en uno de los apartamentos no respondía a tiempo a DHCPDISCOVER y el dispositivo recibía una dirección incorrecta. Comprendí que necesitaba filtrar tales solicitudes en tap0 en cada uno de los enrutadores, pero, como descubrí, iptables no puede trabajar con un dispositivo si forma parte de un puente, y me debía ayudar ebtables. Lamentablemente, en mis firmware no estaba disponible y tuve que recompilar las imágenes para cada dispositivo. Haciendo esto y añadiendo estas líneas en /etc/rc.local de cada enrutador, se resolvió el problema:

ebtables -A INPUT --in-interface tap0 --protocol ipv4 --ip-protocol udp --ip-destination-port 67:68 -j DROP
ebtables -A INPUT --in-interface tap0 --protocol ipv4 --ip-protocol udp --ip-source-port 67:68 -j DROP
ebtables -A FORWARD --out-interface tap0 --protocol ipv4 --ip-protocol udp --ip-destination-port 67:68 -j DROP
ebtables -A FORWARD --out-interface tap0 --protocol ipv4 --ip-protocol udp --ip-source-port 67:68 -j DROP

Esta configuración se mantuvo durante tres años.

Parte 2: Introducción a WireGuard

Últimamente, se ha hablado cada vez más de WireGuard en Internet, admirando la simplicidad de su configuración, la alta velocidad de transferencia y el bajo ping con una seguridad comparable. La búsqueda de información adicional sobre él dejó claro que ni su funcionamiento como parte de un puente, ni su funcionamiento bajo el protocolo TCP son soportados, lo que me llevó a pensar que todavía no tengo alternativas a OpenVPN. Así fui posponiendo mi encuentro con WireGuard.

Hace unos días, en recursos relacionados con IT, circuló la noticia de que WireGuard finalmente se incluiría en el núcleo de Linux, comenzando con la versión 5.6. Los artículos de noticias, como siempre, elogiaban a WireGuard. Nuevamente me sumergí en la búsqueda de alternativas al viejo y querido OpenVPN. Esta vez me encontré con este artículo. Se mencionaba la creación de un túnel Ethernet sobre L3 utilizando GRE. Este artículo me llenó de esperanza. Quedaba sin esclarecer qué hacer con el protocolo UDP. La búsqueda me llevó a artículos sobre el uso de socat junto con un túnel SSH para redirigir un puerto UDP, sin embargo, se señalaba que este enfoque solo funciona en modo de conexión única, es decir, el funcionamiento de varios clientes VPN se volvería imposible. Se me ocurrió la idea de levantar un servidor VPN en un VPS y para los clientes configurar GRE, pero, como resultó, GRE no soporta cifrado, lo que llevaría a que, en caso de que terceros accedieran al servidor, tendrían en sus manos todo el tráfico entre mis redes, cosa que me incomodaba en principio.

De nuevo se tomó la decisión a favor de un cifrado redundante, utilizando VPN sobre VPN de la siguiente manera:

VPN de primer nivel:
VPS es el servidor con la dirección interna 192.168.30.1
MC es cliente VPS con dirección interna 192.168.30.2
MC2 es cliente VPS con dirección interna 192.168.30.3
MC3 es cliente VPS con dirección interna 192.168.30.4

VPN de segundo nivel:
MC es el servidor con la dirección externa 192.168.30.2 y la interna 192.168.31.1
MC2 es cliente MC con la dirección 192.168.30.2 y tiene IP interna 192.168.31.2
MC3 es cliente MC con la dirección 192.168.30.2 y tiene IP interna 192.168.31.3

* MC — router-servidor en el apartamento 1, MC2 — router en el apartamento 2, MC3 — router en el apartamento 3
* Las configuraciones de los dispositivos se publican en el spoiler al final del artículo.

Así que, los pings entre los nodos de la red 192.168.31.0/24 funcionan, es hora de pasar a la configuración del túnel GRE. Antes de esto, para no perder acceso a los routers, conviene configurar túneles SSH para redirigir el puerto 22 en el VPS, de tal manera que, por ejemplo, en el puerto 10022, el VPS tenga acceso al router del apartamento 2, y en el puerto 11122 el VPS tenga acceso al router del apartamento 3. La configuración de la redirección es mejor realizarla con sshtunnel, ya que restablecerá el túnel en caso de caída.

Túnel configurado, se puede conectar a SSH a través del puerto redirigido:

ssh root@MI_VPS -p 10022

A continuación, deberías desconectar OpenVPN:

/etc/init.d/openvpn stop

Ahora configuraremos el túnel GRE en el router del apartamento 2:

ip link add grelan0 type gretap remote 192.168.31.1 local 192.168.31.2
ip link set grelan0 up

Y añadimos la interfaz creada al puente:

brctl addif br-lan grelan0

Realizaremos el mismo procedimiento en el enrutador servidor:

ip link add grelan0 type gretap remote 192.168.31.2 local 192.168.31.1
ip link set grelan0 up

Y, además, añadiremos la interfaz creada al puente:

brctl addif br-lan grelan0

A partir de este momento, los pings comienzan a funcionar correctamente en la nueva red y, con satisfacción, me voy a tomar un café. Luego, para evaluar cómo funciona la red al otro lado del cable, intento conectarme por SSH a uno de los ordenadores en el apartamento 2, pero el cliente SSH 'se cuelga', sin ofrecerme introducir la contraseña. Intento conectarme a este ordenador por telnet en el puerto 22 y veo una línea que indica que se está estableciendo la conexión, el servidor SSH responde, pero por alguna razón no me permite entrar.

$ telnet 192.168.10.110 22
SSH-2.0-OpenSSH_8.1

Intento conectarme a él también por VNC y veo una pantalla negra. Me convenzo de que el problema está en el ordenador remoto, ya que puedo conectarme sin problemas al enrutador desde este apartamento usando la dirección interna. Sin embargo, decido conectarme por SSH a este ordenador a través del enrutador y, para mi sorpresa, descubro que la conexión es exitosa y el ordenador remoto está funcionando correctamente, pero tampoco puede conectarse a mi ordenador.

Desconecto el dispositivo grelan0 del puente y ejecuto OpenVPN en el enrutador del apartamento 2, asegurándome de que la red funcione nuevamente como se espera y que las conexiones no se interrumpan. Encuentro foros donde la gente se queja de problemas similares, donde les aconsejan aumentar la MTU. Dicho y hecho. Sin embargo, mientras la MTU no sea lo suficientemente grande — 7000 para los dispositivos gretap — se podrían observar interrupciones en las conexiones TCP o baja velocidad de transferencia. Debido a la alta MTU para gretap, la MTU para las conexiones WireGuard de primer y segundo nivel se establecieron en 8000 y 7500 respectivamente.

Realicé una configuración similar en el enrutador del apartamento 3, con la única diferencia de que en el enrutador servidor se agregó una segunda interfaz gretap llamada grelan1, que también fue añadida al puente br-lan.

Todo funciona. Ahora se puede colocar la configuración gretap en el inicio automático. Para ello:

Coloqué estas líneas en /etc/rc.local en el enrutador del apartamento 2:

ip link add grelan0 type gretap remote 192.168.31.1 local 192.168.31.2
ip link set dev grelan0 mtu 7000
ip link set grelan0 up
brctl addif br-lan grelan0

Agregué esto en /etc/rc.local en el enrutador del apartamento 3:

ip link add grelan0 type gretap remote 192.168.31.1 local 192.168.31.3
ip link set dev grelan0 mtu 7000
ip link set grelan0 up
brctl addif br-lan grelan0

Y en el enrutador servidor:

ip link add grelan0 type gretap remote 192.168.31.2 local 192.168.31.1
ip link set dev grelan0 mtu 7000
ip link set grelan0 up
brctl addif br-lan grelan0

ip link add grelan1 type gretap remote 192.168.31.3 local 192.168.31.1
ip link set dev grelan1 mtu 7000
ip link set grelan1 up
brctl addif br-lan grelan1

Después de reiniciar los enrutadores de los clientes, descubrí que no se conectaban al servidor por alguna razón. Al conectarme a su SSH (afortunadamente, había configurado el sshtunnel para esto), se descubrió que WireGuard estaba creando una ruta para el endpoint, pero incorrecta. Así, para 192.168.30.2, la tabla de rutas mostraba una ruta a través de la interfaz pppoe-wan, es decir, a través de Internet, aunque la ruta hacia él debería ser a través de la interfaz wg0. Después de eliminar esta ruta, la conexión se restableció. No pude encontrar instrucciones sobre cómo hacer que WireGuard no creara estas rutas. Además, no entendí si esta es una particularidad de OpenWRT o de WireGuard en sí. Sin querer gastar mucho tiempo resolviendo este problema, simplemente añadí en ambos enrutadores un script, en un bucle con un temporizador, que eliminaba esta ruta:

route del 192.168.30.2

Resumiendo

Aún no he logrado descartar completamente OpenVPN, ya que a veces necesito conectarme a una nueva red desde mi portátil o teléfono, y la configuración de un dispositivo gretap en ellos en general es imposible, pero, a pesar de eso, he obtenido una ventaja en la velocidad de transferencia de datos entre los apartamentos y, por ejemplo, el uso de VNC ahora no causa inconvenientes. El ping ha disminuido ligeramente, pero se ha vuelto más estable:

Al usar OpenVPN:

[r0ck3r@desktop ~]$ ping -c 20 192.168.10.110
PING 192.168.10.110 (192.168.10.110) 56(84) bytes of data.
64 bytes from 192.168.10.110: icmp_seq=1 ttl=64 time=133 ms
...
64 bytes from 192.168.10.110: icmp_seq=20 ttl=64 time=125 ms

--- 192.168.10.110 ping statistics ---
20 packets transmitted, 20 received, 0% packet loss, time 19006ms
rtt min/avg/max/mdev = 124.722/126.152/136.907/3.065 ms

Al usar WireGuard:

[r0ck3r@desktop ~]$ ping -c 20 192.168.10.110
PING 192.168.10.110 (192.168.10.110) 56(84) bytes of data.
64 bytes from 192.168.10.110: icmp_seq=1 ttl=64 time=124 ms
...
64 bytes from 192.168.10.110: icmp_seq=20 ttl=64 time=124 ms
--- 192.168.10.110 ping statistics ---
20 packets transmitted, 20 received, 0% packet loss, time 19003ms
rtt min/avg/max/mdev = 123.954/124.423/126.708/0.675 ms

Esto se ve más afectado por el ping alto hacia el VPS, que es de aproximadamente 61.5 ms

Sin embargo, la velocidad ha aumentado significativamente. Así, en un apartamento con un enrutador servidor tengo una velocidad de conexión a Internet de 30 Mbps, mientras que en los demás apartamentos son 5 Mbps. A pesar de esto, durante el uso de OpenVPN no pude alcanzar una velocidad de transferencia de datos entre redes mayor a 3,8 Mbps según las mediciones de iperf, mientras que WireGuard la 'aumentó' a esos mismos 5 Mbps.

Configuración de WireGuard en VPS[Interface]
Dirección = 192.168.30.1/24
PuertoDeEscucha = 51820
ClavePrivada =

[Peer]
PublicKey =
AllowedIPs = 192.168.30.2/32

[Peer]
PublicKey =
AllowedIPs = 192.168.30.3/32

[Peer]
PublicKey =
AllowedIPs = 192.168.30.4/32

Configuración de WireGuard en MS (se agrega en /etc/config/network)

#VPN первого уровня - клиент
config interface 'wg0'
        option proto 'wireguard'
        list addresses '192.168.30.2/24'
        option private_key 'ЗАКРЫТЫЙ_КЛЮЧ_VPN_1_МС'
        option auto '1'
        option mtu '8000'

config wireguard_wg0
        option public_key 'ОТКРЫТЫЙ_КЛЮЧ_VPN_1_VPS'
        option endpoint_port '51820'
        option route_allowed_ips '1'
        option persistent_keepalive '25'
        list allowed_ips '192.168.30.0/24'
        option endpoint_host 'IP_АДРЕС_VPS'

#VPN второго уровня - сервер
config interface 'wg1'
        option proto 'wireguard'
        option private_key 'ЗАКРЫТЫЙ_КЛЮЧ_VPN_2_МС'
        option listen_port '51821'
        list addresses '192.168.31.1/24'
        option auto '1'
        option mtu '7500'

config wireguard_wg1
        option public_key 'ОТКРЫТЫЙ_КЛЮЧ_VPN_2_МК2'
        list allowed_ips '192.168.31.2'

config wireguard_wg1ip link add grelan0 type gretap remote 192.168.31.1 local 192.168.31.3

        option public_key 'ОТКРЫТЫЙ_КЛЮЧ_VPN_2_МК3'
        list allowed_ips '192.168.31.3'

Configuración de WireGuard en MK2 (se agrega en /etc/config/network)

#VPN первого уровня - клиент
config interface 'wg0'
        option proto 'wireguard'
        list addresses '192.168.30.3/24'
        option private_key 'ЗАКРЫТЫЙ_КЛЮЧ_VPN_1_МК2'
        option auto '1'
        option mtu '8000'

config wireguard_wg0
        option public_key 'ОТКРЫТЫЙ_КЛЮЧ_VPN_1_VPS'
        option endpoint_port '51820'
        option persistent_keepalive '25'
        list allowed_ips '192.168.30.0/24'
        option endpoint_host 'IP_АДРЕС_VPS'

#VPN второго уровня - клиент
config interface 'wg1'
        option proto 'wireguard'
        option private_key 'ЗАКРЫТЫЙ_КЛЮЧ_VPN_2_МК2'
        list addresses '192.168.31.2/24'
        option auto '1'
        option listen_port '51821'
        option mtu '7500'

config wireguard_wg1
        option public_key 'ОТКРЫТЫЙ_КЛЮЧ_VPN_2_МС'
        option endpoint_host '192.168.30.2'
        option endpoint_port '51821'
        option persistent_keepalive '25'
        list allowed_ips '192.168.31.0/24'

Configuración de WireGuard en MK3 (se agrega en /etc/config/network)

#VPN первого уровня - клиент
config interface 'wg0'
        option proto 'wireguard'
        list addresses '192.168.30.4/24'
        option private_key 'ЗАКРЫТЫЙ_КЛЮЧ_VPN_1_МК3'
        option auto '1'
        option mtu '8000'

config wireguard_wg0
        option public_key 'ОТКРЫТЫЙ_КЛЮЧ_VPN_1_VPS'
        option endpoint_port '51820'
        option persistent_keepalive '25'
        list allowed_ips '192.168.30.0/24'
        option endpoint_host 'IP_АДРЕС_VPS'

#VPN второго уровня - клиент
config interface 'wg1'
        option proto 'wireguard'
        option private_key 'ЗАКРЫТЫЙ_КЛЮЧ_VPN_2_МК3'
        list addresses '192.168.31.3/24'
        option auto '1'
        option listen_port '51821'
        option mtu '7500'

config wireguard_wg1
        option public_key 'ОТКРЫТЫЙ_КЛЮЧ_VPN_2_МС'
        option endpoint_host '192.168.30.2'
        option endpoint_port '51821'
        option persistent_keepalive '25'
        list allowed_ips '192.168.31.0/24'

En las configuraciones descritas para VPN de segundo nivel, indico a los clientes de WireGuard el puerto 51821. En teoría, esto no es necesario, ya que el cliente establecerá la conexión desde cualquier puerto no privilegiado libre, pero lo hice para poder prohibir todas las conexiones entrantes en las interfaces wg0 de todos los enrutadores, excepto las conexiones UDP entrantes en el puerto 51821.

Espero que el artículo sea útil para alguien.

P.D. Además, quiero compartir mi script que me envía una notificación PUSH a mi teléfono en la aplicación WirePusher cuando un nuevo dispositivo aparece en mi red. Aquí está el enlace al script: github.com/r0ck3r/device_discover.

ACTUALIZACIÓN: Configuración de servidor y clientes OpenVPN

Servidor OpenVPN

client-to-client

ca /etc/openvpn/server/ca.crt
cert /etc/openvpn/server/vpn-server.crt
dh /etc/openvpn/server/dh.pem
key /etc/openvpn/server/vpn-server.key

dev tap
ifconfig-pool-persist /etc/openvpn/ipp.txt 0
keepalive 10 60
proto tcp4
server-bridge 192.168.10.1 255.255.255.0 192.168.10.80 192.168.10.254
status /var/log/openvpn-status.log
verb 3
comp-lzo

Cliente OpenVPN

client
tls-client
dev tap
proto tcp
remote VPS_IP 1194 # Cambia a la IP externa de tu enrutador
resolv-retry infinite
nobind

ca client/ca.crt
cert client/client.crt
key client/client.key
dh client/dh.pem

comp-lzo
persist-tun
persist-key
verb 3

Para la generación de certificados utilicé easy-rsa

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster