[筆記] 透過 wireguard 建立多點 site to site VPN / Multiple Site to Site VPN Using Wireguard

因為實在受夠了現在用的 openwrt + strongswan 建立 IPSec VPN

雖然說其實沒有什麼不好,但是畢竟不是我建立的,而當初的文件也都不見了

完全沒辦法了解當時設計的邏輯,造成後續debug 困難

可以想像一下,一台VPN router ping 不到remote、ping不到internet、甚至ping不到自己 是要怎麼debug !?(翻桌

之前買了兩台edgerouter X 拿來玩了一下 wireguard,感覺還不錯,不過只有測試到點對點

這次試試看躲在gateway後面,看看能不能建立多點的VPN環境

every node

enable ip_forward

edit /etc/sysctl.conf add below line in the end of the file

net.ipv4.ip_forward=1
install wireguard
sudo apt-get install libmnl-dev linux-headers-$(uname -r) build-essential make git libelf-dev
git clone https://git.zx2c4.com/WireGuard
cd WireGuard/src/
make
sudo make install

or via apt

sudo add-apt-repository ppa:wireguard/wireguard
sudo apt install wireguard
create wireguard service file

add /etc/systemd/system/multi-user.target.wants/wg-quick@wg0.service

[Unit]
Description=WireGuard via wg-quick(8) for %I
After=network-online.target nss-lookup.target
Wants=network-online.target nss-lookup.target
Documentation=man:wg-quick(8)
Documentation=man:wg(8)
Documentation=https://www.wireguard.com/
Documentation=https://www.wireguard.com/quickstart/
Documentation=https://git.zx2c4.com/WireGuard/about/src/tools/man/wg-quick.8
Documentation=https://git.zx2c4.com/WireGuard/about/src/tools/man/wg.8

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/wg-quick up %i
ExecStop=/usr/bin/wg-quick down %i
Environment=WG_ENDPOINT_RESOLUTION_RETRIES=infinity

[Install]
WantedBy=multi-user.target

Node A

create wireguard private/public key
wg genkey > /etc/wireguard/private
cat /etc/wireguard/private | wg pubkey > /etc/wireguard/public
/etc/wireguard/wg0.conf

watch the interface name , must meets the interface name in system , ens18 is the default value of my test VM

[Interface]
Address = 10.0.0.40/24
ListenPort = 12000
PrivateKey = private key of node A
PostUp   = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ens18 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens18 -j MASQUERADE

[Peer]
PublicKey = public key of node B
AllowedIPs = 10.0.0.28/32,192.168.28.0/24
Endpoint = 2.2.2.2:12000
PersistentKeepalive = 15

[Peer]
PublicKey = public key of node C
AllowedIPs = 10.0.0.80/32,192.168.80.0/24
Endpoint = 3.3.3.3:12000
PersistentKeepalive = 15

Node B (peer 1)

create wireguard private/public key
wg genkey > /etc/wireguard/private
cat /etc/wireguard/private | wg pubkey > /etc/wireguard/public
/etc/wireguard/wg0.conf

watch the interface name , must meets the interface name in system , ens18 is the default value of my test VM

[Interface]
ListenPort = 12000
PrivateKey = private key of node B
Address = 10.0.0.28/24
PostUp   = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ens18 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens18 -j MASQUERADE

[Peer]
PublicKey = public key of node A
AllowedIPs = 10.0.0.40/32,192.168.40.0/24
Endpoint = 1.1.1.1:12000
PersistentKeepalive = 15

[Peer]
PublicKey = public key of node C
AllowedIPs = 10.0.0.80/32,192.168.80.0/24
Endpoint = 3.3.3.3:12000
PersistentKeepalive = 15

Node C (peer 2)

create wireguard private/public key
wg genkey > /etc/wireguard/private
cat /etc/wireguard/private | wg pubkey > /etc/wireguard/public

/etc/wireguard/wg0.conf

watch the interface name , must meets the interface name in system , ens18 is the default value of my test VM

[Interface]
ListenPort = 12000
PrivateKey = private key of node C
Address = 10.0.0.80/24
PostUp   = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o ens18 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o ens18 -j MASQUERADE


[Peer]
PublicKey = public key of node A
AllowedIPs = 10.0.0.40/32,192.168.40.0/24
Endpoint = 1.1.1.1:12000
PersistentKeepalive = 15

[Peer]
PublicKey = public key of node B
AllowedIPs = 10.0.0.28/32,192.168.28.0/24
Endpoint = 2.2.2.2:12000
PersistentKeepalive = 15
Test

Reboot all nodes , check if interface wg0 up by default or not

use command wg show to check status

for example , this is result of wg show in node C

root@sdvpn:~# wg show
interface: wg0
  public key: public key of Node C
  private key: (hidden)
  listening port: 12000

peer: public key of node A
  endpoint: 1.1.1.1:12000
  allowed ips: 10.0.0.40/32, 192.168.40.0/24
  latest handshake: 49 seconds ago
  transfer: 9.77 KiB received, 9.73 KiB sent
  persistent keepalive: every 15 seconds

peer: public key of node B
  endpoint: 2.2.2.2:12000
  allowed ips: 10.0.0.28/32, 192.168.28.0/24
  latest handshake: 2 minutes, 8 seconds ago
  transfer: 3.93 KiB received, 7.89 KiB sent
  persistent keepalive: every 15 seconds

and the ping test

root@sdvpn:~# ping -c 1 192.168.40.40
PING 192.168.40.40 (192.168.40.40) 56(84) bytes of data.
64 bytes from 192.168.40.40: icmp_seq=1 ttl=63 time=21.2 ms

--- 192.168.40.40 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 21.204/21.204/21.204/0.000 ms
root@sdvpn:~# ping -c 1 192.168.28.40
PING 192.168.28.40 (192.168.28.40) 56(84) bytes of data.
64 bytes from 192.168.28.40: icmp_seq=1 ttl=63 time=24.2 ms

--- 192.168.28.40 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 24.208/24.208/24.208/0.000 ms
root@sdvpn:~# 

and the traceroute

root@sdvpn:~# traceroute 192.168.40.40
traceroute to 192.168.40.40 (192.168.40.40), 30 hops max, 60 byte packets
 1  10.0.0.40 (10.0.0.40)  21.349 ms  22.337 ms  22.576 ms
 2  tcpc040.abc.com (192.168.40.40)  22.565 ms  22.551 ms  22.541 ms
root@sdvpn:~# traceroute 192.168.28.40
traceroute to 192.168.28.40 (192.168.28.40), 30 hops max, 60 byte packets
 1  10.0.0.28 (10.0.0.28)  25.481 ms  30.117 ms  32.086 ms
 2  dcpc040.abc.com (192.168.28.40)  33.811 ms  35.360 ms  36.769 ms
root@sdvpn:~#

additonal steps

enable firewall NAT in each nodes router

not necessary , but if the wireguard node is behind a NAT router , then must enable NAT for wireguard

1.1.1.1 is the WAN IP of the router , and 192.168.80.4 is the wireguard LAN ip, I map port 224 to ssh and 12000 for wireguard

iptables -t nat -A PREROUTING -i eth1 -d 1.1.1.1 -p tcp --dport 224 -j DNAT --to-destination 192.168.80.4:22
iptables -t nat -A PREROUTING -i eth1 -d 1.1.1.1 -p udp --dport 12000 -j DNAT --to-destination 192.168.80.4:12000

summary

if want to add more nodes into VPN , just follow the logic and steps.

create private/public key
create wg0.conf 
add new nodes in every other nodes wg0.conf as peer
  1. for route , must add remote network in AllowedIPs
  2. check ip_forward is enable
  3. I think the postup haws no effect here , because the firewall service was disable by default , and if I use iptables -F to flush all firewall rules , the network still remain in connected.
  4. need to create an ansible playbook for this

Update

strongswan IPSEC VS wireguard

wireguard almost twice faster than strongswan

iperf test with wireguard VPN 30 seconds benchmark

root@sdvpn:~# iperf -c 192.168.40.7 -t 30
------------------------------------------------------------
Client connecting to 192.168.40.7, TCP port 5001
TCP window size: 85.0 KByte (default)
------------------------------------------------------------
[  3] local 10.0.0.80 port 48270 connected with 192.168.40.7 port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-30.1 sec  65.1 MBytes  18.1 Mbits/sec
root@sdvpn:~# 

iperf test with strongswan VPN

root@sdvpn:~# iperf -c 192.168.40.7 -t 30
------------------------------------------------------------
Client connecting to 192.168.40.7, TCP port 5001
TCP window size: 85.0 KByte (default)
------------------------------------------------------------
[  3] local 192.168.80.4 port 57806 connected with 192.168.40.7 port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-30.1 sec  35.6 MBytes  9.94 Mbits/sec
root@sdvpn:~#