Transição do OpenVPN para o WireGuard para integrar redes em uma rede L2

Transição do OpenVPN para o WireGuard para integrar redes em uma rede L2

Gostaria de compartilhar a experiência de unir redes em três apartamentos geograficamente distantes, cada um usando roteadores com OpenWRT como gateway, em uma única rede. Ao escolher entre a combinação de redes L3 com roteamento de sub-redes e L2 com bridging, onde todos os nós da rede estariam em uma única sub-rede, foi dada preferência ao segundo método, mais complexo de configurar, mas que oferece maiores possibilidades, já que na rede criada estava planejado o uso transparente das tecnologias Wake-on-Lan e DLNA.

Parte 1: Antecedentes

Como protocolo para implementar essa tarefa, inicialmente foi escolhido o OpenVPN, pois, em primeiro lugar, ele pode criar um dispositivo tap, que é facilmente adicionado ao bridge, e, em segundo lugar, o OpenVPN suporta operação via protocolo TCP, o que era igualmente importante, já que nenhum dos apartamentos tinha um endereço IP dedicado, e não consegui usar STUN, pois meu provedor, por algum motivo, bloqueia conexões de entrada via protocolo UDP de suas redes, enquanto o protocolo TCP me permitiu encaminhar a porta do servidor VPN para o VPS alugado via SSH. Sim, essa abordagem aumenta bastante a carga, pois os dados são criptografados duas vezes, mas não quis inserir o VPS na minha rede privada, pois havia o risco de terceiros obterem controle sobre ele, portanto, ter um dispositivo assim na rede doméstica era extremamente indesejável, e decidiu-se pagar pelo segurança com um overhead maior.

Para encaminhar a porta no roteador, onde o servidor estava planejado para ser configurado, foi usado o programa sshtunnel. Não vou descrever os detalhes de sua configuração — é feito de forma bastante simples, apenas vou ressaltar que a tarefa dele era encaminhar a porta TCP 1194 do roteador para o VPS. Em seguida, foi configurado o servidor OpenVPN no dispositivo tap0, que foi adicionado ao bridge br-lan. Após verificar a conexão com o servidor recém-criado a partir de um laptop, ficou claro que a ideia de encaminhar a porta valeu a pena, e meu laptop tornou-se um membro da rede do roteador, embora fisicamente não estivesse nela.

O que restava era o seguinte: era preciso distribuir endereços IP entre os diferentes apartamentos para que não houvesse conflitos e configurar os roteadores como clientes do OpenVPN.
Foram escolhidos os seguintes endereços IP dos roteadores e intervalos dos servidores DHCP:

  • 192.168.10.1 com intervalo 192.168.10.2 — 192.168.10.80 para o servidor
  • 192.168.10.100 com intervalo 192.168.10.101 — 192.168.10.149 para o roteador no apartamento nº 2
  • 192.168.10.150 com intervalo 192.168.10.151 — 192.168.10.199 para o roteador no apartamento nº 3

Também era necessário atribuir exatamente esses endereços aos roteadores-clientes do servidor OpenVPN, adicionando à sua configuração a seguinte linha:

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

e acrescentando as seguintes linhas no arquivo /etc/openvpn/ipp.txt:

flat1_id 192.168.10.100
flat2_id 192.168.10.150

onde flat1_id e flat2_id são os nomes dos dispositivos especificados ao criar os certificados para conexão ao OpenVPN

Em seguida, os clientes OpenVPN foram configurados nos roteadores, com os dispositivos tap0 em ambos incluídos na ponte br-lan. Nessa fase, parecia que tudo estava bem, pois as três redes se viam e funcionavam como um todo. No entanto, surgiu um detalhe desagradável: às vezes, os dispositivos podiam receber um endereço IP não do seu roteador, com todas as consequências disso. Por algum motivo, o roteador em um dos apartamentos não era rápido o suficiente para responder ao DHCPDISCOVER e o dispositivo recebia um endereço que não era o seu. Percebi que precisava filtrar essas solicitações em tap0 em cada um dos roteadores, mas, como se descobriu, o iptables não consegue trabalhar com um dispositivo que faz parte de uma ponte e eu precisaria do ebtables. Para minha tristeza, ele não estava nas minhas ROMs, e eu tive que recompilar as imagens para cada dispositivo. Depois de fazer isso e adicionar essas linhas ao /etc/rc.local de cada roteador, o problema foi resolvido:

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

Essa configuração durou três anos.

Parte 2: Introdução ao WireGuard

