OpenVPN Network Bridge with Static Key Authentication

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.

Overview

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.

Server-side configuration

Creating the network bridge

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

OpenVPN instance configuration

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.

Up-script

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

Down-script

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

Client-side configuration

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