
I would like to share my experience of merging networks in three geographically distant apartments, each using OpenWRT routers as gateways, into a single network. When choosing between L3 subnets with routing and L2 bridging, where all network nodes would be in the same subnet, the latter was preferred. Although it is more complex to set up, it offers greater capabilities because the intended network would transparently support Wake-on-Lan and DLNA technologies.
Part 1: Background
For this task, OpenVPN was initially chosen as the protocol because, first, it can create a tap device that integrates seamlessly into the bridge, and second, OpenVPN supports TCP, which was also crucial since none of the apartments had a dedicated IP address. I couldn't use STUN because my provider blocks incoming UDP connections for some reason, while TCP allowed me to forward the VPN server port on the rented VPS via SSH. Yes, this approach does introduce higher overhead since data is encrypted twice, but I didn't want to integrate the VPS into my private network due to the risk of third-party control. Thus, having such a device on the home network was highly undesirable, and I decided to pay for security with the extra overhead.
To forward the port on the router where the server was to be deployed, I used the sshtunnel program. I won't go into the nuances of its configuration—it's fairly straightforward. I will just note that its purpose was to forward TCP port 1194 from the router to the VPS. Next, I configured the OpenVPN server on the tap0 device, which was added to the br-lan bridge. After testing the connection to the newly created server from my laptop, it became clear that the port forwarding concept worked, and my laptop became a member of the router's network, even though it was physically outside of it.
The next step was to assign IP addresses across different apartments to avoid conflicts and configure the routers as OpenVPN clients.
The following IP addresses were chosen for the routers and the DHCP server ranges:
- 192.168.10.1 with the range 192.168.10.2 — 192.168.10.80 for the server
- 192.168.10.100 with the range 192.168.10.101 — 192.168.10.149 for the router in apartment №2
- 192.168.10.150 with the range 192.168.10.151 — 192.168.10.199 for the router in apartment №3
It was also necessary to assign these addresses to the client routers of the OpenVPN server by adding the following line to its configuration:
ifconfig-pool-persist /etc/openvpn/ipp.txt 0and adding the following lines to the file /etc/openvpn/ipp.txt:
flat1_id 192.168.10.100
flat2_id 192.168.10.150
where flat1_id and flat2_id are device names specified when creating certificates for connecting to OpenVPN.
Next, the OpenVPN clients were configured on the routers, and the tap0 devices on both were added to the br-lan bridge. At this stage, everything seemed fine, as all three networks could see each other and functioned as a single entity. However, an unpleasant detail emerged: sometimes devices could receive an IP address not from their own router, leading to various complications. For some reason, the router in one of the apartments was not able to respond in time to DHCPDISCOVER, causing the device to obtain an incorrect address. I realized I needed to filter such requests in tap0 on each router, but, as it turned out, iptables cannot work with a device that is part of a bridge, so ebtables would have to come to my rescue. Unfortunately, it was not included in my firmware, and I had to rebuild the images for each device. After doing this and adding the following 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: Introduction to WireGuard
Recently, WireGuard has been increasingly discussed online, praised for its ease of configuration, high transfer speeds, and low latency while maintaining comparable security. Searching for more information revealed that neither operation as a bridge member nor TCP protocol support is available, making me think that there are still no alternatives to OpenVPN for me. Thus, I postponed my acquaintance with WireGuard.
A few days ago, news spread across various IT-related resources that WireGuard will finally be included in the Linux kernel starting from version 5.6. As always, news articles praised WireGuard. I once again dove into the search for ways to replace the good old OpenVPN. This time I stumbled upon . It discussed the creation of an Ethernet tunnel over L3 using GRE. This article gave me hope. However, it remained unclear what to do with the UDP protocol. My search led me to articles about using socat in conjunction with an SSH tunnel to forward the UDP port; however, they mentioned that this approach only works in a single connection mode, meaning that multiple VPN clients would be impossible. I had the idea of setting up a VPN server on a VPS and configuring GRE for clients, but as it turned out, GRE does not support encryption, which would mean that if someone else gained access to the server, all traffic between my networks would be in their hands, which I fundamentally disagreed with.
Once again, a decision was made in favor of excessive encryption by using VPN over VPN according to the following scheme:
First-Level VPN:
VPS is proxy server with an internal address of 192.168.30.1
MC is client VPS with an internal address of 192.168.30.2
MC2 is client VPS with an internal address of 192.168.30.3
MC3 is client VPS with an internal address of 192.168.30.4
Second-Level VPN:
MC is proxy server with an external address of 192.168.30.2 and an internal address of 192.168.31.1
MC2 is client MC with an address of 192.168.30.2 and an internal IP of 192.168.31.2
MC3 is client MC with an address of 192.168.30.2 and an internal IP of 192.168.31.3
* MC — router-server in apartment 1, MC2 — router in apartment 2, MC3 — router in apartment 3
* Device configurations are published in a spoiler at the end of the article.
So, pings between nodes in the network 192.168.31.0/24 are going through, it's time to set up the GRE tunnel. Before that, to avoid losing access to the routers, it's worth setting up SSH tunnels to forward port 22 on the VPS so that, for example, the router from apartment 2 is available on port 10022 on the VPS, and the router from apartment 3 is available on port 11122. It’s best to set up the forwarding with sshtunnel since it will restore the tunnel in case it drops.
The tunnel is set up; you can connect to SSH through the forwarded port:
ssh root@MY_VPS -p 10022Next, you should disable OpenVPN:
/etc/init.d/openvpn stopNow let's set up 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 let's add the created interface to the bridge:
brctl addif br-lan grelan0
We'll perform the same procedure on the server router:
ip link add grelan0 type gretap remote 192.168.31.2 local 192.168.31.1
ip link set grelan0 up
And, likewise, we'll add the created interface to the bridge:
brctl addif br-lan grelan0
From this moment, pings start successfully reaching the new network, and I happily head off to have coffee. Then, to evaluate how the network works at the other end, I try to connect via SSH to one of the computers in apartment 2, but the SSH client 'freezes,' not prompting for a password. I try to connect to this computer via telnet on port 22 and see a message indicating that the connection is being established, the SSH server is responding, but for some reason isn't allowing me to log in.
$ telnet 192.168.10.110 22
SSH-2.0-OpenSSH_8.1
I try connecting to it via VNC and see a black screen. I convince myself that it’s an issue with the remote computer, as I can connect to the router from this apartment using the internal address without any problems. However, I decide to connect to the SSH of this computer through the router and am surprised to discover that the connection is successful, and the remote computer is functioning normally, yet it still can't connect to my computer.
I remove the grelan0 device from the bridge and start OpenVPN on the router in apartment 2, confirming that the network is functioning properly again and connections are stable. I stumble upon forums where people are complaining about similar issues and are advised to increase the MTU. As instructed, I do so. However, until the MTU is set sufficiently high — 7000 for gretap devices — I experienced either TCP connection drops or low transfer speeds. Due to the high MTU for gretap, the MTU for WireGuard connections at the first and second levels were set to 8000 and 7500, respectively.
I made similar adjustments to the router in apartment 3, with the only difference being that a second gretap interface named grelan1 was added to the server router, which was also included in the bridge br-lan.
Everything is working. Now we can set the gretap set up to run at startup. To do this:
I placed 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 7000
ip link set grelan0 up
brctl addif br-lan grelan0
I added this to /etc/rc.local on the router in my apartment 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
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 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
After rebooting the client routers, I discovered that they were somehow unable to connect to the server. After connecting to their SSH (luckily, I had previously set up an sshtunnel for this), it was found that WireGuard was inexplicably creating a route for the endpoint, and it was incorrect. For 192.168.30.2, the route in the routing table pointed through the pppoe-wan interface, meaning through the internet, whereas the route should have been directed through the wg0 interface. After deleting this route, the connection was restored. I couldn't find any instructions on how to prevent WireGuard from creating these routes. Moreover, I couldn't understand if this was a feature of OpenWRT or WireGuard itself. Not wanting to delve deep into this issue, I simply added a line to the script on both routers that loops on a timer, which deletes this route:
route del 192.168.30.2
In summary
I haven't completely abandoned OpenVPN yet, as I still need to connect to a new network occasionally with my laptop or phone, and the configuration of a gretap device on them is generally not feasible. However, despite this, I gained an advantage in data transfer speed between apartments, and for instance, using VNC is now hassle-free. The ping slightly decreased, but it 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 mainly affected by the high ping to the VPS, which is about 61.5 ms.
However, the speed has increased significantly. In the apartment with the server-router, I have an Internet connection speed of 30 Mbps, while in other apartments it is 5 Mbps. During the use of OpenVPN, I couldn't achieve data transfer speeds between networks greater than 3.8 Mbps according to iperf, while WireGuard 'pumped' it up to the same 5 Mbps.
WireGuard Configuration on VPS[Interface]
Address = 192.168.30.1/24
ListenPort = 51820
PrivateKey =
[Peer]
PublicKey =
AllowedIPs = 192.168.30.2/32
[Peer]
PublicKey =
AllowedIPs = 192.168.30.3/32
[Peer]
PublicKey =
AllowedIPs = 192.168.30.4/32
WireGuard Configuration on MC (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'
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'
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'
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'
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'
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'
In the described configurations for the level two VPN, I specify to the WireGuard clients port 51821. Ideally, this is unnecessary, as the client will establish a connection from any available non-privileged port, but I did it so that it would be possible to prohibit all incoming connections on the wg0 interfaces of all routers, except for incoming UDP connections on port 51821.
I hope this article will be useful to someone.
P.S. I also want to share my script that sends me a PUSH notification to my phone in the WirePusher app whenever a new device appears on my network. Here's the link to the script: .
UPDATE: OpenVPN Server and Client Configuration
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-lzoOpenVPN 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 I used easy-rsa to generate the certificates
Source: habr.com
