This note describes how to connect two networks/devices/VMs over public network using Wireguard with Layer 2 support (ARP, IPv6 link-local, etc).
This can also be achieved using SSH and its "tap" tunnel, however, it does not provide the same level of latency and bandwidth as full-blown VPN such as Wireguard.
In addition, this note describes how to tunnel Wireguard over TCP connection. This may be of use if you encounter firewall in-between so, for instance, you can use TCP port 443 only.
Let's draw a network diagram of what we would like to have in as a result.
Host on private LAN Host on the Internet
+---------------------------------+ +-------------------------------+
| brtun bridge | | brtun bridge |
| +-------------+ | | +--------+ |
| | ethX gretun |<->wg0<->udp2raw | <-Internet, TCP 443-> | udp2raw<->wg0<->| gretun | |
| +-------------+ | | +--------+ |
+---------------------------------+ +-------------------------------+
brtun: 192.168.0.200/24 brtun: 192.168.0.50/24
wg0: 12.12.12.2/24 wg0: 12.12.12.1/24
gretun: 12.12.12.2->12.12.12.1 gretun: 12.12.12.1->12.12.12.2
Distinguishing between server and client here is based on the answer to the question: who can connect to Wireguard listener socket.
Generating a key:
wg genkey | tee wgkeyprivs | wg pubkey > wgkeypubs
Creating a Wireguard interface, setting the private key and a unique private IPv4 address:
ip l a wg0 type wireguard
wg set wg0 private-key ./wgkeyprivs
ip a a 12.12.12.1/24 dev wg0
In case we want Wireguard over TCP, we have to decrease MTU:
ip l set dev wg0 mtu 1200
Configuring peer's public key and setting interface up (you can restrict allowed-ips to the range you want):
ip l set dev wg0 up
wg set wg0 listen-port 51820 peer $(cat wgkeypubc) allowed-ips 0.0.0.0/0
Creating GRETAP interface which will provide Layer 2 over our Wireguard tunnel:
ip l a gretun type gretap local 12.12.12.1 remote 12.12.12.2
ip l s gretun up
Configuring a bridge which includes GRETAP interface. This step is in fact optional, but it allows you some flexibility: you can assign an IP address to this bridge interface and/or you can add additional interfaces to this bridge.
ip l add name brtun type bridge
ip l set dev brtun up
ip l set gretun master brtun
Let's assign an IP address from the target network to this bridge:
sudo ip a a 192.168.0.51/24 dev brtun
If we want Wireguard over TCP, launch UDP2RAW listener which will do its magic. You can get UDP2RAW from this Git repo: https://github.com/wangyu-/udp2raw-tunnel/releases/
./udp2raw_amd64 -s -l YOUR_PUBLIC_IP:443 -r 127.0.0.1:51820 -a --fix-gro
Client is very similar to the server described above.
Generating a key:
wg genkey | tee wgkeyprivc | wg pubkey > wgkeypubc
Creating a Wireguard interface, setting the private key and a unique private IPv4 address:
ip l a wg0 type wireguard
wg set wg0 private-key ./wgkeyprivc
ip a a 12.12.12.2/24 dev wg0
In case we want Wireguard over TCP, we have to decrease MTU:
ip l set dev wg0 mtu 1200
Configuring peer's public key, endpoint address and setting interface up (you can restrict allowed-ips to the range you want):
ip l set dev wg0 up
wg set wg0 listen-port 51820 peer $(cat wgkeypubs) allowed-ips 0.0.0.0/0 endpoint YOUR_PUBLIC_IP:51820 persistent-keepalive 15
In case you want Wireguard over TCP, set endpoint address to a localhost interface:
wg set wg0 listen-port 51820 peer $(cat wgkeypubs) allowed-ips 0.0.0.0/0 endpoint 127.0.0.1:7777 persistent-keepalive 15
Creating GRETAP interface which will provide Layer 2 over our Wireguard tunnel:
ip l a gretun type gretap local 12.12.12.2 remote 12.12.12.1
ip l s gretun up
Configuring a bridge which includes GRETAP interface.
ip l add name brtun type bridge
ip l set dev brtun up
ip l set gretun master brtun
Let's add a physical interface belonging to a LAN network to the bridge and start DHCP client:
ip l set ethX master brtun
dhcpcd ethX
If we want Wireguard over TCP, launch UDP2RAW listener on the localhost interface which connects to the corresponding public listener.
./udp2raw_amd64 -c -l 127.0.0.1:7777 -r YOUR_PUBLIC_IP:443 -a --fix-gro
That's it. Now you will have Layer 2 connectivity between two separated machines over Wireguard VPN (optionally, over TCP). Enjoy your ARP and IPv6 link-local experience.
HI @zOrg1331
I am clueless here after connecting with other systems in the LAN. I managed to use Allowed IPs with /32 and expecting it is working. As mentioned in my previous comment I am able to communicate with LAN IPs between the Wireguard hosts.
Problem starts after I add LAN side interface to bridge. This looks weird. My LAN side IP is 192.168.17.1 on enp2s0 interface. I have a
system with 192.168.17.5 connected with a switch to enp2s0 of Wireguard host.
The moment I add enp2s0 to the bridge these systems stops communicating each other. No Ping. No arp info. If I remove enp2s0 from the
bridge with nomaster option, then they again start communicating each other. I am clueless here.
root@srv1 fcoos]# bridge l
3: enp2s0: <BROADCAST,MULTICAST,PROMISC,UP,LOWER_UP> mtu 1500 master brtun state forwarding priority 32 cost 4
12: gretun@NONE: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1382 master brtun state forwarding priority 32 cost 100
If I run
root@srv1 fcoos]# ip l set enp2s0 nomaster
[root@srv1 fcoos]# ping 192.168.17.5
PING 192.168.17.5 (192.168.17.5) 56(84) bytes of data.
64 bytes from 192.168.17.5: icmp_seq=1 ttl=64 time=0.166 ms
But If I add again to the bridge
oot@srv1 fcoos]# ip l set enp2s0 master brtun up
[root@srv1 fcoos]# ping 192.168.17.5
PING 192.168.17.5 (192.168.17.5) 56(84) bytes of data.
From 192.168.17.1 icmp_seq=1 Destination Host Unreachable
I was expecting the reverse of this. Thinking I am doing something wrong here. But what is that ? Please note that I need to bridge two LANS not two hosts. I have bridged LAN with OpenVPN tap. But performance is not as expected. I am hopeful with wire-guard. But :). Need help