What's new

Selective Routing with Asuswrt-Merlin

  • SNBForums Code of Conduct

    SNBForums is a community for everyone, no matter what their level of experience.

    Please be tolerant and patient of others, especially newcomers. We are all here to share and learn!

    The rules are simple: Be patient, be nice, be helpful or be gone!

I really like the work you do! Thanks! :)
When can we expect the next realease with selectiv vpn routing? :D

I currently don't have any target release date, so it will be once I'm satisfied with the state of 378.53's code.
 
I currently don't have any target release date, so it will be once I'm satisfied with the state of 378.53's code.
Thank you so much Dev. Now that it's released into the wild, will some one please give a newbs example/explanation how to use the added feature? Please and thanks in advanced.
 
Thank you so much Dev. Now that it's released into the wild, will some one please give a newbs example/explanation how to use the added feature? Please and thanks in advanced.

I wrote the documentation for it in the included README.
 
Hi All

First off, this thread is a terrific source of information for selective routing. Thank you to everyone that has taken the time to contribute their knowledge and experience.

Based on many of the posts in this thread, I have almost gotten my routing setup working.

My ideal situation is to have two active OpenVPN client configurations: client 1 (tun11) is configured to use a US VPN; client 2 (tun12) is configured to use a UK VPN. I want to route traffic to either the WAN, tun11 or tun12 based on the IP addresses of machines on my LAN.

Based on this thread - and some broader reading - my current openvpn-event script is as follows:

Code:
#!/bin/sh

# This code based on the contributions from these threads:
# http://www.linksysinfo.org/index.php?threads/route-only-specific-ports-through-vpn-openvpn.37240/
# http://www.snbforums.com/threads/selective-routing-with-asuswrt-merlin.9311/
# And from material in these articles:
# http://linux-ip.net/html/adv-multi-internet.html
# http://fedorasolved.org/Members/kanarip/iptables-howto
#
# This script configures selective VPN routing for Asuswrt-Merlin firmware and two OpenVPN
# client connections. These changes to iptables allow some outbound traffic to use OpenVPN
# client 1, some traffic to use OpenVPN client 2, and some traffic to bypass the VPN
# client connections and use the regular internet.


# The following two commands are listed for reference.
# To list the current rules on the router, issue the command:
#      iptables -t mangle -L PREROUTING
#
#  Flush/reset all the rules to default by issuing the command:
#      iptables -t mangle -F PREROUTING


# First it is necessary to disable Reverse Path Filtering on all
# current and future network interfaces:

