Selective Routing Using DD-WRT & OpenVPN
This is a quick guide on how I managed to configure OpenVPN on DD-WRT such that only traffic from some LAN clients and some ports is routed over the VPN tunnel.
Recently I signed up for a nice little VPN service Tiger VPN which so far seems quite nice – FYI, they have not asked me to recommend them or paid me in any way to say nice things about them. I just genuinely like the service 🙂
They supply OpenVPN configuration files so that you can easily roll your VPN client of choice if you don’t want to use their own client and they even have a script to automagically install on your DD-WRT enabled router.
The problem is that by default the setup will route all of your network’s outbound connections over the VPN.
I have managed to create a configuration which does the following:
- Routes all traffic from a single LAN IP over the VPN.
- Blocks traffic from the same LAN IP from reaching the internet when the VPN is down
- This is often referred to as a kill switch.
- Routes all traffic destined for a specific port over the VPN
- Prevents requests to the same port when the VPN is down
Under Administration > Commands in the DD-WRT GUI, save the following as a custom script:
#!/bin/sh # Some MASQUERADE line that I don't really understand. iptables -I POSTROUTING -t nat -o tun1 -j MASQUERADE # Set the default route for table 200 as over the VPN ip route add default dev tun1 table 200 # Assign all outgoing connections from 192.168.11 to table 200 (so they go over the VPN) ip rule add from 192.168.1.11 table 200 # Assign all packets marked with 11 to table 200 (so they go over the VPN) ip rule add fwmark 11 table 200 # Flush the cache ip route flush cache # Mark all tcp packets whos destination port is 563 with 11 (so that it will be routed over the VPN) iptables -t mangle -I PREROUTING --dport 563 -j MARK --set-mark 11
Under Administration > Commands, save the following to the firewall script:
# Prevent 192.168.1.11 from reaching the internet directly (so no connection if VPN down) iptables -I FORWARD -s 192.168.1.11 -o vlan2 -j DROP # Prevent 192.168.1.11 from connecting to port 563 directly (so no connection if VPN down) iptables -I FORWARD -s 192.168.1.11 --dport 563 -o vlan2 -j DROP
The next step is a little bit trickier. Basically you have to use the DD-WRT GUI to configure as many of the OpenVPN settings as you can (based on what your provider specifies) and then do the rest in the ‘additional config’ box.
Use the DD-WRT OpenVPN documentation to help you identify which GUI settings correspond to which OpenVPN properties. Each time you click ‘Apply Settings’ you can check the raw generated config vis ssh by looking at /tmp/openvpncl/openvpn.conf
My settings for TigerVPN look like this (username and password removed obviously):
Under additional config for OpenVPN client I have the following:
# Write to a log file for easy viewing log /tmp/tigervpn.log # Mute messages that repeat a bunch of times mute 50 # Do not accept the routes provided by the VPN server # (will manage those myself) route-nopull # Keep the connection alive and attempt to reestablish it if it dies keepalive 10 60 # Additional settings specified by VPN provider tls-client remote-cert-tls server # Dont use auth-nocache as it prevents reconnection due to a bug # auth-nocache # Script to run when the link is established # This sets up my custom routes and iptables rules up /tmp/custom.sh
The really important setting there was the route-nopull. What this does is prevent the OpenVPN client from automatically installing routes provided by the VPN server. We do this because we want to use the routes set up in our scripts.
The final generated OpenVPN config (viewable under ‘/tmp/openvpncl/openvpn.conf’ on the router) looks like this:
ca /tmp/openvpncl/ca.crt management 127.0.0.1 16 management-log-cache 100 verb 3 mute 3 syslog writepid /var/run/openvpncl.pid client resolv-retry infinite nobind persist-key persist-tun script-security 2 dev tun1 proto udp cipher aes-256-cbc auth sha1 auth-user-pass /tmp/openvpncl/credentials remote zur.tigervpn.com 1194 comp-lzo adaptive tun-mtu 1500 mtu-disc yes fast-io tun-ipv6 # Write to a log file for easy viewing log /tmp/tigervpn.log # Mute messages that repeat a bunch of times mute 50 # Do not accept the routes provided by the VPN server # (will manage those myself) route-nopull # Keep the connection alive and attempt to reestablish it if it dies keepalive 10 60 # Additional settings specified by VPN provider tls-client remote-cert-tls server # Script to run when the link is established # This sets up my custom routes and iptables rules up /tmp/custom.sh