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.
Thanks for this article.
I was looking for a fastest option to bridge two locations with same LAN network.
Wireguard plus GRETAP and bridging seems to be the best option for this. I followed this article and with the help, I am able to
connect two hosts to reach each other with LAN IP addresses . I.e with this method we can connect two systems with a bridge over Wireguard and GRETAP. But when try to reach other systems than the Wireguard host, it seems not working.
On a boarder way I am able to see that Wireguard is doing some mischief with 'Allowed IPS' option.
Being both side same LAN I am forced to use 'Allowed IPS' same network. Say for example if you
are planning to extend 192.168.5.0/24 with this solution, we need to add Allowed IPs = 192.168.5.0/24 on both side.
in addition to the WG interface IPs. This seems creating problem as other systems in the same network can't reach
Wireguard system LAN ip address as Wireguard forwarding that packets to peer system. So once Wireguard is up,
the Wireguard systems are not ping-able from the LAN network on each side, because Wireguard seems to forward that
packets to the peer host instead of responding to ping.
Wondering any workaround for this problem ?