for i in /proc/sys/net/ipv4/conf/*/rp_filter ; do
  echo 0 > $i
done


# Delete and table 10, 20 and 30 and flush any existing rules if they exist.
# Table 10 will be used for the WAN/internet.
# Table 20 will be used for OpenVPN client 1, and table 30 for OpenVPN client 2.

ip route flush table 10
ip route del default table 10
ip rule del fwmark 10 table 10
ip route flush table 20
ip route del default table 20
ip rule del fwmark 20 table 20
ip route flush table 30
ip route del default table 30
ip rule del fwmark 30 table 30
ip route flush cache
iptables -t mangle -F PREROUTING


# Define "tun11" (OpenVPN client 1) and "tun12" (OpenVPN client 2).
# Associate table 10 with the WAN/internet, table 20 with "tun11" (OpenVPN client 1)
# and table 30 with "tun12" (OpenVPN client 2).

tun_if="tun11"
tun_ifs="tun12"
tun_ip=$(ifconfig $tun_if | grep 'inet addr:'| cut -d: -f2 | awk '{ print $1}')
tun_ips=$(ifconfig $tun_ifs | grep 'inet addr:'| cut -d: -f2 | awk '{ print $1}')

ip route add default via $(nvram get wan_gateway) dev eth0 table 10
ip rule add fwmark 10 table 10
ip route add default via $tun_ip dev $tun_if table 20
ip rule add fwmark 20 table 20
ip route add default via $tun_ips dev $tun_ifs table 30
ip rule add fwmark 30 table 30


# Define the routing policies for the traffic. The rules will be applied in the order that
# they are listed. Packets with MARK set to "10" will pass through the WAN/internet. If
# MARK is set to "20" it will pass through OpenVPN client 1. If MARK is set to "30" it
# will pass through OpenVPN client 2.
#
# EXAMPLES:
#
#  All LAN traffic will bypass the VPN (Useful to put this rule first, so all traffic bypasses the VPN and you can configure exceptions afterwards)
#    iptables -t mangle -A PREROUTING -i br0 -j MARK --set-mark 10
#  Ports 80 and 443 will bypass the VPN
#    iptables -t mangle -A PREROUTING -i br0 -p tcp -m multiport --dport 80,443 -j MARK --set-mark 10
#  All traffic from a particular computer on the LAN will use the OpenVPN client 1
#    iptables -t mangle -A PREROUTING -i br0 -m iprange --src-range 192.168.1.2 -j MARK --set-mark 20
#  All traffic to a specific Internet IP address will use the OpenVPN client 2
#    iptables -t mangle -A PREROUTING -i br0 -m iprange --dst-range 216.146.38.70 -j MARK --set-mark 30
#  All UDP and ICMP traffic will bypass the VPN
#    iptables -t mangle -A PREROUTING -i br0 -p udp -j MARK --set-mark 10
#    iptables -t mangle -A PREROUTING -i br0 -p icmp -j MARK --set-mark 10


# By default all traffic goes through the WAN/internet
iptables -t mangle -A PREROUTING -i br0 -j MARK --set-mark 10

# Set specific IP range traffic to go through OpenVPN client 1 (tun11)
iptables -t mangle -A PREROUTING -i br0 -m iprange --src-range 192.168.1.20-192.168.1.40 -j MARK --set-mark 20

#Set specific IP range traffic to go through OpenVPN client 2 (tun12)
iptables -t mangle -A PREROUTING -i br0 -m iprange --src-range 192.168.1.120-192.168.1.140 -j MARK --set-mark 30

exit

The routing appears to be working. If a machine on the LAN has an IP that is outside the 192.168.1.20-192.168.1.40 and 192.168.1.120-192.168.1.140 ranges, the traffic routes over the WAN. If the machine has an IP within the 192.168.1.20-192.168.1.40 range, then it routes through tun11 (the US VPN). Similarly, if the machine has an IP within the 192.168.1.120-192.168.1.140 range, then it routes through tun12 (the UK VPN).

So far, so good.

But there is one remaining issue: DNS leaks. At the moment - regardless of whether traffic routes through the WAN, tun11 or tun 12 - all connections end up utilising the DNS server(s) specified in the 'WAN' --> 'WAN DNS Setting' section of the router's settings. This is not ideal. When traffic routes through the WAN, I want queries to resolve using my ISP's DNS. When traffic is routed through tun11 or tun12, however, I want queries to resolve using the respective DNS server(s) for that VPN (and not my ISP's DNS).

Is there a simple way to achieve this outcome? Any help would be most appreciated!
 
This works great, but there seems to be a bug when you connect via the OpenVPN server and have an OpenVPN client running at the same time that you cannot access any LAN computers, despite push LAN to clients being turned on.
 
Code below was working flawlessly and has now defaulted to the VPN for all connections.

Just upgraded to 378.53 on an AC68U

openvpn-event

Code:
#!/bin/sh

touch /tmp/000openvpn-event,ran

# This script configures "selective" VPN routing. Normally Tomato will route ALL traffic out
# the OpenVPN tunnel. These changes to iptables allow some outbound traffic to use the VPN, and some
# traffic to bypass the VPN and use the regular Internet instead.
#
#  To list the current rules on the router, issue the command:
#      iptables -t mangle -L PREROUTING
#
#  Flush/reset all the rules to default by issuing the command:
#      iptables -t mangle -F PREROUTING

# First it is necessary to disable Reverse Path Filtering on all
# current and future network interfaces:

for i in /proc/sys/net/ipv4/conf/*/rp_filter ; do
      echo 0 > $i
done

# Delete and table 100 and flush any existing rules if they exist.

ip route flush table 100
ip route del default table 100
ip rule del fwmark 1 table 100
ip route flush cache
iptables -t mangle -F PREROUTING

# Copy all non-default and non-VPN related routes from the main table into table 100.
# Then configure table 100 to route all traffic out the WAN gateway and assign it mark "1"
#
# NOTE: Here I assume the OpenVPN tunnel is named "tun11".

