OpenVPN has two authentication modes, one based on SSL/TLS security using RSA certificates and keys, the other using a pre-shared static key 1).
A certain country's firewall tends to interrupt vanilla OpenVPN's connection if it is operated in TLS mode. I am not entirely sure how this is done, there are a lot of speculations on how it is done 2). In short, rumour says the firewall is powerful enough to detect OpenVPN's key exchange signature through DPI. There are also a lot of fixes 3)4), however they require applying patches and compilation, they are not exactly simple.
The Chinese firewall doesn't seem to interrupt OpenVPN when it is operated in static-key mode. However the basic static key configuration tutorial only tells you how to do a point-to-point link 5).
In this article, we explore how to create an OpenVPN network bridge to link all your VPN clients together, using static key authentication.
On the server, one OpenVPN instance is run for each client connecting to the server. The OpenVPN instances on the server are linked together using a network bridge created via bridge-utils 6). (In contrast, only one OpenVPN instance is required on the server in the official tutorial 7)).
In our setup, TAP devices are required, as we are forwarding Ethernet frames between them. TAP devices operate at the link layer, while TUN devices operate at the network layer 8).
Compared to the official tutorial, we also set IP address for each client in the client configuration. The server does not assign IP address for each client.
We are effectively configuring OpenVPN to send traffic to a broadcast address. However in my experience, the kernel's network bridge driver seems to take care of everything automatically. I am not sure if there is performance penalty with this configuration, however I find the performance acceptable. The data transfer rate seems to be limited only by the bandwidth between your client and the server.
We create /etc/network/interfaces.d/br0
with the following content:
auto br0 iface br0 inet static address 192.168.4.1 netmask 255.255.255.0 pre-up /sbin/brctl addbr br0 post-down /sbin/brctl delbr br0
For each client instance, we need to create a corresponding server instance. The following content can be used as a template:
dev tap1 proto udp port 12345 secret home.key ifconfig 192.168.4.1 255.255.255.0 user nobody group nogroup persist-key persist-tun comp-lzo comp-noadapt keepalive 2 10 ping-timer-rem cipher AES-256-CBC up "/etc/openvpn/tap-pre-up.sh tap1" down "/etc/openvpn/tap-post-down.sh tap1" script-security 2 mtu-test
Note that you need to specifically name the tap device - you can't just use tap
, you have to use tap0
, tap1
and etc. You also need to set a new port for each instance - each OpenVPN instance needs an exclusive port.
The up-script adds the TAP interface into the network bridge. We create /etc/openvpn
with the following content:
#!/bin/bash brctl addif br0 $1
The down-script destroys the TAP interface after OpenVPN shuts down. This enables OpenVPN to restart correctly. OpenVPN does not destroy the TAP device automatically, as it is still on the network bridge. We create /etc/openvpn/tap-post-down.sh
with the following content:
#!/bin/bash tunctl -d $1
We can have the following in the client configuration:
remote your.hostname.com 12345 nobind dev tap proto udp secret secret.key ifconfig 192.168.4.120 255.255.255.0 user nobody group nogroup persist-key persist-tun comp-lzo comp-noadapt verb 4 cipher AES-256-CBC mtu-test