Migrating from OpenVPN to WireGuard to join networks into one L2 network



I would like to share the experience of combining networks in three geographically remote apartments, in each of which routers with OpenWRT are used as a gateway into one common network. When choosing a method for combining networks between L3 with routing of subnets and L2 with bridging, when all nodes of the network will be on the same subnet, the second method was preferred, which was more difficult to configure, but giving more opportunities, since the network was planned to use transparent technologies Wake-on-Lan and DLNA.

Part 1: Background


OpenVPN was initially chosen as the protocol for implementing this task, because, firstly, it can create a tap device that can be easily added to the bridge, and secondly, OpenVPN supports TCP protocol operation, which was also important, because none of the apartments had a dedicated IP address, and I was not able to use STUN, because for some reason my provider blocks incoming connections via UDP from their networks, while TCP allowed me to forward the port of the VPN server to leased VPS using SSH. Yes, this approach gives a big load, since the data is encrypted twice, but I did not want to enter VPS into my private network, as there was a risk of third parties gaining control over it, therefore,having such a device on the home network was extremely undesirable and it was decided to pay for security with a large overhead.

To forward the port on the router on which it was planned to deploy the server, the sshtunnel program was used. I will not describe the intricacies of its configuration - this is done quite easily, I just note that its task was to forward the TCP port 1194 from the router to the VPS. Next, the OpenVPN server was configured on the tap0 device, which wound up in the br-lan bridge. After checking the connection to the server you just created from the laptop, it became clear that the idea of ​​port forwarding had paid off and my laptop became a member of the router network, although I was not physically there.

The matter remained small: it was necessary to distribute IP addresses in different apartments so that they did not conflict and configure routers as OpenVPN clients.
The following router IP addresses and DHCP server ranges were selected:

  • 192.168.10.1 with a range of 192.168.10.2 - 192.168.10.80 for the server
  • 192.168.10.100 with a range of 192.168.10.101 - 192.168.10.149 for the router in apartment No. 2
  • 192.168.10.150 with a range of 192.168.10.151 - 192.168.10.199 for the router in apartment No. 3

It was also necessary to assign these addresses to the client routers of the OpenVPN server by adding the following lines to its configuration:

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

and adding the following lines to the /etc/openvpn/ipp.txt file:

flat1_id 192.168.10.100
flat2_id 192.168.10.150

where flat1_id and flat2_id are the device names specified when creating certificates for connecting to OpenVPN

Next, OpenVPN clients were configured on the routers, tap0 devices on both were added to the br-lan bridge. At this stage, it seemed that everything was in order, since all three networks see each other and work as a whole. However, it turned out to be a not very pleasant detail: sometimes devices could not get an IP address from their router, with all the ensuing consequences. For some reason, the router in one of the apartments did not have time to respond in time to DHCPDISCOVER and the device did not receive its address. I realized that I need to filter such requests in tap0 on each of the routers, but, as it turned out, iptables cannot work with the device if it is part of the bridge and ebtables should come to my aid. Unfortunately, it wasn’t in my firmware and I had to rebuild the images for each device.Having done this and adding such lines to /etc/rc.local of each router, the problem was solved:

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

This configuration lasted for three years.

Part 2: Introducing WireGuard


Recently, on the Internet, they began to talk more and more about WireGuard, admiring the simplicity of its configuration, high transmission speed, low ping with comparable security. The search for additional information about him made it clear that they did not support either working as a member of the bridge or working with the TCP protocol, which made me think that there were still no alternatives to OpenVPN for me. So I put off getting to know WireGuard.

A few days ago, over the resources, one way or another connected with IT, the news flashed that WireGuard will finally be included in the Linux kernel, starting with version 5.6. News articles, as always, praised WireGuard. I again plunged into the search for ways to replace the good old OpenVPN. This time I ran into this article. It talked about building an Ethernet tunnel over L3 using GRE. This article gave me hope. It remained unclear what to do with the UDP protocol. The search led me to articles about using socat in conjunction with an SSH tunnel to forward a UDP port, however, they noted that this approach only works in single connection mode, that is, the work of several VPN clients would be impossible. I came up with the idea of ​​raising a VPN server on VPS, and setting up GRE for clients, but as it turned out, GRE does not support encryption, which will lead to the fact that in case of access to the server by third parties, all traffic between my networks is in their hands that did not suit me in principle.

Again, the decision was made in favor of excessive encryption, by using a VPN over a VPN according to the following scheme:

First level VPN:
VPS is a server with an internal address of 192.168.30.1
MS is a VPS client with an internal address of 192.168.30.2
MK2 is a VPS client with an internal address of 192.168.30.3
MK3 is a VPS client with an internal address of 192.168.30.3 MK2 is a

second-level VPN:
MS is a server with an external address 192.168.30.2 and an internal 192.168.31.1
MK2 is an MS client with an address of 192.168.30.2 and has an internal IP 192.168.31.2
MK3 is an MS clientwith the address 192.168.30.2 and has an internal IP 192.168.31.3

* MS - router-server in apartment 1, MK2 - router in apartment 2, MK3 - router in apartment 3
* Device configurations are published in the spoiler at the end of the article.

And so, pings between the nodes of the network 192.168.31.0/24 go, it is time to move on to setting up the GRE tunnel. Before this, in order not to lose access to the routers, it is worth setting up SSH tunnels to forward 22 ports on the VPS, so that, for example, the router from apartment 2 will be available on the 10022nd VPS port, and on the 11122th port the VPS will be available the router is from apartment 3. It is best to configure forwarding with the same sshtunnel, as it will restore the tunnel if it falls.

