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.