Ultimamente, na Internet, tem-se falado cada vez mais sobre o WireGuard, admirando a simplicidade de sua configuração, alta velocidade de transmissão e baixa latência com segurança comparável. A busca por informações adicionais sobre ele deixou claro que tanto o funcionamento como parte de uma ponte quanto o uso do protocolo TCP não são suportados, o que me fez pensar que ainda não havia alternativas ao OpenVPN para mim. Assim, fui adiando meu contato com o WireGuard.

Há alguns dias, circulou uma notícia nos recursos relacionados à TI de que o WireGuard finalmente será incluído no kernel do Linux, a partir da versão 5.6. Os artigos de notícias, como sempre, elogiavam o WireGuard. Novamente, mergulhei na busca por alternativas ao bom e velho OpenVPN. Desta vez, encontrei este artigo. O artigo falava sobre a criação de um túnel Ethernet sobre L3 usando GRE. Esse artigo me encheu de esperança. Permanecia incerto o que fazer com o protocolo UDP. A pesquisa me levou a artigos sobre o uso do socat em conjunto com um túnel SSH, para encaminhar a porta UDP, no entanto, foi mencionado que essa abordagem só funciona em modo de uma única conexão, ou seja, o funcionamento de múltiplos clientes VPN seria impossível. Tive a ideia de levantar um servidor VPN em um VPS e configurar o GRE para os clientes, mas, como se mostrou, o GRE não suporta criptografia, o que levaria a que, caso terceiros obtivessem acesso ao servidor, todo o tráfego entre minhas redes ficaria em suas mãos, o que de forma alguma era aceitável para mim.

Mais uma vez, foi tomada a decisão a favor da criptografia redundante, utilizando VPN sobre VPN da seguinte maneira:

VPN de primeiro nível:
VPS é servidor com endereço interno 192.168.30.1
MC é cliente VPS com endereço interno 192.168.30.2
MC2 é cliente VPS com endereço interno 192.168.30.3
MC3 é cliente VPS com endereço interno 192.168.30.4

VPN de segundo nível:
MC é servidor com endereço externo 192.168.30.2 e interno 192.168.31.1
MC2 é cliente MC com endereço 192.168.30.2 e IP interno 192.168.31.2
MC3 é cliente MC com endereço 192.168.30.2 e IP interno 192.168.31.3

* MC — roteador-servidor no apartamento 1, MC2 — roteador no apartamento 2, MC3 — roteador no apartamento 3
* As configurações dos dispositivos estão publicadas em um spoiler no final do artigo.

Assim, os pings entre os nós da rede 192.168.31.0/24 estão funcionando, é hora de passar à configuração do túnel GRE. Antes disso, para não perder o acesso aos roteadores, é aconselhável configurar túneis SSH para encaminhar a porta 22 no VPS, de tal forma que, por exemplo, na porta 10022, o VPS terá acesso ao roteador do apartamento 2, e na porta 11122, ao roteador do apartamento 3. A configuração do encaminhamento é melhor realizada utilizando o sshtunnel, pois ele restaurará o túnel caso ele caia.

O túnel está configurado, agora é possível conectar via SSH através da porta encaminhada:

ssh root@MEU_VPS -p 10022

Em seguida, deve-se desconectar do OpenVPN:

/etc/init.d/openvpn stop

Agora vamos configurar o túnel GRE no roteador do apartamento 2:

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

E adicionaremos a interface criada ao bridge:

brctl addif br-lan grelan0

Executaremos o mesmo procedimento no roteador-servidor:

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

E, também, adicionaremos a interface criada ao bridge:

brctl addif br-lan grelan0

A partir deste momento, os pings começam a funcionar com sucesso na nova rede e eu, satisfeito, vou beber café. Em seguida, para avaliar como a rede funciona do outro lado do cabo, tento me conectar via SSH a um dos computadores no apartamento 2, mas o cliente SSH "congela", não oferecendo a opção de inserir a senha. Tento me conectar a esse computador via telnet na porta 22 e vejo uma linha que indica que a conexão está sendo estabelecida, o servidor SSH responde, mas por algum motivo não me permite entrar.

$ telnet 192.168.10.110 22
SSH-2.0-OpenSSH_8.1

Tento me conectar a ele via VNC e vejo uma tela preta. Convencio-me de que o problema está no computador remoto, pois posso me conectar ao roteador deste apartamento através do endereço interno. No entanto, decido me conectar ao SSH deste computador através do roteador e, para minha surpresa, a conexão é bem-sucedida, e o computador remoto funciona perfeitamente, mas também não consegue se conectar ao meu computador.