The tunnel is configured, you can connect to SSH through the forwarded port:

ssh root@_VPS -p 10022

Next, disable OpenVPN:

/etc/init.d/openvpn stop

Now configure the GRE tunnel on the router from apartment 2:

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

And add the created interface to the bridge:

brctl addif br-lan grelan0

We will perform a similar procedure on the router-server:

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

And, also, add the created interface to the bridge:

brctl addif br-lan grelan0

starting from this moment, pings begin to successfully go to the new network and I, with satisfaction, am going to drink coffee. Then, in order to evaluate how the network works on the other end of the wire, I try to connect via SSH to one of the computers in apartment 2, but the ssh client freezes without prompting for a password. I try to connect to this computer via telnet to port 22 and I see a line from which it can be understood that the connection is being established, the SSH server is responding, just for some reason does not offer me to log in.

$ telnet 192.168.10.110 22
SSH-2.0-OpenSSH_8.1

I try to connect to it via VNC and see a black screen. I assure myself that it is a remote computer, because I can easily connect to the router from this apartment at the internal address. However, I decide to connect to the SSH of this computer through a router and am surprised to find that the connection is successful and the remote computer is working properly, but it also cannot connect to my computer.

I remove the grelan0 device from the bridge and run OpenVPN on the router in apartment 2 and make sure that the network works again as expected and the connections do not break. When I search, I come across forums where people complain about the same problems, where they are advised to raise the MTU. However, I was not able to increase the MTU for the first level VPN (wg0): with MTUs above 1420, which is set automatically, breaks begin, but at the same time, the second level VPN wg1 working on top of wg0 worked correctly with MTU 1600. This is enough to install The MTU is 1500 for the gretap device, so that this interface has the same MTU value as the br-lan bridge into which gretap was planned to be added. As I understand it, the bridge sets the MTU equal to the smaller of the available values ​​on all devices.

I made a similar configuration on the router from apartment 3, with the only difference being that on the router the server added a second gretap interface named grelan1, which was also added to the br-lan bridge.

Everything is working. Now you can put the gretap assembly at startup. To do this:

Put these lines in /etc/rc.local on the router in apartment 2:

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

Added this to /etc/rc.local on the router in apartment 3:

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

And on the server router:

ip link add grelan0 type gretap remote 192.168.31.2 local 192.168.31.1
ip link set dev grelan0 mtu 1500
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 1500
ip link set grelan1 up
brctl addif br-lan grelan1

After rebooting the client routers, I found that for some reason they did not connect to the server. Having connected to their SSH (fortunately, I preconfigured sshtunnel for this), it was discovered that WireGuard was creating a route for endpoint for some reason, but it was incorrect. So, for 192.168.30.2, the route table indicated the route through the pppoe-wan interface, that is, via the Internet, although the route to it should have been routed through the wg0 interface. After deleting this route, the connection was restored. I could not find somewhere instructions on how to make WireGuard not create these routes. Moreover, I did not even understand, a feature is OpenWRT, or WireGuard itself. Not having to deal with this problem for a long time, I simply added a line to this router to the script looped over by a timer to delete this route:

route del 192.168.30.2

To summarize


I have not yet achieved a complete rejection of OpenVPN, since I sometimes need to connect to a new network from a laptop or phone, and setting up a gretap device on them is generally impossible, but despite this, I got an advantage in the data transfer speed between apartments and, for example, the use of VNC now does not cause inconvenience. Ping decreased slightly, but became more stable:

When using 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

When using 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

It is more affected by the high ping before VPS, which is approximately 61.5 ms.

However, the speed has increased significantly. So, in an apartment with a router-server, I have an Internet connection speed of 30 Mbps, and in other apartments - 5 Mbps. At the same time, while using OpenVPN, I was not able to achieve a data transfer speed between networks of more than 3.8 Mb / s according to iperf, while WireGuard “pumped” it to the same 5 Mb / s.

WireGuard Configuration on VPS
[Interface]
Address = 192.168.30.1/24
ListenPort = 51820
PrivateKey = <___VPS>

[Peer]
PublicKey = <__VPN_1_>
AllowedIPs = 192.168.30.2/32

[Peer]
PublicKey = <__VPN_2_2>
AllowedIPs = 192.168.30.3/32

[Peer]
PublicKey = <__VPN_2_3>
AllowedIPs = 192.168.30.4/32


WireGuard configuration on MS (added to / 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'

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 '1600'

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'


WireGuard configuration on MK2 (added to / 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'

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 '1600'

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'


WireGuard configuration on MK3 (added to / 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'

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 '1600'

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'


In the described configurations for the second level VPN, I specify the 51821 port to WireGuard clients. In principle, this is not necessary, as the client will establish a connection from any free unprivileged port, but I made it so that I could block all incoming connections on the wg0 interfaces of all routers, except incoming UDP connections to port 51821.

I hope this article is useful to someone.

PS Also, I want to share my script that sends me a PUSH notification on the phone to the WirePusher application when a new device appears on my network. Here is the link to the script: github.com/r0ck3r/device_discover .

UPDATE: Configuring OpenVPN Server and Clients

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


OpenVPN client
client
tls-client
dev tap
proto tcp
remote VPS_IP 1194 # Change to your router's External IP
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



To generate certificates used easy-rsa

Source: https://habr.com/ru/post/undefined/


All Articles