ip route show table main | grep -Ev ^default | grep -Ev tun11 \
  | while read ROUTE ; do
      ip route add table 100 $ROUTE
done
ip route add default table 100 via $(nvram get wan_gateway)
ip rule add fwmark 1 table 100
ip route flush cache


# Define the routing policies for the traffic. The rules will be applied in the order that they
# are listed. In the end, packets with MARK set to "0" will pass through the VPN. If MARK is set
# to "1" it will bypass the VPN.
#
# EXAMPLES:
#
#  All LAN traffic will bypass the VPN (Useful to put this rule first, so all traffic bypasses the VPN and you can configure exceptions afterwards)
#    iptables -t mangle -A PREROUTING -i br0 -j MARK --set-mark 1
#  Ports 80 and 443 will bypass the VPN
#    iptables -t mangle -A PREROUTING -i br0 -p tcp -m multiport --dport 80,443 -j MARK --set-mark 1
#  All traffic from a particular computer on the LAN will use the VPN
#    iptables -t mangle -A PREROUTING -i br0 -m iprange --src-range 192.168.1.2 -j MARK --set-mark 0
#  All traffic to a specific Internet IP address will use the VPN
#    iptables -t mangle -A PREROUTING -i br0 -m iprange --dst-range 216.146.38.70 -j MARK --set-mark 0
#  All UDP and ICMP traffic will bypass the VPN
#    iptables -t mangle -A PREROUTING -i br0 -p udp -j MARK --set-mark 1
#    iptables -t mangle -A PREROUTING -i br0 -p icmp -j MARK --set-mark 1

# By default all traffic bypasses the VPN
iptables -t mangle -A PREROUTING -i br0 -j MARK --set-mark 1

# Netflix On WDLiveTV explicitly uses the VPN
iptables -t mangle -A PREROUTING -i br0 -m iprange --src-range 192.168.1.21 -j MARK --set-mark 0

 #Ma & Pa PS3 explicitly uses the VPN
iptables -t mangle -A PREROUTING -i br0 -m iprange --src-range 192.168.1.185 -j MARK --set-mark 0
 
Just upgraded to 378.53 myself (thank you RMerlin for the selective routing UI). I need to add an destination IP exception that bypasses the VPN for one device I have listed in the policy rules section. Currently, this device has a destination IP assignment of 0.0.0.0. Is there a way using the policy rules section to assign around this IP so that for this device all internet traffic, expect for one destination IP, is routed through the VPN? If so, what would an example look like?
 
Just upgraded to 378.53 myself (thank you RMerlin for the selective routing UI). I need to add an destination IP exception that bypasses the VPN for one device I have listed in the policy rules section. Currently, this device has a destination IP assignment of 0.0.0.0. Is there a way using the policy rules section to assign around this IP so that for this device all internet traffic, expect for one destination IP, is routed through the VPN? If so, what would an example look like?

If you SSH/TELNET to the router and issue

Code:
ip   rule   add   from   192.168.1.xxx   to   xxx.xxx.xxx.xxx   table   254
ip   route   flush   cache

If this works, then you should be able to add this to script openvpn-event
 
Last edited:
Hi,

So by default it will route everything thru the tunnel?

Is it possible to route based on port range?

No, by default nothing gets routed through the tunnel, unless you disable Policy Routing.

Port specification is not technically possible.
 
Port specification is not technically possible.

Would something like this work if you issue the command over ssh?

Code:
iptables -t mangle -A PREROUTING -i br0 -p tcp -m multiport --dport 80,443 -j MARK --set-mark X
where X is the mark of the packages going thru the tunnel?
 
Would something like this work if you issue the command over ssh?

Code:
iptables -t mangle -A PREROUTING -i br0 -p tcp -m multiport --dport 80,443 -j MARK --set-mark X
where X is the mark of the packages going thru the tunnel?

My implementation does not use packet marking. Marking in the PREROUTING chain isn't reliable, because the DPI engine can flush the content of that chain when it gets restarted. Because of this, my RPDB implementation is strictly IP-based.
 
Would something like this work if you issue the command over ssh?

