Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
wireguard, wireguard layer 2, wireguard over TCP

Intro

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.

Objective

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
 

Setting things up

Distinguishing between server and client here is based on the answer to the question: who can connect to Wireguard listener socket.

Server

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

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

Results

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.

References

@mrbluecoat
Copy link

I think cat wgkeypubc is supposed to be cat wgkeypubs

@legale
Copy link

legale commented Nov 15, 2022

@zOrg1331 помоги разоюраться. Неделю ковыряюсь. Никак не заставлю туннель работать.

Есть сервер для туннеля (debian11) клиент точка доступа openwrt 21.02.

На сервере делаю так:

export ADDR=$(ip addr show dev ens192 | grep -Eo 'inet [0-9./]+' | cut -d ' ' -f 2)
export MAC=$(cat /sys/class/net/ens192/address)
export GW=$(ip ro show dev ens192 | grep -Eo 'via [0-9./]+' | cut -d ' ' -f 2)

ip link add br0 type bridge
ip link set ens192 master br0
ip link set dev br0 address $MAC
ip addr add $ADDR dev br0
ip link set br0 up
ip ro del default dev ens192
ip route add default via $GW dev br0
ip addr flush dev ens192
ip link add gre1 type gretap local 10.66.66.1 remote 10.66.66.2
ip link set gre1 master br0

10.66.66.1 это работающий туннель wg.

На клиенте тоже делаю бридж и к нему добавляю gre интерфейс.
вот что показывает ip link show

43: br-lan: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1368 qdisc noqueue state UP mode DEFAULT group default qlen 1000  link/ether d6:9f:22:36:47:f6 brd ff:ff:ff:ff:ff:ff
45: gre4t-gre@NONE: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1368 qdisc fq_codel master br-lan state UNKNOWN mode DEFAULT group default qlen 1000 link/ether 9a:cd:bc:67:dd:56 brd ff:ff:ff:ff:ff:ff

ip link show master br-lan

44: wlan0_1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq master br-lan state UP mode DEFAULT group default qlen 4096
    link/ether 44:d1:fa:bc:0e:60 brd ff:ff:ff:ff:ff:ff
45: gre4t-gre@NONE: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1368 qdisc fq_codel master br-lan state UNKNOWN mode DEFAULT group default qlen 1000
    link/ether 9a:cd:bc:67:dd:56 brd ff:ff:ff:ff:ff:ff

В итоге по dhcp на клиенте на br-lan интерфейс получаю ip адрес из сети на другом конце туннеля. Пинг работает. А вот wget просто повисает в раздумьях, а потом вышибает по таймауту.

Что я пропустил? Куда копать?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment