Selective (split) VPN routing for dd-wrt: Whitelisting servers and clients

All the traffic from my house goes through a VPN, using a dd-wrt flashed router at the client. However, I ran into two issues:

  1. Server Whitelisting: Certain hosts appear to blacklist VPN exit nodes. (e.g., Craigslist) I need to permit clients to connect to these using the ISP gateway, instead of the VPN.
  2. Client Whitelisting: I don’t need traffic from my Roku to go through the VPN. Likewise, my work laptop has a VPN provided by my employer, so it doesn’t need to go through my personal VPN as well.

Attempt 1

The dd-wrt firmware allows one to specify which clients (IP ranges) should use the VPN, using Policy Based Routing in the OpenVPN client setup. So I added an IP range to that window corresponding to the DHCP range used by the router, and assigned my Roku and work laptops static IPs outside that range.

Then I added the servers I wanted to whitelist to routes in the “Advanced Config” options in the OpenVPN tab of the dd-wrt firmware, like this:

route 208.82.237.0 255.255.255.0 net_gateway

However, this didn’t work. No new routes were added to the routing table, and there were no errors in the log.

I concluded that if there are entries in the Policy Based Routing box, they override any route commands in the “Advanced Config” or .ovpn file. (In other words, my client whitelist was preventing the server whitelist from being implemented.)

Attempt 2

On the assumption that Policy-Based Routing negates route rules in the dd-wrt OpenVPN client set up, I tried a different approach.

Instead of using Policy-Based routing to include certain IPs, I used source based routing to send certain traffic through the ISP gateway. You might need to adjust the ISP_GATEWAY line to suit your configuration. The netmasks below will cover from 192.168.1.50–192.168.1.99. My DHCP range starts at 192.168.1.100, so unless otherwise specified clients will use the VPN.  (IPConverterTools was very helpful for working out the netmasks.)

Save this shell script in non-volatile ram (for example, /jffs/openvpn-route-up.sh) and make it executable.

#!/bin/bash
ISP_GATEWAY=$(ip route show default | awk '/default/ {print $3}')
ip rule add from 192.168.1.50/255.255.255.254 table 200
ip rule add from 192.168.1.52/255.255.255.252 table 200
ip rule add from 192.168.1.56/255.255.255.248 table 200
ip rule add from 192.168.1.64/255.255.255.224 table 200
ip rule add from 192.168.1.96/255.255.255.252 table 200
ip route add default via ${ISP_GATEWAY} dev eth0 table 200
ip route flush cache

This script needs to be run after the VPN comes up. OpenVPN lets us script this easily. To your OVPN config, add:

route-up /jffs/openvpn-route-up.sh

Cleanup: update with newer version of this script that clears the table of existing entries if they exist.

This configuration has two advantages:

  1. If you want to have a host bypass the VPN, assign it a static IP in the range 192.168.1.50–192.168.1.99. I did this for my Roku Streaming Stick and work laptop.
  2. If the Policy-Based Routing box of the dd-wrt firmware can be emptied, the route options in the OpenVPN configuration will take effect. Now you can add sites to whitelist, such as Craigslist.

route 208.82.237.0 255.255.255.0 net_gateway