Code:
iptables -t mangle -A PREROUTING -i br0 -p tcp -m multiport --dport 80,443 -j MARK --set-mark X
where X is the mark of the packages going thru the tunnel?

I believe it is technically possible although you will need to manually add the appropriate routing policy rule(s) in openvpn-event:

Code:
ip rule add fwmark X table nnn
ip route flush cache

where nnn = 111 for VPN Client1 traffic and nnn = 112 is for VPN Client2.
(Pity RMerlin wasn't able to add the ability - as allowed under a Debian install - to add the RPDB feature to name the tables using the parameter file 'etc/iproute2/rt_tables').

NOTE: Can't recall if the tag mark is specified in decimal in the iptables statement and hex in the ip statement, but you should be safe if you use single digit tag marks! :eek:

To ensure the iptables tagging rules are not erased when the DPI engine flushes them (e.g. 02:00 every couple of days?) then simply use nat-start to tag your ports

i.e. put all your tagging rules in a separate /jffs script which can be called from either nat-start and /or openvpn-event etc. (ensuring that you don't create unnecessary duplicates).

P.S. You can also add logic in nat-start to only tag the traffic (i.e. call/run the tagging script) if the VPN Client is UP.
 
Last edited:
I hope this isn't too off-topic...

I'm using UnoTelly for DNS for a variety of reasons, but I have a few devices, like Chromecast, that have hard-coded DNS servers. On the UnoTelly site, they have some IPTables commands to reroute all traffic (from any device on the network) to known DNSs (e.g. 8.8.8.8 and 8.8.4.4) for use with DD-WRT. I created a nat-start file in the jffs/scripts directory and I was wondering if there was a good way to test to see if the commands are working. Ideally, if I set everything up correctly, it should appear seamless, thus it's hard to tell if the script is rerouting traffic properly or not. Is there some sort of terminal command I can do to test the script? Here is the script:

Code:
#!/bin/sh

iptables -I PREROUTING -t nat -p udp -d 8.8.4.4 --dport 53 -j DNAT --to-destination 23.21.182.24
iptables -I PREROUTING -t nat -p udp -d 8.8.8.8 --dport 53 -j DNAT --to-destination 23.21.182.24
 
(Pity RMerlin wasn't able to add the ability - as allowed under a Debian install - to add the RPDB feature to name the tables using the parameter file 'etc/iproute2/rt_tables').

Did you try it? Maybe it would work, I don't know if anything special is required at compile time, or if it's part of iproute2 out of the box. Try creating your tables in /etc/iproute2/rt_tables and see what happens then.
 
I hope this isn't too off-topic...

I'm using UnoTelly for DNS for a variety of reasons, but I have a few devices, like Chromecast, that have hard-coded DNS servers. On the UnoTelly site, they have some IPTables commands to reroute all traffic (from any device on the network) to known DNSs (e.g. 8.8.8.8 and 8.8.4.4) for use with DD-WRT. I created a nat-start file in the jffs/scripts directory and I was wondering if there was a good way to test to see if the commands are working. Ideally, if I set everything up correctly, it should appear seamless, thus it's hard to tell if the script is rerouting traffic properly or not. Is there some sort of terminal command I can do to test the script? Here is the script:

Code:
#!/bin/sh

iptables -I PREROUTING -t nat -p udp -d 8.8.4.4 --dport 53 -j DNAT --to-destination 23.21.182.24
iptables -I PREROUTING -t nat -p udp -d 8.8.8.8 --dport 53 -j DNAT --to-destination 23.21.182.24

Use DNSFilter.
 
Did you try it? Maybe it would work, I don't know if anything special is required at compile time, or if it's part of iproute2 out of the box. Try creating your tables in /etc/iproute2/rt_tables and see what happens then.

:oops: I guess when I originally tried I must have had a typo; clearly it does indeed work :rolleyes:

So much easier to have self documenting RPDB rules

e.g. human friendly entries such as VPN_HMA_NewYork etc.!! rather than a number!
 
:oops: I guess when I originally tried I must have had a typo; clearly it does indeed work :rolleyes:

Cool, that must be built into the iproute2 package then.
 

Latest threads

Sign Up For SNBForums Daily Digest

Get an update of what's new every day delivered to your mailbox. Sign up here!
Top