OpenVPN SplitTunneling on OpenWRT


Split-tunneling is a networking technique that lets you route traffic to different network gateways depending on where it is coming from (or better on its source IP address).

Scenario

We own an OpenWRT router and we want to configure multiple SSIDs, when a user connects to a certain SSID we aim to route their traffic to a paid VPN service (like NordVPN or ExpressVPN), while another SSID provides a direct route to the WAN gateway. (or a different VPN service)

To do so we need to make use of split-tunneling (not so easy) and know how to setup an OpenVPN client on our router. (easy)

Note: This post is based on OpenWRT 18.06. Apart from minor differences this should work on other versions as well.

OpenVPN client setup

First, we need to install OpenVPN on our router:

opkg update && opkg install openvpn-openssl ip-full

We can now copy our .ovpn file to /etc/openvpn on our router along with CA certificates and the TA key. (if needed)

If your .ovpn contains the “auth-user-pass” option, make sure to change it to “auth-user-pass /etc/openvpn/auth.txt” and create auth.txt:

cat /etc/openvpn/auth.txt
USERNAME
PASSWORD
Make sure you use absolute paths only in your .ovpn config file or it won’t work. You can rename your .ovpn file to .conf, but it doesn’t really matter.

Try running:

/usr/sbin/openvpn /etc/openvpn/paidvpn.conf

If you see “Initialization Sequence Completed” everything went well. You can now stop openvpn with CTRL+C.

All that’s left to do is to add openvpn to the “Startup” entries. In “System” -> “Startup” scroll down to the “Local Startup” section and add (above exit 0) /usr/sbin/openvpn /etc/openvpn/client.conf &

Interface and firewall configuration

First, we need to setup a new network interface for the VPN tunnel.

Go to Network -> Interfaces -> Add new interface … and fill-in as shown below:

Creating VPN interface
Make sure you enter the right VPN tunnel interface (tunX). You can specify a fixed tunnel interface name in your .ovpn config file: dev tun0 instead of dev tun.

Now in “Advanced settings” tick “Bring up on boot” and in “Firewall settings” create a new firewall zone, name it “vpn”.

Since we want two different networks with separate gateways we create another LAN bridge, br-lan2, which we will assign to our new WiFi network.

Go to Network -> Interfaces -> Add new interface …, choose “Static Address” and enter “lan2” where it says “Name of the new interface”. Click on “Submit” and then fill in “IPv4 Address” with an IP address in a different subnet than the one of the default lan bridge. (e.g. 192.168.4.1) and select “255.255.255.0” as the IPv4 netmask.

Note: if you wish to do so, you may use a 192.168.1.X IP address and change the netmask in order to separate the two networks. (This is important in order to route the traffic correctly)

Now in “Physical settings” tick “Bridge interfaces” and in “Firewall settings” create a new firewall zone, name it “lan2”.

Go to the “DHCP Server” section and turn it on.

Newly created interfaces

All the needed interfaces are now setup correctly. Go to “Network” -> “Firewall” and copy the following settings:

SSID Setup

Now go to “Network” -> “Wireless”, Add a new SSID and attach it to “lan2

Split Tunneling

To route some of our network traffic to another gateway we need to create a new routing table and configure a block of IP addresses to use that routing table instead of the default table.

Go to /etc/iproute2/rt_tables and append “200 vpn” at the end. You are creating a custom routing table called “vpn”, 200 is the integer mapping associated to our custom table used by the Linux kernel.

We also need to create a new file, /etc/openvpn/route-up.sh, which specifies how to perform the routing correctly.

#!/bin/sh
echo "$dev : $ifconfig_local -> $ifconfig_remote gw: $route_vpn_gateway"
# Remove default routes pushed by VPN server (we don't want to route # all network traffic through the VPN gateway)
/sbin/ip route del 128.0.0.0/1 via ${route_vpn_gateway}
/sbin/ip route del 0.0.0.0/1 via ${route_vpn_gateway}
# Search route for traffic coming from 192.168.0.4/24 in table 'vpn' # (unicast: This rule type simple causes the kernel to refer to the # specified routing table in the search for a route.)
/sbin/ip rule add from 192.168.4.0/24 table vpn
# Search route for traffic going to 192.168.0.4/24 in table 'vpn'
/sbin/ip rule add to 192.168.4.0/24 table vpn
# Use 'vpn' table as default for tun0
/sbin/ip route add table vpn default dev ${dev}
# Route traffic from/to 192.168.4.0/24 on br-lan2 using the 'vpn'.  # table. (192.168.4.1 is the source address for outgoing packets)
/sbin/ip route add 192.168.4.0/24 dev br-LAN2 src 192.168.4.1 table vpn

Now simply make this file executable:

chmod +x /etc/openvpn/route-up.sh

You now need to tell openvpn that it needs to execute route-up.sh when the tunnel is initialised; to do so simply add a few lines to the .ovpn/.config file:

route-up /etc/openvpn/route-up.sh
script-security 2

Done, reboot your OpenWRT router now.

— Amedeo