Desconecto o dispositivo grelan0 do bridge e inicio o OpenVPN no roteador do apartamento 2, garantindo que a rede funcione novamente como deveria e que as conexões não sejam interrompidas. Pesquisando, encontro fóruns onde as pessoas reclamam de problemas semelhantes, onde é sugerido aumentar o MTU. E assim foi feito. No entanto, enquanto o MTU não foi definido suficientemente grande — 7000 para dispositivos gretap, observei ou interrupções nas conexões TCP ou baixa velocidade de transferência. Devido ao alto MTU para gretap — o MTU para as conexões WireGuard do primeiro e segundo níveis foi definido em 8000 e 7500, respectivamente.

Realizei configuração semelhante no roteador do apartamento 3, com a única diferença de que no roteador servidor foi adicionada uma segunda interface gretap chamada grelan1, que também foi adicionada ao bridge br-lan.

Está tudo funcionando. Agora, posso colocar a montagem gretap no auto-início. Para isso:

Coloquei essas linhas em /etc/rc.local no roteador do 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

Adicionei isto em /etc/rc.local no roteador do 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

E no roteador-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

Após reiniciar os roteadores dos clientes, percebi que, por algum motivo, eles não estavam se conectando ao servidor. Conectando-me ao SSH deles (felizmente, eu configurei o sshtunnel para isso) descobri que o WireGuard, por algum motivo, está criando uma rota para o endpoint, sendo esta incorreta. Assim, para 192.168.30.2, a tabela de rotas indicava uma rota através da interface pppoe-wan, ou seja, pela internet, embora a rota para ele devesse ser direcionada através da interface wg0. Depois de remover essa rota, a conexão foi restaurada. Não consegui encontrar instruções sobre como fazer o WireGuard não criar essas rotas. Além disso, não entendi se essa é uma característica do OpenWRT ou do próprio WireGuard. Sem querer gastar muito tempo resolvendo esse problema, adicionei a ambos os roteadores um script, que roda continuamente em um timer, com a linha que remove essa rota:

route del 192.168.30.2

Em resumo

Ainda não consegui abandonar completamente o OpenVPN, pois preciso me conectar ocasionalmente a uma nova rede com meu laptop ou telefone, e a configuração do dispositivo gretap neles, em geral, é impossível. No entanto, apesar disso, consegui um aumento na velocidade de transmissão de dados entre os apartamentos e, por exemplo, o uso de VNC agora não é incômodo. O ping diminuiu ligeiramente, mas se tornou mais estável:

Ao 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

Ao 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

Ele é mais afetado pelo ping alto para o VPS, que é de aproximadamente 61,5 ms

No entanto, a velocidade aumentou significativamente. Assim, no apartamento com o roteador-servidor, tenho uma velocidade de conexão à Internet de 30 Mbps, enquanto nos outros apartamentos é de 5 Mbps. Durante o uso do OpenVPN, não consegui atingir uma velocidade de transferência de dados entre as redes maior que 3,8 Mbps, segundo as medições do iperf, enquanto o WireGuard 'conseguiu' elevar essa taxa para os mesmos 5 Mbps.

Configuração do WireGuard no VPS[Interface]
Endereço = 192.168.30.1/24
PortaDeEscuta = 51820
ChavePrivada =

[Peer]
PublicKey =
AllowedIPs = 192.168.30.2/32

[Peer]
PublicKey =
AllowedIPs = 192.168.30.3/32

[Peer]
PublicKey =
AllowedIPs = 192.168.30.4/32

Configuração do WireGuard no MS (adicionada em /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'

Configuração do WireGuard no MK2 (adicionada em /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'

Configuração do WireGuard no MK3 (adicionada em /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'

Nas configurações descritas para o VPN de segundo nível, indico aos clientes do WireGuard a porta 51821. Em teoria, isso não é necessário, pois o cliente estabelecerá a conexão de qualquer porta livre não privilegiada, mas fiz assim para que fosse possível proibir todas as conexões de entrada nas interfaces wg0 de todos os roteadores, exceto as conexões UDP de entrada na porta 51821.

Espero que o artigo seja útil para alguém.

P.S. Além disso, quero compartilhar meu script, que me envia uma notificação PUSH para o celular no aplicativo WirePusher quando um novo dispositivo aparece na minha rede. Aqui está o link para o script: github.com/r0ck3r/device_discover.

ATUALIZAÇÃO: Configuração do servidor e 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 # Altere para o IP Externo do seu roteador
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

Utilizei o easy-rsa para gerar os certificados.

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster