If you run VPN on your router, you may have had cases where you want Internet traffic to bypass the VPN. Most solutions I’ve found use some form of a script originally found on LinksysInfo. However these approaches are IP based, which can be a problem if those IPs change, or if the service you’re accessing uses a CDN. If your router is running firmware that supports ipset, you can use dnsmasq and iptables to solve this problem.
This example uses release 112 of Tomato by Shibby. Some versions of utilities are not the latest available, so syntax may be slightly different than readily available man pages. The code snippets below include a commented reference to where they go in the admin GUI, but this is just what worked for me.
The core of the solution is to create an ipset for hosts of interest, configure Dnsmasq to populate that ipset and then use iptables rules to route outgoing traffic to those IPs over the WAN instead of over the VPN.
# Administration > Scripts > Init ipset --create bypass_vpn iphash modprobe ipt_set
The first thing you need to do is create an ipset and load the
module. Here we’ve created an ipset named
bypass_vpn of type
that newer versions of ipset use a different syntax,
hash:ip, for the set
type. If you later get errors from iptables when trying to create rules with the
ipset, you probably forgot to load the kernel module.
# Advanced > DHCP/DNS > Dnsmasq Custom configuration server=/example.com/192.168.1.1 ipset=/example.com/bypass_vpn #log-queries
Next you need to tell Dnsmasq to route DNS requests to a DNS server that is
going to give you location appropriate results. This is particularly important
if you’re trying to get traffic to use a local CDN. In the above example,
example.com is our host of interest,
192.168.1.1 is the IP of a DNS server
that will resolve that host to a desirable IP and
bypass_vpn is the ipset to
store the results in for later use by iptables. You will need a server/ipset
pair for every hostname you wish to bypass the VPN.
When you’re first setting things up, you’ll probably want to also add
log-queries to the Dnsmasq config, which will log DNS requests to the system
log at /var/log/messages. In addition to hostnames you’re already aware of, be
on the lookout for hosts referred to by
# Administration > Scripts > WAN Up # The commands needed to create the routing table for packets marked with a # 1 are not shown here. See the aforementioned LinksysInfo thread for more # information. # MARK = 0; all traffic goes through VPN by default iptables -t mangle -A PREROUTING -i br0 -j MARK --set-mark 0 # MARK = 1; bypass VPN for bypass_vpn ipset iptables -t mangle -A PREROUTING -i br0 -m set --set bypass_vpn dst -j MARK --set-mark 1
Finally you need to create rules to mark packets matching the ipset. In the
br0 is the interface the packets are entering through,
bypass_vpn is the ipset containing the IPs to match and
1 is the mark value
corresponding to a routing table that bypasses the VPN. This is not a complete
iptables configuration. Only the packet marking rules are shown. Note that the
--match-set option mentioned in the iptables man page did not work for me.